Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: PDF driver 5 : * Author: Even Rouault, <even.rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2023, Even Rouault, <even.rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "pdfdrivercore.h" 14 : 15 : static const char *const szOpenOptionList = 16 : "<OpenOptionList>" 17 : #if defined(HAVE_POPPLER) || defined(HAVE_PDFIUM) 18 : " <Option name='RENDERING_OPTIONS' type='string-select' " 19 : "description='Which graphical elements to render' " 20 : "default='RASTER,VECTOR,TEXT' " 21 : "alt_config_option='GDAL_PDF_RENDERING_OPTIONS'>" 22 : " <Value>RASTER,VECTOR,TEXT</Value>\n" 23 : " <Value>RASTER,VECTOR</Value>\n" 24 : " <Value>RASTER,TEXT</Value>\n" 25 : " <Value>RASTER</Value>\n" 26 : " <Value>VECTOR,TEXT</Value>\n" 27 : " <Value>VECTOR</Value>\n" 28 : " <Value>TEXT</Value>\n" 29 : " </Option>" 30 : #endif 31 : " <Option name='DPI' type='float' description='Resolution in Dot Per " 32 : "Inch' default='72' alt_config_option='GDAL_PDF_DPI'/>" 33 : " <Option name='USER_PWD' type='string' description='Password' " 34 : "alt_config_option='PDF_USER_PWD'/>" 35 : #ifdef HAVE_MULTIPLE_PDF_BACKENDS 36 : " <Option name='PDF_LIB' type='string-select' description='Which " 37 : "underlying PDF library to use' " 38 : #if defined(HAVE_PDFIUM) 39 : "default='PDFIUM'" 40 : #elif defined(HAVE_POPPLER) 41 : "default='POPPLER'" 42 : #elif defined(HAVE_PODOFO) 43 : "default='PODOFO'" 44 : #endif // ~ default PDF_LIB 45 : " alt_config_option='GDAL_PDF_LIB'>" 46 : #if defined(HAVE_POPPLER) 47 : " <Value>POPPLER</Value>\n" 48 : #endif // HAVE_POPPLER 49 : #if defined(HAVE_PODOFO) 50 : " <Value>PODOFO</Value>\n" 51 : #endif // HAVE_PODOFO 52 : #if defined(HAVE_PDFIUM) 53 : " <Value>PDFIUM</Value>\n" 54 : #endif // HAVE_PDFIUM 55 : " </Option>" 56 : #endif // HAVE_MULTIPLE_PDF_BACKENDS 57 : " <Option name='LAYERS' type='string' description='List of layers (comma " 58 : "separated) to turn ON (or ALL to turn all layers ON)' " 59 : "alt_config_option='GDAL_PDF_LAYERS'/>" 60 : " <Option name='LAYERS_OFF' type='string' description='List of layers " 61 : "(comma separated) to turn OFF' alt_config_option='GDAL_PDF_LAYERS_OFF'/>" 62 : " <Option name='BANDS' type='string-select' description='Number of raster " 63 : "bands' default='3' alt_config_option='GDAL_PDF_BANDS'>" 64 : " <Value>3</Value>\n" 65 : " <Value>4</Value>\n" 66 : " </Option>" 67 : " <Option name='NEATLINE' type='string' description='The name of the " 68 : "neatline to select' alt_config_option='GDAL_PDF_NEATLINE'/>" 69 : "</OpenOptionList>"; 70 : 71 2687 : const char *PDFGetOpenOptionList() 72 : { 73 2687 : return szOpenOptionList; 74 : } 75 : 76 : /************************************************************************/ 77 : /* PDFDatasetIdentify() */ 78 : /************************************************************************/ 79 : 80 63077 : int PDFDatasetIdentify(GDALOpenInfo *poOpenInfo) 81 : { 82 63077 : if (STARTS_WITH(poOpenInfo->pszFilename, "PDF:")) 83 60 : return TRUE; 84 63017 : if (STARTS_WITH(poOpenInfo->pszFilename, "PDF_IMAGE:")) 85 0 : return TRUE; 86 : 87 63017 : if (poOpenInfo->nHeaderBytes < 128) 88 52903 : return FALSE; 89 : 90 10114 : return memcmp(poOpenInfo->pabyHeader, "%PDF", 4) == 0; 91 : } 92 : 93 : /************************************************************************/ 94 : /* PDFDriverSetCommonMetadata() */ 95 : /************************************************************************/ 96 : 97 1309 : void PDFDriverSetCommonMetadata(GDALDriver *poDriver) 98 : { 99 1309 : poDriver->SetDescription(DRIVER_NAME); 100 1309 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 101 1309 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 102 1309 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); 103 1309 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Geospatial PDF"); 104 1309 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/pdf.html"); 105 1309 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "pdf"); 106 1309 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte"); 107 1309 : poDriver->SetMetadataItem( 108 : GDAL_DMD_CREATIONFIELDDATATYPES, 109 1309 : "Integer Integer64 Real String Date DateTime Time"); 110 : 111 : #if defined(HAVE_POPPLER) || defined(HAVE_PDFIUM) 112 1309 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 113 : #endif 114 : 115 1309 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES, "YES"); 116 1309 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES_READ, "YES"); 117 1309 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES"); 118 1309 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 119 : 120 : #ifdef HAVE_POPPLER 121 1309 : poDriver->SetMetadataItem("HAVE_POPPLER", "YES"); 122 : #endif // HAVE_POPPLER 123 : #ifdef HAVE_PODOFO 124 : poDriver->SetMetadataItem("HAVE_PODOFO", "YES"); 125 : #endif // HAVE_PODOFO 126 : #ifdef HAVE_PDFIUM 127 1309 : poDriver->SetMetadataItem("HAVE_PDFIUM", "YES"); 128 : #endif // HAVE_PDFIUM 129 : 130 1309 : poDriver->SetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST, 131 1309 : "<LayerCreationOptionList/>"); 132 : 133 1309 : poDriver->SetMetadataItem( 134 : GDAL_DMD_CREATIONOPTIONLIST, 135 : "<CreationOptionList>\n" 136 : " <Option name='COMPRESS' type='string-select' " 137 : "description='Compression method for raster data' default='DEFLATE'>\n" 138 : " <Value>NONE</Value>\n" 139 : " <Value>DEFLATE</Value>\n" 140 : " <Value>JPEG</Value>\n" 141 : " <Value>JPEG2000</Value>\n" 142 : " </Option>\n" 143 : " <Option name='STREAM_COMPRESS' type='string-select' " 144 : "description='Compression method for stream objects' " 145 : "default='DEFLATE'>\n" 146 : " <Value>NONE</Value>\n" 147 : " <Value>DEFLATE</Value>\n" 148 : " </Option>\n" 149 : " <Option name='GEO_ENCODING' type='string-select' " 150 : "description='Format of geo-encoding' default='ISO32000'>\n" 151 : " <Value>NONE</Value>\n" 152 : " <Value>ISO32000</Value>\n" 153 : " <Value>OGC_BP</Value>\n" 154 : " <Value>BOTH</Value>\n" 155 : " </Option>\n" 156 : " <Option name='NEATLINE' type='string' description='Neatline'/>\n" 157 : " <Option name='DPI' type='float' description='DPI' default='72'/>\n" 158 : " <Option name='WRITE_USERUNIT' type='boolean' description='Whether " 159 : "the UserUnit parameter must be written'/>\n" 160 : " <Option name='PREDICTOR' type='int' description='Predictor Type " 161 : "(for DEFLATE compression)'/>\n" 162 : " <Option name='JPEG_QUALITY' type='int' description='JPEG quality " 163 : "1-100' default='75'/>\n" 164 : " <Option name='JPEG2000_DRIVER' type='string'/>\n" 165 : " <Option name='TILED' type='boolean' description='Switch to tiled " 166 : "format' default='NO'/>\n" 167 : " <Option name='BLOCKXSIZE' type='int' description='Block Width'/>\n" 168 : " <Option name='BLOCKYSIZE' type='int' description='Block Height'/>\n" 169 : " <Option name='LAYER_NAME' type='string' description='Layer name " 170 : "for raster content'/>\n" 171 : " <Option name='CLIPPING_EXTENT' type='string' description='Clipping " 172 : "extent for main and extra rasters. Format: xmin,ymin,xmax,ymax'/>\n" 173 : " <Option name='EXTRA_RASTERS' type='string' description='List of " 174 : "extra (georeferenced) rasters.'/>\n" 175 : " <Option name='EXTRA_RASTERS_LAYER_NAME' type='string' " 176 : "description='List of layer names for the extra (georeferenced) " 177 : "rasters.'/>\n" 178 : " <Option name='EXTRA_STREAM' type='string' description='Extra data " 179 : "to insert into the page content stream'/>\n" 180 : " <Option name='EXTRA_IMAGES' type='string' description='List of " 181 : "image_file_name,x,y,scale[,link=some_url] (possibly repeated)'/>\n" 182 : " <Option name='EXTRA_LAYER_NAME' type='string' description='Layer " 183 : "name for extra content'/>\n" 184 : " <Option name='MARGIN' type='int' description='Margin around image " 185 : "in user units'/>\n" 186 : " <Option name='LEFT_MARGIN' type='int' description='Left margin in " 187 : "user units'/>\n" 188 : " <Option name='RIGHT_MARGIN' type='int' description='Right margin " 189 : "in user units'/>\n" 190 : " <Option name='TOP_MARGIN' type='int' description='Top margin in " 191 : "user units'/>\n" 192 : " <Option name='BOTTOM_MARGIN' type='int' description='Bottom margin " 193 : "in user units'/>\n" 194 : " <Option name='OGR_DATASOURCE' type='string' description='Name of " 195 : "OGR datasource to display on top of the raster layer'/>\n" 196 : " <Option name='OGR_DISPLAY_FIELD' type='string' description='Name " 197 : "of field to use as the display field in the feature tree'/>\n" 198 : " <Option name='OGR_DISPLAY_LAYER_NAMES' type='string' " 199 : "description='Comma separated list of OGR layer names to display in " 200 : "the feature tree'/>\n" 201 : " <Option name='OGR_WRITE_ATTRIBUTES' type='boolean' " 202 : "description='Whether to write attributes of OGR features' " 203 : "default='YES'/>\n" 204 : " <Option name='OGR_LINK_FIELD' type='string' description='Name of " 205 : "field to use as the URL field to make objects clickable.'/>\n" 206 : " <Option name='XMP' type='string' description='xml:XMP metadata'/>\n" 207 : " <Option name='WRITE_INFO' type='boolean' description='to control " 208 : "whether a Info block must be written' default='YES'/>\n" 209 : " <Option name='AUTHOR' type='string'/>\n" 210 : " <Option name='CREATOR' type='string'/>\n" 211 : " <Option name='CREATION_DATE' type='string'/>\n" 212 : " <Option name='KEYWORDS' type='string'/>\n" 213 : " <Option name='PRODUCER' type='string'/>\n" 214 : " <Option name='SUBJECT' type='string'/>\n" 215 : " <Option name='TITLE' type='string'/>\n" 216 : " <Option name='OFF_LAYERS' type='string' description='Comma " 217 : "separated list of layer names that should be initially hidden'/>\n" 218 : " <Option name='EXCLUSIVE_LAYERS' type='string' description='Comma " 219 : "separated list of layer names, such that only one of those layers can " 220 : "be ON at a time.'/>\n" 221 : " <Option name='JAVASCRIPT' type='string' description='Javascript " 222 : "script to embed and run at file opening'/>\n" 223 : " <Option name='JAVASCRIPT_FILE' type='string' description='Filename " 224 : "of the Javascript script to embed and run at file opening'/>\n" 225 : " <Option name='COMPOSITION_FILE' type='string' description='XML " 226 : "file describing how the PDF should be composed'/>\n" 227 1309 : "</CreationOptionList>\n"); 228 : 229 : #ifdef HAVE_PDF_READ_SUPPORT 230 1309 : poDriver->SetMetadataItem(GDAL_DMD_OPENOPTIONLIST, szOpenOptionList); 231 1309 : poDriver->pfnIdentify = PDFDatasetIdentify; 232 1309 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 233 1309 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES"); 234 1309 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES"); 235 : #endif 236 : 237 1309 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES"); 238 1309 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES"); 239 1309 : } 240 : 241 : /************************************************************************/ 242 : /* DeclareDeferredPDFPlugin() */ 243 : /************************************************************************/ 244 : 245 : #ifdef PLUGIN_FILENAME 246 1595 : void DeclareDeferredPDFPlugin() 247 : { 248 1595 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 249 : { 250 302 : return; 251 : } 252 1293 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); 253 : #ifdef PLUGIN_INSTALLATION_MESSAGE 254 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, 255 : PLUGIN_INSTALLATION_MESSAGE); 256 : #endif 257 1293 : PDFDriverSetCommonMetadata(poDriver); 258 1293 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 259 : } 260 : #endif