[mapguide-commits] r4252 - sandbox/rfc60/MgDev/Common/Renderers

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Tue Sep 22 19:08:46 EDT 2009


Author: uvlite
Date: 2009-09-22 19:08:45 -0400 (Tue, 22 Sep 2009)
New Revision: 4252

Modified:
   sandbox/rfc60/MgDev/Common/Renderers/AGGImageIO.cpp
   sandbox/rfc60/MgDev/Common/Renderers/AGGImageIO.h
   sandbox/rfc60/MgDev/Common/Renderers/AGGRenderer.cpp
   sandbox/rfc60/MgDev/Common/Renderers/AGGRenderer.h
Log:
rfc60 the AGGrenderer uses the provided colortable for the color quantization of the PNG8 image

Modified: sandbox/rfc60/MgDev/Common/Renderers/AGGImageIO.cpp
===================================================================
--- sandbox/rfc60/MgDev/Common/Renderers/AGGImageIO.cpp	2009-09-22 23:03:51 UTC (rev 4251)
+++ sandbox/rfc60/MgDev/Common/Renderers/AGGImageIO.cpp	2009-09-22 23:08:45 UTC (rev 4252)
@@ -15,10 +15,10 @@
 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
+//#include "ace/OS.h"
 #include "stdafx.h"
 #include "RendererStyles.h"
 #include "AGGImageIO.h"
-#include "AGGRenderer.h"
 #include "png.h"
 #include "RS_ByteData.h"
 #include "agg_context.h"
@@ -26,12 +26,17 @@
 #include "gd.h" //for image read support other than PNG (which means JPEG and GIF)
 //NOTE: We do not use gd for reading or writing PNG since internally gd drops a bit
 //from the alpha channel, which is not desirable for high quality output
-
 #include "GDUtils.h"
+#include <assert.h>
+#define myassert(COND,L,F) if (!(COND)){ printf ("(%d) failed assertion in %d %s", GetCurrentThreadId(), L,F); throw new exception();}
 
+//#include "smartalloc.h"
 #pragma warning(disable : 4611)
 
+enum MS_RETURN_VALUE {MS_SUCCESS, MS_FAILURE, MS_DONE};
 
