[mapserver-commits] r11599 - trunk/mapserver

svn at osgeo.org svn at osgeo.org
Tue Apr 19 01:14:17 EDT 2011


Author: tbonfort
Date: 2011-04-18 22:14:17 -0700 (Mon, 18 Apr 2011)
New Revision: 11599

Modified:
   trunk/mapserver/HISTORY.TXT
   trunk/mapserver/mapimageio.c
   trunk/mapserver/mapquantization.c
   trunk/mapserver/mapserver.h
   trunk/mapserver/mapsymbol.h
Log:
fix incorrect quantization for images with very large number of
colors (#3848)

Modified: trunk/mapserver/HISTORY.TXT
===================================================================
--- trunk/mapserver/HISTORY.TXT	2011-04-19 05:09:19 UTC (rev 11598)
+++ trunk/mapserver/HISTORY.TXT	2011-04-19 05:14:17 UTC (rev 11599)
@@ -15,6 +15,9 @@
 Current Version (SVN trunk): 
 ---------------------------- 
 
+- fix incorrect quantization for images with very large number of
+  colors (#3848)
+
 - fix poor performance of polygon hatching (#3846)
 
 - upgrade clipper library to 4.2 (related to #3846)

Modified: trunk/mapserver/mapimageio.c
===================================================================
--- trunk/mapserver/mapimageio.c	2011-04-19 05:09:19 UTC (rev 11598)
+++ trunk/mapserver/mapimageio.c	2011-04-19 05:14:17 UTC (rev 11599)
@@ -194,18 +194,20 @@
 int remapPaletteForPNG(rasterBufferObj *rb, rgbPixel *rgb, unsigned char *a, int *num_a) {
    int bot_idx, top_idx, x;
    int remap[256];
+   unsigned int maxval = rb->data.palette.scaling_maxval; 
+  
+   assert(rb->type == MS_BUFFER_BYTE_PALETTE);
+   
    /*
-   ** Step 3.5 [GRR]: remap the palette colors so that all entries with
+   ** remap the palette colors so that all entries with
    ** the maximal alpha value (i.e., fully opaque) are at the end and can
    ** therefore be omitted from the tRNS chunk.  Note that the ordering of
-   ** opaque entries is reversed from how Step 3 arranged them--not that
-   ** this should matter to anyone.
+   ** opaque entries is reversed from how they were previously arranged
+   ** --not that this should matter to anyone.
    */
    
-   assert(rb->type == MS_BUFFER_BYTE_PALETTE);
-   
    for (top_idx = rb->data.palette.num_entries-1, bot_idx = x = 0;  x < rb->data.palette.num_entries;  ++x) {
-     if (rb->data.palette.palette[x].a == 255)
+     if (rb->data.palette.palette[x].a == maxval)
          remap[x] = top_idx--;
      else
          remap[x] = bot_idx++;
@@ -219,20 +221,29 @@
    *num_a = bot_idx;
    
    for(x=0;x<rb->width*rb->height;x++)
-         rb->data.palette.pixels[x] = remap[rb->data.palette.pixels[x]];
+      rb->data.palette.pixels[x] = remap[rb->data.palette.pixels[x]];
    
+
    for (x = 0; x < rb->data.palette.num_entries; ++x) {
-      a[remap[x]] = rb->data.palette.palette[x].a;
-      if(a[remap[x]] == 255) {
+      if(maxval == 255) {
+         a[remap[x]] = rb->data.palette.palette[x].a;
          rgb[remap[x]].r = rb->data.palette.palette[x].r;
          rgb[remap[x]].g = rb->data.palette.palette[x].g;
          rgb[remap[x]].b = rb->data.palette.palette[x].b;
       } else {
-         double da = a[remap[x]]/255.0;
-         rgb[remap[x]].r = rb->data.palette.palette[x].r / da;
-         rgb[remap[x]].g = rb->data.palette.palette[x].g / da;
-         rgb[remap[x]].b = rb->data.palette.palette[x].b / da;
+         /* rescale palette */
+         rgb[remap[x]].r = (rb->data.palette.palette[x].r * 255 + (maxval >> 1)) / maxval;
+         rgb[remap[x]].g = (rb->data.palette.palette[x].g * 255 + (maxval >> 1)) / maxval;
+         rgb[remap[x]].b = (rb->data.palette.palette[x].b * 255 + (maxval >> 1)) / maxval;
+         a[remap[x]] = (rb->data.palette.palette[x].a * 255 + (maxval >> 1)) / maxval;
       }
+      if(a[remap[x]] != 255) {
+         /* un-premultiply pixels */
+         double da = 255.0/a[remap[x]];
+         rgb[remap[x]].r *=  da;
+         rgb[remap[x]].g *=  da;
+         rgb[remap[x]].b *=  da;
+      }
    }
    
    return MS_SUCCESS;
@@ -287,7 +298,7 @@
                PNG_FILTER_TYPE_DEFAULT);
    
    remapPaletteForPNG(rb,rgb,a,&num_a);
-   
+
    png_set_PLTE(png_ptr, info_ptr, (png_colorp)(rgb),rb->data.palette.num_entries);
    if(num_a)
       png_set_tRNS(png_ptr, info_ptr, a,num_a, NULL);
@@ -387,10 +398,13 @@
         qrb.width = rb->width;
         qrb.height = rb->height;
         qrb.data.palette.pixels = (unsigned char*)malloc(qrb.width*qrb.height*sizeof(unsigned char));
+        qrb.data.palette.scaling_maxval = 255;
         if(force_pc256) {
             qrb.data.palette.palette = palette;
             qrb.data.palette.num_entries = atoi(msGetOutputFormatOption( format, "QUANTIZE_COLORS", "256"));
-            ret = msQuantizeRasterBuffer(rb,&(qrb.data.palette.num_entries),qrb.data.palette.palette, NULL, 0);
+            ret = msQuantizeRasterBuffer(rb,&(qrb.data.palette.num_entries),qrb.data.palette.palette,
+                  NULL, 0,
+                  &qrb.data.palette.scaling_maxval);
         } else {
             int colorsWanted = atoi(msGetOutputFormatOption( format, "QUANTIZE_COLORS", "0"));
             const char *palettePath = msGetOutputFormatOption( format, "PALETTE", "palette.txt");
@@ -414,14 +428,15 @@
                 qrb.data.palette.palette = palette;
                 qrb.data.palette.num_entries = MS_MAX(colorsWanted,numPaletteGivenEntries);
                 ret = msQuantizeRasterBuffer(rb,&(qrb.data.palette.num_entries),qrb.data.palette.palette,
-                                             paletteGiven,numPaletteGivenEntries);            
+                                             paletteGiven,numPaletteGivenEntries,
+                                             &qrb.data.palette.scaling_maxval);            
             }
         }
         if(ret != MS_FAILURE) {
             ret = msClassifyRasterBuffer(rb,&qrb);
             ret = savePalettePNG(&qrb,info,compression);  
         }
-        //msFreeRasterBuffer(&qrb);
+        msFree(qrb.data.palette.pixels);
         return ret;
     }
     else if(rb->type == MS_BUFFER_BYTE_RGBA) {

Modified: trunk/mapserver/mapquantization.c
===================================================================
--- trunk/mapserver/mapquantization.c	2011-04-19 05:09:19 UTC (rev 11598)
+++ trunk/mapserver/mapquantization.c	2011-04-19 05:14:17 UTC (rev 11599)
@@ -121,16 +121,21 @@
  * - forced_palette: entries that should appear in the computed palette
  * - num_forced_palette_entries: number of entries contained in "force_palette". if 0,
  *   "force_palette" can be NULL
+ * - palette_scaling_maxval: the quantization process may have to reduce the image depth
+ *   by iteratively dividing the pixels by 2. In case palette_scaling_maxval is set to
+ *   something different than 255, the returned palette colors have to be scaled back up to
+ *   255, and rb's pixels will have been scaled down to maxsize (see bug #3848)
  */
 int msQuantizeRasterBuffer(rasterBufferObj *rb,
       unsigned int *reqcolors, rgbaPixel *palette,
-      rgbaPixel *forced_palette, int num_forced_palette_entries) {
+      rgbaPixel *forced_palette, int num_forced_palette_entries,
+      unsigned int *palette_scaling_maxval) {
           rgbaPixel **apixels=NULL; /* pointer to the start rows of truecolor pixels */
 	
     register rgbaPixel *pP;
     register int col;
     
-    unsigned char maxval, newmaxval;
+    unsigned char newmaxval;
     acolorhist_vector achv, acolormap=NULL;
     
     int row;
@@ -142,7 +147,7 @@
     
 	 assert(rb->type == MS_BUFFER_BYTE_RGBA);
 
-    maxval = 255;
+    *palette_scaling_maxval = 255;
 
     apixels=(rgbaPixel**)msSmallMalloc(rb->height*sizeof(rgbaPixel**));
     
@@ -162,41 +167,25 @@
                 apixels, rb->width, rb->height, MAXCOLORS, &colors );
         if ( achv != (acolorhist_vector) 0 )
             break;
-        newmaxval = maxval / 2;
+        newmaxval = *palette_scaling_maxval / 2;
         for ( row = 0; row < rb->height; ++row )
             for ( col = 0, pP = apixels[row]; col < rb->width; ++col, ++pP )
-                PAM_DEPTH( *pP, *pP, maxval, newmaxval );
-        maxval = newmaxval;
+                PAM_DEPTH( *pP, *pP, *palette_scaling_maxval, newmaxval );
+        *palette_scaling_maxval = newmaxval;
     }
     newcolors = MS_MIN(colors, *reqcolors);
-    acolormap = mediancut(achv, colors, rb->width*rb->height, maxval, newcolors);
+    acolormap = mediancut(achv, colors, rb->width*rb->height, *palette_scaling_maxval, newcolors);
     pam_freeacolorhist(achv);
     
     
     *reqcolors = newcolors;
 
 
-    /*
-     ** rescale the palette colors to a maxval of 255
-     */
-
-    if (maxval < 255) {
-        for (x = 0; x < newcolors; ++x) {
-            /* the rescaling part of this is really just PAM_DEPTH() broken out
-             *  for the PNG palette; the trans-remapping just puts the values
-             *  in different slots in the PNG palette */
-        	palette[x].r = (acolormap[x].acolor.r * 255 + (maxval >> 1)) / maxval;
-        	palette[x].g = (acolormap[x].acolor.g * 255 + (maxval >> 1)) / maxval;
-        	palette[x].b = (acolormap[x].acolor.b * 255 + (maxval >> 1)) / maxval;
-        	palette[x].a = (acolormap[x].acolor.a * 255 + (maxval >> 1)) / maxval;
-        }
-    } else {
-        for (x = 0; x < newcolors; ++x) {
-         palette[x].r = acolormap[x].acolor.r;
-         palette[x].g = acolormap[x].acolor.g;
-         palette[x].b = acolormap[x].acolor.b;
-         palette[x].a = acolormap[x].acolor.a;
-        }
+    for (x = 0; x < newcolors; ++x) {
+       palette[x].r = acolormap[x].acolor.r;
+       palette[x].g = acolormap[x].acolor.g;
+       palette[x].b = acolormap[x].acolor.b;
+       palette[x].a = acolormap[x].acolor.a;
     }
     
    free(acolormap);

Modified: trunk/mapserver/mapserver.h
===================================================================
--- trunk/mapserver/mapserver.h	2011-04-19 05:09:19 UTC (rev 11598)
+++ trunk/mapserver/mapserver.h	2011-04-19 05:14:17 UTC (rev 11599)
@@ -2620,7 +2620,9 @@
 
 
 /* in mapimageio.c */
-int msQuantizeRasterBuffer(rasterBufferObj *rb, unsigned int *reqcolors, rgbaPixel *palette, rgbaPixel *forced_palette, int num_forced_palette_entries);
+int msQuantizeRasterBuffer(rasterBufferObj *rb, unsigned int *reqcolors, rgbaPixel *palette,
+      rgbaPixel *forced_palette, int num_forced_palette_entries,
+      unsigned int *palette_scaling_maxval);
 int msClassifyRasterBuffer(rasterBufferObj *rb, rasterBufferObj *qrb);
 int msSaveRasterBuffer(mapObj *map, rasterBufferObj *data, FILE *stream, outputFormatObj *format);
 int msSaveRasterBufferToBuffer(rasterBufferObj *data, bufferObj *buffer, outputFormatObj *format);

Modified: trunk/mapserver/mapsymbol.h
===================================================================
--- trunk/mapserver/mapsymbol.h	2011-04-19 05:09:19 UTC (rev 11598)
+++ trunk/mapserver/mapsymbol.h	2011-04-19 05:14:17 UTC (rev 11599)
@@ -72,6 +72,7 @@
 	unsigned char *pixels; /*stores the actual pixel indexes*/
 	rgbaPixel *palette; /*rgba palette entries*/
 	unsigned int num_entries; /*number of palette entries*/
+   unsigned int scaling_maxval;
 } paletteArrayObj;
 
 typedef struct {



More information about the mapserver-commits mailing list