LCOV - code coverage report
Current view: top level - frmts/pdf - pdfdrivercore.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 48 49 98.0 %
Date: 2025-10-22 13:51:22 Functions: 6 7 85.7 %

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

Generated by: LCOV version 1.14