+static bool UseColorMap = true;
+
 struct png_write_context
 {
     unsigned char* buf;
@@ -342,9 +347,6 @@
 ////////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////
 
 /* Read a PNG file.  You may want to return an error code if the read
  * fails (depending upon the failure).  There are two "prototypes" given
@@ -653,17 +655,214 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////
+/******************************************************************************
+ * mapgd.c 7803 2008-07-09 05:17:40Z sdlime
+ * Project:  MapServer
+ * Purpose:  GD rendering and other GD related functions.
+ * Author:   Steve Lime and the MapServer team.
+ ******************************************************************************/
+/// copied from mapserver source tree --------> mapgd.c line 3248 - 3463, UV  25.02.2009
+ // copy src to dst using dst's palette
+ // src must be a truecolor image
+ // dst must be a paletted image
+ // method is to fine tune the caching used to lookup color values in the palette:
+ //  -0 is the default method, which allocates cache memory when needed
+ //  -1 is a memory conservative method, that uses very little caching but is much slower
+ //  -2 is a memory hungry caching method (allocates 32MB on the heap) but is the fastest for large images
+ // see bug #2422 for some benchmark timings of these methods
+ //
+int AGGImageIO::ImageCopyForcePaletteGD(gdImagePtr src, gdImagePtr dst, int method) 
+{
+    int x, y;
+    int w, h;
+    int c, r, g, b,color;
+    if(!src || !dst) return MS_FAILURE;
+    // input images have different sizes
+    if(gdImageSX(src) != gdImageSX(dst) || gdImageSY(src) != gdImageSY(dst)) return MS_FAILURE;
+    if(!gdImageTrueColor(src) || gdImageTrueColor(dst)) return MS_FAILURE; /* 24-bit to 8-bit */
+    w = gdImageSX(src);
+    h = gdImageSY(src);
+    if(method==0) {
+        /*default caching strategy*/
+        unsigned short ***cols=(unsigned short***)calloc(256,sizeof(unsigned short**));
+        
+        /*pointer to cache, pointed by red component, indexed by green component*/
+        unsigned short **data=(unsigned short**)calloc(256*256,sizeof(unsigned short*));
+        
+       for(r=0;r<256;r++) {
+        /*populate the cache*/
+        cols[r]=&(data[r*256]);
+
+        for (y = 0; (y < h); y++) {
+            for (x = 0; (x < w); x++) {
+                c = gdImageGetPixel(src, x, y);  
+                r = gdTrueColorGetRed(c);
+                g = gdTrueColorGetGreen(c);
+                b = gdTrueColorGetBlue(c);
+                
+                if(cols[r][g]==NULL) {
+                    /*this is the first time we see this r,g couple. 
+                     *allocate bytes for the blue component*/ 
+                    cols[r][g]=(unsigned short*)calloc(256,sizeof(unsigned short));
+                }
+
+                if(!cols[r][g][b]) {
+                    /*this r,g,b triplet was never seen before
+                     * compute its index in the palette and cache the result
+                     */
+                    color = gdImageColorClosest(dst, r, g, b);
+                    dst->pixels[y][x] = color;
+                    /*the cache data was calloc'ed to avoid initialization
+                     * store 'index+1' so we are sure the test for cols[r][g][b]
+                     * returns true, i.e that this color was cached*/
+                    cols[r][g][b]=color+1;
+                }
+                else {
+                    /*the cache data was calloc'ed to avoid initialization
+                     * the cache contains 'index+1' so we must subtract
+                     * 1 to get the real color index*/
+                    dst->pixels[y][x] = cols[r][g][b]-1;
+                } // if
+            } // for x
+        } // for y
+       } // for r
+        for(r=0;r<256;r++) 
+            for(g=0;g<256;g++) 
+                if(cols[r][g]) /*only free the row if it was used*/
+                    free(cols[r][g]); 
+        free(data);
+        free(cols);
+    }
+    else if(method==1) {
+        /*memory conservative method, does not allocate mem on the heap*/
+        int R[10], G[10], B[10], C[10];
+        int i, color, nCache = 0, iCache =0, maxCache=10;
+
+        for (y = 0; (y < h); y++) {
+            for (x = 0; (x < w); x++) {
+                c = gdImageGetPixel(src, x, y);
+                r =  gdTrueColorGetRed(c);
+                g = gdTrueColorGetGreen(c);
+                b = gdTrueColorGetBlue(c);
+                color = -1;
+
+                /* adding a simple cache to keep colors instead of always calling gdImageColorClosest
+               seems to reduce significantly the time passed in this function 
+               spcially with large images (bug 2096)*/
+                for (i=0; i<nCache; i++)
+                {
+                    if (R[i] == r)
+                    {
+                        if (G[i] == g && B[i] == b)
+                        {
+                            color = C[i];
+                            break;
+                        }
+                    }
+                }
+
+                if (color == -1)
+                {
+                    color = gdImageColorClosest(dst, r, g, b);
+                    R[iCache] = r;
+                    G[iCache] = g;
+                    B[iCache] = b;
+                    C[iCache] = color;
+                    nCache++;
+                    if (nCache >= maxCache)
+                        nCache = maxCache;
+
+                    iCache++;
+                    if (iCache == maxCache)
+                        iCache = 0;
+                }
+
+                gdImageSetPixel(dst, x, y, color);
+            }
+        }
+    }
+    else if(method==2) {
+        /*memory hungry method, fastest for very large images*/
+        
+        /*use a cache for every possible r,g,b triplet
+         * this is usually a full 32MB (when short is 2 bytes) */
+        short *cache=(short*)calloc(16777216,sizeof(short));
+
+        for (y = 0; (y < h); y++) {
+            for (x = 0; (x < w); x++) {
+                int index;
+                c = gdImageGetPixel(src, x, y);    
+                index=c&0xFFFFFF; /*use r,g,b for the cache index, i.e. remove alpha*/
+                if(!cache[index]) {
+                    r =  gdTrueColorGetRed(c);
+                    g = gdTrueColorGetGreen(c);
+                    b = gdTrueColorGetBlue(c);
+                    color = gdImageColorClosest(dst, r, g, b);
+                    cache[index]=color+1;
+                    dst->pixels[y][x] = color;
+                }
+                else
+                    dst->pixels[y][x] = cache[index]-1;
+            }
+        }
+        free(cache);
+    }
+    if(gdImageTrueColor(dst)) return MS_FAILURE; /* result is not 8-bit */
+    return MS_SUCCESS;
+}
 ////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////
+/// helper function to create an empty image with a palette provided in std::list<MgColor>
+/// inParam: 24bit image, filename of palette file, imagesixeX, imagesizeY
+/// return: 8bit image using given palette if provided ...
+gdImagePtr AGGImageIO::CreateGdImageWithPalette( gdImagePtr img24, RSCOLORS* baseColorPalette,
+                                                 int sx, int sy) 
+{
+    gdImagePtr gdPPalette, gdPPaletteFromImg24;
+    /// allow empty default parameter	assert (baseColorPalette);
+    int ncolors = baseColorPalette?baseColorPalette->size():0;
 
+    myassert(sx > 0 && sy > 0,__LINE__, __WFILE__);
 
+    // create new empty palette image
+    gdPPalette = gdImageCreatePalette(sx, sy);
+    myassert (gdPPalette,__LINE__, __WFILE__); 
+
+    // if the palette file contains less than 256, fill the rest with colors generated by gd
+    // those can include the base colors
+    if (ncolors < 256)
+    {
+        gdPPaletteFromImg24 = gdImageCreatePaletteFromTrueColor(img24,1,(256 - ncolors - 1));
+        myassert (gdPPaletteFromImg24,__LINE__, __WFILE__);
+
+        // copy colors from palette into new empty gdpalette
+        for (int c = 0; c < gdPPaletteFromImg24->colorsTotal; c++) 
+        {
+            gdImageColorAllocate(gdPPalette,gdPPaletteFromImg24->red[c], 
+                                            gdPPaletteFromImg24->green[c],  
+                                            gdPPaletteFromImg24->blue[c]);
+        }
+        gdImageDestroy(gdPPaletteFromImg24);
+    }
+#ifdef _DEBUG_PNG8
+    printf("\n(%d) ########################### AGGImageIO::CreateGdImageWithPalette colors: %d\n",GetCurrentThreadId(), ncolors);
+#endif
+
+    if (baseColorPalette)
+    {
+        // add colors from the colorpalette	(duplicate color entries make the used palette less than 256)
+        RSCOLORS::iterator it;
+        for (it = baseColorPalette->begin();it != baseColorPalette->end(); it++) 
+        {
+            gdImageColorAllocate(gdPPalette, (*it).red(), (*it).green(), (*it).blue());
+//            delete *it; // the RS_Color is on the heap and needs destruction
+        }
+//        delete baseColorPalette;
+    }
+    myassert(gdImageTrueColor(gdPPalette) == 0,__LINE__, __WFILE__);		// result is not a 8-bit paletted image 
+    return gdPPalette;  // this is an empty image with the right color palette
+}
+////////////////////////////////////////////////////////////////////////////////////////
+/// create an image using the other Save method and store it at filename
 bool AGGImageIO::Save(const RS_String& filename, const RS_String& format,
                  unsigned int* src, int src_width, int src_height,
                  int dst_width, int dst_height, RS_Color& bgColor)
@@ -700,10 +899,13 @@
     return true;
 }
 
