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 2431 : const char *PDFGetOpenOptionList() 72 : { 73 2431 : return szOpenOptionList; 74 : } 75 : 76 : /************************************************************************/ 77 : /* PDFDatasetIdentify() */ 78 : /************************************************************************/ 79 : 80 63971 : int PDFDatasetIdentify(GDALOpenInfo *poOpenInfo) 81 : { 82 63971 : if (STARTS_WITH(poOpenInfo->pszFilename, "PDF:")) 83 60 : return TRUE; 84 63911 : if (STARTS_WITH(poOpenInfo->pszFilename, "PDF_IMAGE:")) 85 0 : return TRUE; 86 : 87 63911 : if (poOpenInfo->nHeaderBytes < 128) 88 53635 : return FALSE; 89 : 90 10276 : return memcmp(poOpenInfo->pabyHeader, "%PDF", 4) == 0; 91 : } 92 : 93 : /************************************************************************/ 94 : /* PDFDriverSetCommonMetadata() */ 95 : /************************************************************************/ 96 : 97 1400 : void PDFDriverSetCommonMetadata(GDALDriver *poDriver) 98 : { 99 1400 : poDriver->SetDescription(DRIVER_NAME); 100 1400 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 101 1400 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 102 1400 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); 103 1400 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Geospatial PDF"); 104 1400 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/pdf.html"); 105 1400 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "pdf"); 106 1400 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte"); 107 1400 : poDriver->SetMetadataItem( 108 : GDAL_DMD_CREATIONFIELDDATATYPES, 109 1400 : "Integer Integer64 Real String Date DateTime Time"); 110 : 111 : #if defined(HAVE_POPPLER) || defined(HAVE_PDFIUM) 112 1400 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 113 : #endif 114 : 115 1400 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES, "YES"); 116 1400 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES_READ, "YES"); 117 1400 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES"); 118 1400 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 119 : 120 : #ifdef HAVE_POPPLER 121 1400 : 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 1400 : poDriver->SetMetadataItem("HAVE_PDFIUM", "YES"); 128 : #endif // HAVE_PDFIUM 129 : 130 1400 : poDriver->SetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST, 131 1400 : "<LayerCreationOptionList/>"); 132 : 133 1400 : 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 : " </Option>\n" 154 : " <Option name='NEATLINE' type='string' description='Neatline'/>\n" 155 : " <Option name='DPI' type='float' description='DPI' default='72'/>\n" 156 : " <Option name='WRITE_USERUNIT' type='boolean' description='Whether " 157 : "the UserUnit parameter must be written'/>\n" 158 : " <Option name='PREDICTOR' type='int' description='Predictor Type " 159 : "(for DEFLATE compression)'/>\n" 160 : " <Option name='JPEG_QUALITY' type='int' description='JPEG quality " 161 : "1-100' default='75'/>\n" 162 : " <Option name='JPEG2000_DRIVER' type='string'/>\n" 163 : " <Option name='TILED' type='boolean' description='Switch to tiled " 164 : "format' default='NO'/>\n" 165 : " <Option name='BLOCKXSIZE' type='int' description='Block Width'/>\n" 166 : " <Option name='BLOCKYSIZE' type='int' description='Block Height'/>\n" 167 : " <Option name='LAYER_NAME' type='string' description='Layer name " 168 : "for raster content'/>\n" 169 : " <Option name='CLIPPING_EXTENT' type='string' description='Clipping " 170 : "extent for main and extra rasters. Format: xmin,ymin,xmax,ymax'/>\n" 171 : " <Option name='EXTRA_RASTERS' type='string' description='List of " 172 : "extra (georeferenced) rasters.'/>\n" 173 : " <Option name='EXTRA_RASTERS_LAYER_NAME' type='string' " 174 : "description='List of layer names for the extra (georeferenced) " 175 : "rasters.'/>\n" 176 : " <Option name='EXTRA_STREAM' type='string' description='Extra data " 177 : "to insert into the page content stream'/>\n" 178 : " <Option name='EXTRA_IMAGES' type='string' description='List of " 179 : "image_file_name,x,y,scale[,link=some_url] (possibly repeated)'/>\n" 180 : " <Option name='EXTRA_LAYER_NAME' type='string' description='Layer " 181 : "name for extra content'/>\n" 182 : " <Option name='MARGIN' type='int' description='Margin around image " 183 : "in user units'/>\n" 184 : " <Option name='LEFT_MARGIN' type='int' description='Left margin in " 185 : "user units'/>\n" 186 : " <Option name='RIGHT_MARGIN' type='int' description='Right margin " 187 : "in user units'/>\n" 188 : " <Option name='TOP_MARGIN' type='int' description='Top margin in " 189 : "user units'/>\n" 190 : " <Option name='BOTTOM_MARGIN' type='int' description='Bottom margin " 191 : "in user units'/>\n" 192 : " <Option name='OGR_DATASOURCE' type='string' description='Name of " 193 : "OGR datasource to display on top of the raster layer'/>\n" 194 : " <Option name='OGR_DISPLAY_FIELD' type='string' description='Name " 195 : "of field to use as the display field in the feature tree'/>\n" 196 : " <Option name='OGR_DISPLAY_LAYER_NAMES' type='string' " 197 : "description='Comma separated list of OGR layer names to display in " 198 : "the feature tree'/>\n" 199 : " <Option name='OGR_WRITE_ATTRIBUTES' type='boolean' " 200 : "description='Whether to write attributes of OGR features' " 201 : "default='YES'/>\n" 202 : " <Option name='OGR_LINK_FIELD' type='string' description='Name of " 203 : "field to use as the URL field to make objects clickable.'/>\n" 204 : " <Option name='XMP' type='string' description='xml:XMP metadata'/>\n" 205 : " <Option name='WRITE_INFO' type='boolean' description='to control " 206 : "whether a Info block must be written' default='YES'/>\n" 207 : " <Option name='AUTHOR' type='string'/>\n" 208 : " <Option name='CREATOR' type='string'/>\n" 209 : " <Option name='CREATION_DATE' type='string'/>\n" 210 : " <Option name='KEYWORDS' type='string'/>\n" 211 : " <Option name='PRODUCER' type='string'/>\n" 212 : " <Option name='SUBJECT' type='string'/>\n" 213 : " <Option name='TITLE' type='string'/>\n" 214 : " <Option name='OFF_LAYERS' type='string' description='Comma " 215 : "separated list of layer names that should be initially hidden'/>\n" 216 : " <Option name='EXCLUSIVE_LAYERS' type='string' description='Comma " 217 : "separated list of layer names, such that only one of those layers can " 218 : "be ON at a time.'/>\n" 219 : " <Option name='JAVASCRIPT' type='string' description='Javascript " 220 : "script to embed and run at file opening'/>\n" 221 : " <Option name='JAVASCRIPT_FILE' type='string' description='Filename " 222 : "of the Javascript script to embed and run at file opening'/>\n" 223 : " <Option name='COMPOSITION_FILE' type='string' description='XML " 224 : "file describing how the PDF should be composed'/>\n" 225 1400 : "</CreationOptionList>\n"); 226 : 227 : #ifdef HAVE_PDF_READ_SUPPORT 228 1400 : poDriver->SetMetadataItem(GDAL_DMD_OPENOPTIONLIST, szOpenOptionList); 229 1400 : poDriver->pfnIdentify = PDFDatasetIdentify; 230 1400 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 231 1400 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES"); 232 1400 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES"); 233 : 234 1400 : poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES"); 235 1400 : poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS, 236 1400 : "GeoTransform SRS GCPs DatasetMetadata"); 237 : #endif 238 : 239 1400 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES"); 240 1400 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES"); 241 1400 : } 242 : 243 : /************************************************************************/ 244 : /* DeclareDeferredPDFPlugin() */ 245 : /************************************************************************/ 246 : 247 : #ifdef PLUGIN_FILENAME 248 1686 : void DeclareDeferredPDFPlugin() 249 : { 250 1686 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 251 : { 252 302 : return; 253 : } 254 1384 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); 255 : #ifdef PLUGIN_INSTALLATION_MESSAGE 256 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, 257 : PLUGIN_INSTALLATION_MESSAGE); 258 : #endif 259 1384 : PDFDriverSetCommonMetadata(poDriver); 260 1384 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 261 : } 262 : #endif