[mapserver-commits] r13186 - trunk/mapserver

svn at osgeo.org svn at osgeo.org
Wed Feb 29 15:56:49 EST 2012


Author: rouault
Date: 2012-02-29 12:56:49 -0800 (Wed, 29 Feb 2012)
New Revision: 13186

Modified:
   trunk/mapserver/HISTORY.TXT
   trunk/mapserver/mapagg.cpp
   trunk/mapserver/mapcairo.c
   trunk/mapserver/mapdummyrenderer.c
   trunk/mapserver/mapgd.c
   trunk/mapserver/mapkml.cpp
   trunk/mapserver/mapogl.cpp
   trunk/mapserver/mapserver.h
   trunk/mapserver/maputil.c
Log:
PDF backend: add support for generating geospatial PDF, when GDAL 2.0 with PDF driver is used, and the GEO_ENCODING FORMATOPTION (set to ISO32000 or OGC_BP) is added to the OUTPUTFORMAT definition. (#4216)

Modified: trunk/mapserver/HISTORY.TXT
===================================================================
--- trunk/mapserver/HISTORY.TXT	2012-02-29 18:20:20 UTC (rev 13185)
+++ trunk/mapserver/HISTORY.TXT	2012-02-29 20:56:49 UTC (rev 13186)
@@ -15,6 +15,10 @@
 Current Version (SVN trunk, 6.1-dev, future 6.2): 
 -------------------------------------------------
 
+- PDF backend: add support for generating geospatial PDF, when
+  GDAL 2.0 with PDF driver is used, and the GEO_ENCODING FORMATOPTION
+  (set to ISO32000 or OGC_BP) is added to the OUTPUTFORMAT definition. (#4216)
+
 - Python mapscript: fix swig mappings to work with both python 2.5.and 2.6 (#3940)
 
 - Added classgroup CGI parameter support (#4207)

Modified: trunk/mapserver/mapagg.cpp
===================================================================
--- trunk/mapserver/mapagg.cpp	2012-02-29 18:20:20 UTC (rev 13185)
+++ trunk/mapserver/mapagg.cpp	2012-02-29 20:56:49 UTC (rev 13186)
@@ -841,7 +841,7 @@
    return image;
 }
 
-int agg2SaveImage(imageObj *img, FILE *fp, outputFormatObj * format) {
+int agg2SaveImage(imageObj *img, mapObj* map, FILE *fp, outputFormatObj * format) {
    msSetError(MS_MISCERR, "AGG2 does not support direct image saving", "agg2SaveImage()");
 
    return MS_FAILURE;

Modified: trunk/mapserver/mapcairo.c
===================================================================
--- trunk/mapserver/mapcairo.c	2012-02-29 18:20:20 UTC (rev 13185)
+++ trunk/mapserver/mapcairo.c	2012-02-29 20:56:49 UTC (rev 13186)
@@ -43,6 +43,11 @@
 #include <svg-cairo.h>
 #endif
 
+#ifdef USE_GDAL
+#include <cpl_string.h>
+#include <gdal.h>
+#endif
+
 # include <cairo-ft.h>
 /*
 #include <pango/pangocairo.h>
@@ -699,10 +704,145 @@
     return image;
 }
 
-int saveImageCairo(imageObj *img, FILE *fp, outputFormatObj *format) {
+/* msSaveImagePostPDFProcessing() will call the GDAL PDF driver to add geospatial */
+/* information to the regular PDF generated by cairo. This is only triggered if the */
+/* GEO_ENCODING outputformat option is set (to ISO32000 or OGC_BP). Additionnal */
+/* options can be provided by specifying outputformat options starting with */
+/* METADATA_ITEM: prefix. For example METADATA_ITEM:PRODUCER=MapServer */
+/* Those options are AUTHOR, CREATOR, CREATION_DATE, KEYWORDS, PRODUCER, SUBJECT, TITLE */
+/* See http://gdal.org/frmt_pdf.html documentation. */
+
+static void msTransformToGeospatialPDF(imageObj *img, mapObj *map, cairo_renderer *r)
+{
+/* We need a GDAL 2.0 PDF driver at runtime, but as far as the C API is concerned, GDAL 1.9 is */
+/* largely sufficient. */
+#if defined(USE_GDAL) && defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1900
+    GDALDatasetH hDS = NULL;
+    const char* pszGEO_ENCODING = NULL;
+    GDALDriverH hPDFDriver = NULL;
+    const char* pszVirtualIO = NULL;
+    int bVirtualIO = FALSE;
+    char* pszTmpFilename = NULL;
+    VSILFILE* fp = NULL;
+
+    if (map == NULL)
+        return;
+
+    pszGEO_ENCODING = msGetOutputFormatOption(img->format, "GEO_ENCODING", NULL);
+    if (pszGEO_ENCODING == NULL)
+        return;
+
+    msGDALInitialize();
+
+    hPDFDriver = GDALGetDriverByName("PDF");
+    if (hPDFDriver == NULL)
+        return;
+
+    /* When compiled against libpoppler, the PDF driver is VirtualIO capable */
+    /* but not, when it is compiled against libpodofo. */
+    pszVirtualIO = GDALGetMetadataItem( hPDFDriver, GDAL_DCAP_VIRTUALIO, NULL );
+    if (pszVirtualIO)
+        bVirtualIO = CSLTestBoolean(pszVirtualIO);
+
+    if (bVirtualIO)
+        pszTmpFilename = msTmpFile(map, NULL, "/vsimem/mscairopdf/", "pdf");
+    else
+        pszTmpFilename = msTmpFile(map, map->mappath, NULL, "pdf");
+
+    /* Copy content of outputStream buffer into file */
+    fp = VSIFOpenL(pszTmpFilename, "wb");
+    if (fp == NULL)
+    {
+        msFree(pszTmpFilename);
+        return;
+    }
+    VSIFWriteL(r->outputStream->data, 1, r->outputStream->size, fp);
+    VSIFCloseL(fp);
+    fp = NULL;
+
+    hDS = GDALOpen(pszTmpFilename, GA_Update);
+    if ( hDS != NULL )
+    {
+        char* pszWKT = msProjectionObj2OGCWKT( &(map->projection) );
+        if( pszWKT != NULL )
+        {
+            double adfGeoTransform[6];
+            int i;
+
+            /* Add user-specified options */
+            for( i = 0; i < img->format->numformatoptions; i++ )
+            {
+                const char* pszOption = img->format->formatoptions[i];
+                if( strncasecmp(pszOption,"METADATA_ITEM:",14) == 0 )
+                {
+                    char* pszKey = NULL;
+                    const char* pszValue = CPLParseNameValue(pszOption + 14,
+                                                                &pszKey);
+                    if( pszKey != NULL )
+                    {
+                        GDALSetMetadataItem(hDS, pszKey, pszValue, NULL);
+                        CPLFree(pszKey);
+                    }
+                }
+            }
+
+            /* We need to rescale the geotransform because GDAL will not necessary */
+            /* open the PDF with the DPI that was used to generate it */
+            memcpy(adfGeoTransform, map->gt.geotransform, 6 * sizeof(double));
+            adfGeoTransform[1] = adfGeoTransform[1] * map->width / GDALGetRasterXSize(hDS);
+            adfGeoTransform[5] = adfGeoTransform[5] * map->height / GDALGetRasterYSize(hDS);
+            GDALSetGeoTransform(hDS, adfGeoTransform);
+            GDALSetProjection(hDS, pszWKT);
+
+            msFree( pszWKT );
+            pszWKT = NULL;
+
+            CPLSetThreadLocalConfigOption("GDAL_PDF_GEO_ENCODING", pszGEO_ENCODING);
+
+            GDALClose(hDS);
+            hDS = NULL;
+
+            CPLSetThreadLocalConfigOption("GDAL_PDF_GEO_ENCODING", NULL);
+
+            /* We need to replace the buffer with the content of the GDAL file */
+            fp = VSIFOpenL(pszTmpFilename, "rb");
+            if( fp != NULL )
+            {
+                int nFileSize;
+
+                VSIFSeekL(fp, 0, SEEK_END);
+                nFileSize = (int)VSIFTellL(fp);
+
+                msBufferResize(r->outputStream, nFileSize);
+
+                VSIFSeekL(fp, 0, SEEK_SET);
+                VSIFReadL(r->outputStream->data, 1, nFileSize, fp);
+
+                r->outputStream->size = nFileSize;
+
+                VSIFCloseL(fp);
+                fp = NULL;
+            }
+        }
+    }
+
+    if ( hDS != NULL )
+        GDALClose(hDS);
+
+    VSIUnlink(pszTmpFilename);
+
+    msFree(pszTmpFilename);
+#endif
+}
+
+int saveImageCairo(imageObj *img, mapObj *map, FILE *fp, outputFormatObj *format) {
     cairo_renderer *r = CAIRO_RENDERER(img);
     if(!strcasecmp(img->format->driver,"cairo/pdf") || !strcasecmp(img->format->driver,"cairo/svg")) {
         cairo_surface_finish (r->surface);
+
+        if (map != NULL && !strcasecmp(img->format->driver,"cairo/pdf"))
+            msTransformToGeospatialPDF(img, map, r);
+
         fwrite(r->outputStream->data,r->outputStream->size,1,fp);
     } else {
         /* not supported */

Modified: trunk/mapserver/mapdummyrenderer.c
===================================================================
--- trunk/mapserver/mapdummyrenderer.c	2012-02-29 18:20:20 UTC (rev 13185)
+++ trunk/mapserver/mapdummyrenderer.c	2012-02-29 20:56:49 UTC (rev 13186)
@@ -159,7 +159,7 @@
     return NULL;
 }
 
-int saveImageDummy(imageObj *img, FILE *fp, outputFormatObj *format) {
+int saveImageDummy(imageObj *img, mapObj *map, FILE *fp, outputFormatObj *format) {
     msSetError(MS_RENDERERERR,"saveImage not implemented","saveImage()");
     return MS_FAILURE;
 }

Modified: trunk/mapserver/mapgd.c
===================================================================
--- trunk/mapserver/mapgd.c	2012-02-29 18:20:20 UTC (rev 13185)
+++ trunk/mapserver/mapgd.c	2012-02-29 20:56:49 UTC (rev 13186)
@@ -88,7 +88,7 @@
 
 
 
-int saveImageGD(imageObj *img, FILE *fp, outputFormatObj *format) 
+int saveImageGD(imageObj *img, mapObj *map, FILE *fp, outputFormatObj *format) 
 {
   gdImagePtr ip;
 

Modified: trunk/mapserver/mapkml.cpp
===================================================================
--- trunk/mapserver/mapkml.cpp	2012-02-29 18:20:20 UTC (rev 13185)
+++ trunk/mapserver/mapkml.cpp	2012-02-29 20:56:49 UTC (rev 13186)
@@ -55,7 +55,7 @@
     return image;
 }
 
-int msSaveImageKml(imageObj *img, FILE *fp, outputFormatObj *format)
+int msSaveImageKml(imageObj *img, mapObj* map, FILE *fp, outputFormatObj *format)
 {
     KmlRenderer* renderer = getKmlRenderer(img);
     return renderer->saveImage(img, fp, format);

Modified: trunk/mapserver/mapogl.cpp
===================================================================
--- trunk/mapserver/mapogl.cpp	2012-02-29 18:20:20 UTC (rev 13185)
+++ trunk/mapserver/mapogl.cpp	2012-02-29 20:56:49 UTC (rev 13186)
@@ -52,7 +52,7 @@
     return (OglRenderer*) img->img.plugin;
 }
 
-int msSaveImageOgl(imageObj *img, FILE *fp, outputFormatObj *format)
+int msSaveImageOgl(imageObj *img, mapObj *map, FILE *fp, outputFormatObj *format)
 {
     rasterBufferObj data;
     OglRenderer* renderer = getOglRenderer(img);

Modified: trunk/mapserver/mapserver.h
===================================================================
--- trunk/mapserver/mapserver.h	2012-02-29 18:20:20 UTC (rev 13185)
+++ trunk/mapserver/mapserver.h	2012-02-29 20:56:49 UTC (rev 13186)
@@ -2753,7 +2753,7 @@
 
 	/* image i/o */
 	imageObj* (*createImage)(int width, int height, outputFormatObj *format, colorObj* bg);
-	int (*saveImage)(imageObj *img, FILE *fp, outputFormatObj *format);
+	int (*saveImage)(imageObj *img, mapObj *map, FILE *fp, outputFormatObj *format);
 	unsigned char* (*saveImageBuffer)(imageObj *img, int *size_ptr, outputFormatObj *format);
 	/*...*/
 

Modified: trunk/mapserver/maputil.c
===================================================================
--- trunk/mapserver/maputil.c	2012-02-29 18:20:20 UTC (rev 13185)
+++ trunk/mapserver/maputil.c	2012-02-29 20:56:49 UTC (rev 13186)
@@ -841,7 +841,7 @@
 
                 nReturnVal = msSaveRasterBuffer(map,&data,stream,img->format );
             } else {
-                nReturnVal = renderer->saveImage(img, stream, img->format);
+                nReturnVal = renderer->saveImage(img, map, stream, img->format);
             }
             if( stream != stdout )
                 fclose(stream);



More information about the mapserver-commits mailing list