-
+////////////////////////////////////////////////////////////////////////////////////////
+/// convert imagebuffer src into the desired format using the provided baseColorPalette for 8bit 
+/// (the baseColorPalette is a default parameter NULL)
 RS_ByteData* AGGImageIO::Save(const RS_String& format,
                   unsigned int* src, int src_width, int src_height,
-                  int dst_width, int dst_height, RS_Color& bgColor)
+                  int dst_width, int dst_height, RS_Color& bgColor, 
+                  PRSCOLORS baseColorPalette)
 {
     bool drop_alpha = bgColor.alpha() == 255;
 
@@ -749,77 +951,98 @@
             return byteData;
         }
         else if (format == L"JPG" || format == L"GIF" || format == L"PNG8")
-        {
-            gdImagePtr gdimg = gdImageCreateTrueColor(dst_width, dst_height);
+        {	// gdimg24 contains the 24bit image
+            gdImagePtr gdimg24 = gdImageCreateTrueColor(dst_width, dst_height);
 
-            int bgc = ConvertColor(gdimg, bgColor);
+            int bgc = ConvertColor(gdimg24, bgColor);
 
             // initialize the destination image to the bg color (temporarily turn
             // off alpha blending so the fill has the supplied alpha)
-            gdImageAlphaBlending(gdimg, 0);
-            gdImageFilledRectangle(gdimg, 0, 0, gdImageSX(gdimg)-1, gdImageSY(gdimg)-1, bgc);
+            gdImageAlphaBlending(gdimg24, 0);
+            gdImageFilledRectangle(gdimg24, 0, 0, gdImageSX(gdimg24)-1, gdImageSY(gdimg24)-1, bgc);
 
             // set any transparent color
             if (bgColor.alpha() != 255)
-                gdImageColorTransparent(gdimg, bgc);
+                gdImageColorTransparent(gdimg24, bgc);
 
+            // copy the src data into the gdImage
             unsigned int* ptr = src;
             for (int j=0; j<dst_height; j++)
             {
                 for(int i=0; i<dst_width; i++)
                 {
                     //TODO: can be optimized
-
                     unsigned int c = *ptr++;
                     int a = c >> 24;
-                    int b = (c >> 16) & 0xff;
-                    int g = (c >> 8) & 0xff;
-                    int r = c & 0xff;
-
                     // skip any fully transparent pixels so a transparent
                     // background color will show through
                     if (a != 0)
                     {
-                        int gdc = gdImageColorAllocateAlpha(gdimg, r, g, b, a);
-                        gdImageSetPixel(gdimg, i, j, gdc);
+                        int b = (c >> 16) & 0xff;  // some simple optimization ;-)
+                        int g = (c >> 8) & 0xff;
+                        int r = c & 0xff;
+
+                        int gdc = gdImageColorAllocateAlpha(gdimg24, r, g, b, a);
+                        gdImageSetPixel(gdimg24, i, j, gdc);
                     }
                 }
             }
 
-            gdImageAlphaBlending(gdimg, 1);
+            gdImageAlphaBlending(gdimg24, 1);
 
             // Make output image non-interlaced --- it's a little faster to compress that way.
-            gdImageInterlace(gdimg, 0);
+            gdImageInterlace(gdimg24, 0);
 
             // Make sure the alpha values get saved -- but only if required
             // it is faster not to save them and makes a smaller PNG
-            if (bgColor.alpha() != 255)
-                gdImageSaveAlpha(gdimg, 1);
-            else
-                gdImageSaveAlpha(gdimg, 0);
+            gdImageSaveAlpha(gdimg24, (bgColor.alpha() != 255)?1:0);
 
-            //convert to 256 color paletted image for PNG8, GIF
-            if (format == L"GIF" || format == L"PNG8")
-                gdImageTrueColorToPalette(gdimg, 0, 256);
+            gdImagePtr gdImgPalette = NULL;
+            //  convert to 256 color paletted image for PNG8, GIF
+            if (format == L"GIF" || format == L"PNG8") 
+            //{ //former GIF code
+            //  gdImageTrueColorToPalette(gdimg24, 0, 256);
+            //	gdImgPalette = gdimg24;
+            //}
+            {	/// skip color quantization if no palette given or empty
+                if (baseColorPalette && !baseColorPalette->empty() && UseColorMap)  // memory based switch
+                {	
+                    gdImgPalette = CreateGdImageWithPalette(gdimg24, baseColorPalette, 
+                                                            gdImageSX(gdimg24), gdImageSY(gdimg24));
+                    myassert(gdImgPalette,__LINE__, __WFILE__);
 
+                    // methods are described above - we use method 1 as default????? TODO what's best???
+                    myassert(ImageCopyForcePaletteGD(gdimg24, gdImgPalette, 1) == MS_SUCCESS,__LINE__, __WFILE__);
+                    /// forced palette GD image now in gdimgPalette
+                } else 
+                {
+                    gdImageTrueColorToPalette(gdimg24, 0, 256);  // in place conversion
+                    gdImgPalette = gdimg24;
+                }
+            }
+
             //get an in-memory image stream
             int size = 0;
             unsigned char* data = NULL;
 
             if (format == L"GIF")       // MgImageFormats::Gif
-                data = (unsigned char*)gdImageGifPtr(gdimg, &size);
+                data = (unsigned char*)gdImageGifPtr(gdImgPalette, &size);
+            else if (format == L"PNG8")   // MgImageFormats::Png8
+                data = (unsigned char*)gdImagePngPtr(gdImgPalette, &size);
             else if (format == L"JPG")  // MgImageFormats::Jpeg
-                data = (unsigned char*)gdImageJpegPtr(gdimg, &size, 75);
-            else if (format == L"PNG8")   // MgImageFormats::Png8
-                data = (unsigned char*)gdImagePngPtr(gdimg, &size);
+                data = (unsigned char*)gdImageJpegPtr(gdimg24, &size, 75);
 
             std::auto_ptr<RS_ByteData> byteData;
             byteData.reset((NULL == data)? NULL : new RS_ByteData(data, size));
 
             gdFree(data);
 
-            //if we allocated a temporary image to stretch-blit, destroy it
-            gdImageDestroy(gdimg);
+            if (gdimg24 == gdImgPalette)
+                gdimg24 = NULL;		// reset pointer so destructor is not called twice -> exception !!!
+            else	//if we allocated a temporary image to stretch-blit, destroy it
+                gdImageDestroy(gdimg24);
+            //if we allocated a paletted image, destroy it (very likely that is)
+            gdImageDestroy(gdImgPalette);
 
             return byteData.release();
         }
@@ -830,6 +1053,8 @@
     return NULL;
 }
 
