[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