+//---------------------------------------------------------------------------
+
 //TODO: This routine should be rewritten to use agg to blend PNGs more accurately
 void AGGImageIO::Combine(const RS_String& src1, const RS_String& src2, const RS_String& dst)
 {

Modified: sandbox/rfc60/MgDev/Common/Renderers/AGGImageIO.h
===================================================================
--- sandbox/rfc60/MgDev/Common/Renderers/AGGImageIO.h	2009-09-22 23:03:51 UTC (rev 4251)
+++ sandbox/rfc60/MgDev/Common/Renderers/AGGImageIO.h	2009-09-22 23:08:45 UTC (rev 4252)
@@ -14,9 +14,10 @@
 //  License along with this library; if not, write to the Free Software
 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
+#include "gd.h"
+#include "AGGRenderer.h"
 
 class RS_ByteData;
-
 class AGGImageIO
 {
 public:
@@ -26,7 +27,8 @@
 
     static RS_ByteData* Save(const RS_String& format,
                       unsigned int* src, int src_width, int src_height,
-                      int dst_width, int dst_height, RS_Color& bgColor);
+                      int dst_width, int dst_height, RS_Color& bgColor, 
+                      PRSCOLORS baseColorPalette=NULL);
 
     static void Combine(const RS_String& src1, const RS_String& src2, const RS_String& dst);
 
@@ -37,6 +39,8 @@
     static unsigned int* DecodeJPEG(const unsigned char* src, size_t len, int& width, int& height);
 
 private:
+    static gdImagePtr CreateGdImageWithPalette( gdImagePtr img24, PRSCOLORS colors, int x, int y); 
+    static int ImageCopyForcePaletteGD(gdImagePtr src, gdImagePtr dst, int method);
     static unsigned char* ReadFile(const RS_String& fname, size_t& len);
     static void UnmultiplyAlpha(unsigned int* argb, int len);
 };

Modified: sandbox/rfc60/MgDev/Common/Renderers/AGGRenderer.cpp
===================================================================
--- sandbox/rfc60/MgDev/Common/Renderers/AGGRenderer.cpp	2009-09-22 23:03:51 UTC (rev 4251)
+++ sandbox/rfc60/MgDev/Common/Renderers/AGGRenderer.cpp	2009-09-22 23:08:45 UTC (rev 4252)
@@ -88,7 +88,7 @@
 bool AGGRenderer::s_bClampPoints    = false;
 bool AGGRenderer::s_bGeneralizeData = false;
 
-
+///-----------------------------------------------------------------------------------------
 // constructor that allows a backbuffer
 AGGRenderer::AGGRenderer(int width,
                          int height,
@@ -130,7 +130,7 @@
         m_labeler = new LabelRendererLocal(this, tileExtentOffset);
 }
 
-
+///-----------------------------------------------------------------------------------------
 //default constructor
 AGGRenderer::AGGRenderer(int width,
                          int height,
@@ -184,7 +184,7 @@
         m_labeler = new LabelRendererLocal(this, tileExtentOffset);
 }
 
-
+///-----------------------------------------------------------------------------------------
 AGGRenderer::~AGGRenderer()
 {
     delete m_context;
@@ -195,9 +195,8 @@
         delete[] m_rows;
 }
 
-
-void AGGRenderer::UpdateBackBuffer(int width, int height, unsigned int* backbuffer)
-{
+///-----------------------------------------------------------------------------------------
+void AGGRenderer::UpdateBackBuffer(int width, int height, unsigned int* backbuffer){
     if (m_bownbuffer)
         delete[] m_rows;
 
@@ -211,7 +210,7 @@
     m_context = new agg_context(m_rows, m_width, m_height);
 }
 
-
+///-----------------------------------------------------------------------------------------
 unsigned int* AGGRenderer::GetBackBuffer(int &width, int& height)
 {
     width = m_width;
@@ -219,31 +218,33 @@
     return m_rows;
 }
 
-
+///-----------------------------------------------------------------------------------------
+/// this one writes into a file not returning a ByteStream using default parameters for the W x H
 void AGGRenderer::Save(const RS_String& filename, const RS_String& format)
 {
     Save(filename, format, m_width, m_height);
 }
-
-
+///-----------------------------------------------------------------------------------------
+/// this one writes into a file not returning a ByteStream!!
 void AGGRenderer::Save(const RS_String& filename, const RS_String& format, int width, int height)
 {
     AGGImageIO::Save(filename, format, m_rows, m_width, m_height, width, height, m_bgcolor);
 }
-
-
-RS_ByteData* AGGRenderer::Save(const RS_String& format, int width, int height)
+///-----------------------------------------------------------------------------------------
+/// return the rendered image passed in via the imagebuffer (m_rows) as a bytestream in the given image format
+/// using the provided colorPalette if given
+RS_ByteData* AGGRenderer::Save(const RS_String& format, int width, int height, 
+							   PRSCOLORS baseColorPalette)
 {
-    return AGGImageIO::Save(format, m_rows, m_width, m_height, width, height, m_bgcolor);
+    return AGGImageIO::Save(format, m_rows, m_width, m_height, width, height, m_bgcolor, baseColorPalette);
 }
-
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::Combine(const RS_String& fileIn1, const RS_String& fileIn2, const RS_String& fileOut)
 {
     AGGImageIO::Combine(fileIn1, fileIn2, fileOut);
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::StartMap(RS_MapUIInfo* mapInfo,
                            RS_Bounds&    extents,
                            double        mapScale,
@@ -300,7 +301,7 @@
     InitFontEngine(this);
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::EndMap()
 {
     // turn off selection mode so the labels draw normal
@@ -313,7 +314,7 @@
     m_mapInfo = NULL;
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::StartLayer(RS_LayerUIInfo*      legendInfo,
                              RS_FeatureClassInfo* classInfo)
 {
@@ -322,7 +323,7 @@
     m_fcInfo = classInfo;
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::EndLayer()
 {
     // clear the layer/feature info
@@ -330,7 +331,7 @@
     m_fcInfo = NULL;
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::StartFeature(RS_FeatureReader* /*feature*/,
                                bool              /*initialPass*/,
                                const RS_String*  /*tooltip*/,
@@ -342,7 +343,7 @@
 {
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::ProcessPolygon(LineBuffer* lb, RS_FillStyle& fill)
 {
     _ASSERT(NULL != lb);
@@ -486,7 +487,7 @@
     }
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::ProcessPolyline(LineBuffer* lb, RS_LineStroke& lsym)
 {
     _ASSERT(NULL != lb);
@@ -595,7 +596,7 @@
     printf("      minx = %6.4f miny = %6.4f maxx = %6.4f maxy = %6.4f\n", ext.minx, ext.miny, ext.maxx, ext.maxy); \
     printf("      width = %6.4f height = %6.4f\n", ext.width(), ext.height());
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::ProcessRaster(unsigned char* data,
                                 int length,
                                 RS_ImageFormat format,
@@ -625,7 +626,7 @@
     }
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::ProcessMarker(LineBuffer* srclb, RS_MarkerDef& mdef, bool allowOverpost, RS_Bounds* bounds)
 {
     RS_MarkerDef use_mdef = mdef;
@@ -650,7 +651,7 @@
     }
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::ProcessOneMarker(double x, double y, RS_MarkerDef& mdef, bool allowOverpost, RS_Bounds* bounds)
 {
     RS_InputStream* symbol = NULL;
@@ -1030,7 +1031,7 @@
     }
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::ProcessLabelGroup(RS_LabelInfo*    labels,
                                     int              nlabels,
                                     const RS_String& text,
@@ -1047,88 +1048,88 @@
     m_labeler->ProcessLabelGroup(labels, nlabels, text, type, exclude, path, scaleLimit);
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::SetSymbolManager(RS_SymbolManager* manager)
 {
     m_symbolManager = manager;
 }
 
-
+///-----------------------------------------------------------------------------------------
 RS_MapUIInfo* AGGRenderer::GetMapInfo()
 {
     return m_mapInfo;
 }
 
-
+///-----------------------------------------------------------------------------------------
 RS_LayerUIInfo* AGGRenderer::GetLayerInfo()
 {
     return m_layerInfo;
 }
 
-
+///-----------------------------------------------------------------------------------------
 RS_FeatureClassInfo* AGGRenderer::GetFeatureClassInfo()
 {
     return m_fcInfo;
 }
 
-
+///-----------------------------------------------------------------------------------------
 double AGGRenderer::GetMapScale()
 {
     return m_mapScale;
 }
 
-
+///-----------------------------------------------------------------------------------------
 double AGGRenderer::GetDrawingScale()
 {
     return m_drawingScale;
 }
 
-
+///-----------------------------------------------------------------------------------------
 RS_Bounds& AGGRenderer::GetBounds()
 {
     return m_extents;
 }
 
-
+///-----------------------------------------------------------------------------------------
 double AGGRenderer::GetDpi()
 {
     return m_dpi;
 }
 
-
+///-----------------------------------------------------------------------------------------
 double AGGRenderer::GetMetersPerUnit()
 {
     return m_metersPerUnit;
 }
 
-
+///-----------------------------------------------------------------------------------------
 bool AGGRenderer::RequiresClipping()
 {
     return m_bRequiresClipping;
 }
 
-
+///-----------------------------------------------------------------------------------------
 bool AGGRenderer::RequiresLabelClipping()
 {
     // always the same value as RequiresClipping
     return m_bRequiresClipping;
 }
 
-
+///-----------------------------------------------------------------------------------------
 bool AGGRenderer::SupportsTooltips()
 {
     // set to false to disable processing of tooltips
     return false;
 }
 
-
+///-----------------------------------------------------------------------------------------
 bool AGGRenderer::SupportsHyperlinks()
 {
     // set to false to disable processing of hyperlinks
     return false;
 }
 
-
+///-----------------------------------------------------------------------------------------
 bool AGGRenderer::UseLocalOverposting()
 {
     return m_bLocalOverposting;
@@ -1324,7 +1325,7 @@
 }
 
 
-//-----------------------------------------------------------------------------
+///-----------------------------------------------------------------------------
 // scale an input number in meters to a mapping
 // space number given a device or mapping space unit.
 //-----------------------------------------------------------------------------
@@ -1340,13 +1341,13 @@
     return number * scale_factor;
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::SetRenderSelectionMode(bool mode)
 {
     SetRenderSelectionMode(mode, 0x0000FF00);
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::SetRenderSelectionMode(bool mode, int rgba)
 {
     SE_Renderer::SetRenderSelectionMode(mode, rgba);
@@ -1367,7 +1368,7 @@
 // Text drawing
 //////////////////////////////////////////////////////////////////////////////
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::DrawString(const RS_String& s,
                              double           x,
                              double           y,
@@ -1383,7 +1384,7 @@
     DrawString(c(), sConv, x, y, width, height, font, color, angleRad);
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::DrawString(agg_context*     cxt,
                              const RS_String& s,
                              double           x,
@@ -1742,7 +1743,7 @@
     }
 }
 
-
+///-----------------------------------------------------------------------------------------
 // Called when applying a line style on a feature geometry.  Line styles can
 // only be applied to linestring and polygon feature geometry types.
 void AGGRenderer::ProcessLine(SE_ApplyContext* ctx, SE_RenderLineStyle* style)
@@ -1825,7 +1826,7 @@
         LineBufferPool::FreeLineBuffer(m_pPool, spLB.release());
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::_TransferPoints(agg_context* c, LineBuffer* srcLB, const SE_Matrix* xform, unsigned int* pathids, bool isPolygon)
 {
     if (s_bClampPoints)
@@ -1930,7 +1931,7 @@
     }
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::_TransferPointsClamped(agg_context* c, LineBuffer* srcLB, const SE_Matrix* xform, unsigned int* pathids, bool isPolygon)
 {
     c->ps.remove_all();
@@ -2080,7 +2081,7 @@
     DrawScreenPolyline(c(), srclb, xform, lineStroke);
 }
 
-
+///-----------------------------------------------------------------------------------------
 // copied from WritePolylines, except it doesn't do to screen transform - we should refactor
 void AGGRenderer::DrawScreenPolyline(agg_context* c, LineBuffer* srclb, const SE_Matrix* xform, const SE_LineStroke& lineStroke)
 {
@@ -2154,13 +2155,13 @@
     c->ras.filling_rule(agg::fill_even_odd);
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::DrawScreenPolygon(LineBuffer* polygon, const SE_Matrix* xform, unsigned int color)
 {
     DrawScreenPolygon(c(), polygon, xform, color);
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::DrawScreenPolygon(agg_context* c, LineBuffer* polygon, const SE_Matrix* xform, unsigned int color)
 {
     if ((color & 0xFF000000) == 0)
@@ -2188,59 +2189,59 @@
     }
 }
 
-
+///-----------------------------------------------------------------------------------------
 bool AGGRenderer::YPointsUp()
 {
     return true;
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::GetWorldToScreenTransform(SE_Matrix& xform)
 {
     xform = m_xform;
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::SetWorldToScreenTransform(SE_Matrix& xform)
 {
     m_xform = xform;
     m_xform.inverse(m_ixform);
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::WorldToScreenPoint(double& inx, double& iny, double& ox, double& oy)
 {
     m_xform.transform(inx, iny, ox, oy);
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::ScreenToWorldPoint(double& inx, double& iny, double& ox, double& oy)
 {
     m_ixform.transform(inx, iny, ox, oy);
 }
 
-
+///-----------------------------------------------------------------------------------------
 // returns number of pixels per millimeter device
 double AGGRenderer::GetScreenUnitsPerMillimeterDevice()
 {
     return m_dpi / MILLIMETERS_PER_INCH;
 }
 
-
+///-----------------------------------------------------------------------------------------
 // returns number of pixels per millimeter world
 double AGGRenderer::GetScreenUnitsPerMillimeterWorld()
 {
     return m_dpi / MILLIMETERS_PER_INCH / m_mapScale;
 }
 
-
+///-----------------------------------------------------------------------------------------
 // screen units are pixels
 double AGGRenderer::GetScreenUnitsPerPixel()
 {
     return 1.0;
 }
 
-
+///-----------------------------------------------------------------------------------------
 RS_FontEngine* AGGRenderer::GetRSFontEngine()
 {
     return this;
@@ -2252,7 +2253,7 @@
     m_labeler->AddExclusionRegion(fpts, npts);
 }
 
-
+///-----------------------------------------------------------------------------------------
 // labeling - this is the entry API for adding SE labels
 // to the label mananger
 void AGGRenderer::ProcessSELabelGroup(SE_LabelInfo*   labels,
@@ -2269,7 +2270,7 @@
     m_labeler->ProcessLabelGroup(labels, nlabels, type, exclude, path);
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::DrawScreenRaster(unsigned char* data, int length,
                                    RS_ImageFormat format, int native_width, int native_height,
                                    double x, double y, double w, double h, double angledeg)
@@ -2277,6 +2278,7 @@
     DrawScreenRaster(c(), data, length, format, native_width, native_height, x, y, w, h, angledeg);
 }
 
+///-----------------------------------------------------------------------------------------
 
 void AGGRenderer::DrawScreenRaster(agg_context* cxt, unsigned char* data, int length,
                                    RS_ImageFormat format, int native_width, int native_height,
@@ -2362,7 +2364,7 @@
     RenderWithTransform(src, cxt, img_mtx, format);
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::DrawScreenRasterTransform(agg_context* cxt, unsigned char* data, int length,
                                             RS_ImageFormat format, int native_width, int native_height,
                                             double x, double y, double w, double h,
@@ -2420,7 +2422,7 @@
 #endif
 }
 
-
+///-----------------------------------------------------------------------------------------
 // Renders the mesh rectangle defined by the point mappings at the four supplied mesh indices
 void AGGRenderer::RenderTransformMeshRectangle(mg_rendering_buffer& src, agg_context* cxt,
                                                RS_ImageFormat format, TransformMesh* transformMesh,
@@ -2443,7 +2445,7 @@
         mesh_pt_ur.pt_dest, mesh_pt_ul.pt_dest, mesh_pt_ll.pt_dest);
 }
 
-
+///-----------------------------------------------------------------------------------------
 // Renders the triangle in the source image defined by the three source points into
 // the triangle in the supplied context defined by the three destination points.
 void AGGRenderer::RenderTransformedTriangle(mg_rendering_buffer& src, agg_context* cxt, RS_ImageFormat format,
@@ -2471,7 +2473,7 @@
     RenderWithTransform(src, cxt, img_mtx, format, false);
 }
 
-
+///-----------------------------------------------------------------------------------------
 // Renders the source image to the destination context, using the specified
 // affine transformation matrix.
 void AGGRenderer::RenderWithTransform(mg_rendering_buffer& src, agg_context* cxt,
@@ -2580,7 +2582,7 @@
 //////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////
 
-
+///-----------------------------------------------------------------------------------------
 // Inserts the contents of a given DWF input stream into the current
 // output W2D.  The given coord sys transformation is applied and geometry
 // will be clipped to the RS_Bounds context of the DWFRenderer.
@@ -2705,7 +2707,7 @@
     }
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::AddW2DContent(RS_InputStream* in, CSysTransformer* xformer, const RS_String& w2dfilter)
 {
     WT_Result result;
@@ -2746,7 +2748,7 @@
         m_imw2d = NULL;
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::SetActions(WT_File& file)
 {
     file.set_stream_open_action (agr_open);
@@ -2827,7 +2829,7 @@
     file.set_gouraud_polyline_action(agr_process_gouraudPolyline);
 }
 
-
+///-----------------------------------------------------------------------------------------
 // Given an array of points in W2D logical coordinates, this function:
 // 1. Transforms W2D logical coords into their model space using the
 //    W2D file's units structure
@@ -2950,7 +2952,7 @@
     return spLB.release();
 }
 
-
+///-----------------------------------------------------------------------------------------
 // This function scales a W2D space related value from source W2D space
 // to destination.  Since the source W2D file can fit into a small piece
 // of the destination DWF or be much larger, we need to take that scaling
@@ -2981,7 +2983,7 @@
     return dDstSpace;
 }
 
-
+///-----------------------------------------------------------------------------------------
 void AGGRenderer::UpdateSymbolTrans(WT_File& /*file*/, WT_Viewport& viewport)
 {
     _ASSERT(m_xformer);

Modified: sandbox/rfc60/MgDev/Common/Renderers/AGGRenderer.h
===================================================================
--- sandbox/rfc60/MgDev/Common/Renderers/AGGRenderer.h	2009-09-22 23:03:51 UTC (rev 4251)
+++ sandbox/rfc60/MgDev/Common/Renderers/AGGRenderer.h	2009-09-22 23:08:45 UTC (rev 4252)
@@ -48,6 +48,14 @@
 };
 typedef agg::row_ptr_cache<unsigned char> mg_rendering_buffer;
 
+
+/// for the list of colors used to do color quantization
+typedef std::list<RS_Color*> RSCOLORLIST;
+typedef RSCOLORLIST* PRSCOLORLIST;
+/// the efficient way
+typedef std::vector<RS_Color> RSCOLORS;
+typedef RSCOLORS* PRSCOLORS;
+
 class AGGRenderer : public SE_Renderer, public RS_FontEngine
 {
     friend class LabelRenderer;
@@ -149,7 +157,7 @@
     //
     RENDERERS_API void Save(const RS_String& filename, const RS_String& format);
     RENDERERS_API void Save(const RS_String& filename, const RS_String& format, int width, int height);
-    RENDERERS_API RS_ByteData* Save(const RS_String& format, int width, int height);
+    RENDERERS_API RS_ByteData* Save(const RS_String& format, int width, int height, PRSCOLORS baseColorPalette=NULL);
 
     RENDERERS_API void Combine(const RS_String& fileIn1, const RS_String& fileIn2, const RS_String& fileOut);
     RENDERERS_API void SetWorldToScreenTransform(SE_Matrix& xform);



More information about the mapguide-commits mailing list