Skip to content

Commit 77fa762

Browse files
committed
PDF driver: add 'gdal driver pdf list-layers'
1 parent 88da046 commit 77fa762

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed

Diff for: autotest/gdrivers/pdf.py

+43
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# SPDX-License-Identifier: MIT
1313
###############################################################################
1414

15+
import json
1516
import os
1617
import shutil
1718
import sys
@@ -3097,3 +3098,45 @@ def test_pdf_iso32000_invalid_srs():
30973098

30983099
# Just test that this does not crash
30993100
gdal.Open("data/pdf/invalid_srs.pdf")
3101+
3102+
3103+
###############################################################################
3104+
#
3105+
3106+
3107+
@gdaltest.enable_exceptions()
3108+
@pytest.mark.skipif(not have_read_support(), reason="no read support available")
3109+
def test_pdf_gdal_driver_pdf_list_layer():
3110+
3111+
alg = gdal.GetGlobalAlgorithmRegistry()["driver"]
3112+
assert alg.GetName() == "driver"
3113+
3114+
alg = gdal.GetGlobalAlgorithmRegistry()["driver"]["pdf"]
3115+
assert alg.GetName() == "pdf"
3116+
3117+
alg = gdal.GetGlobalAlgorithmRegistry()["driver"]["pdf"]["list-layers"]
3118+
assert alg.GetName() == "list-layers"
3119+
alg["input"] = "data/pdf/adobe_style_geospatial.pdf"
3120+
assert alg.Run()
3121+
assert json.loads(alg["output-string"]) == [
3122+
"New_Data_Frame",
3123+
"New_Data_Frame.Graticule",
3124+
"Layers",
3125+
"Layers.Measured_Grid",
3126+
"Layers.Graticule",
3127+
]
3128+
3129+
alg = gdal.GetGlobalAlgorithmRegistry()["driver"]["pdf"]["list-layers"]
3130+
alg["input"] = "data/pdf/adobe_style_geospatial.pdf"
3131+
alg["output-format"] = "text"
3132+
assert alg.Run()
3133+
assert (
3134+
alg["output-string"]
3135+
== "New_Data_Frame\nNew_Data_Frame.Graticule\nLayers\nLayers.Measured_Grid\nLayers.Graticule\n"
3136+
)
3137+
3138+
alg = gdal.GetGlobalAlgorithmRegistry()["driver"]["pdf"]["list-layers"]
3139+
assert alg.GetName() == "list-layers"
3140+
alg["input"] = "data/byte.tif"
3141+
with pytest.raises(Exception, match="is not a PDF"):
3142+
alg.Run()

Diff for: frmts/pdf/pdfdataset.cpp

+85
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919

2020
#include "gdal_pdf.h"
2121

22+
#include "cpl_json_streaming_writer.h"
2223
#include "cpl_vsi_virtual.h"
2324
#include "cpl_spawn.h"
2425
#include "cpl_string.h"
2526
#include "gdal_frmts.h"
27+
#include "gdalalgorithm.h"
2628
#include "ogr_spatialref.h"
2729
#include "ogr_geometry.h"
2830

@@ -7711,6 +7713,88 @@ CPLString PDFSanitizeLayerName(const char *pszName)
77117713
return osName;
77127714
}
77137715

7716+
/************************************************************************/
7717+
/* GDALPDFListLayersAlgorithm */
7718+
/************************************************************************/
7719+
7720+
#ifdef HAVE_PDF_READ_SUPPORT
7721+
7722+
class GDALPDFListLayersAlgorithm final : public GDALAlgorithm
7723+
{
7724+
public:
7725+
GDALPDFListLayersAlgorithm()
7726+
: GDALAlgorithm("list-layers",
7727+
std::string("List layers of a PDF dataset"),
7728+
"/drivers/raster/pdf.html")
7729+
{
7730+
AddInputDatasetArg(&m_dataset, GDAL_OF_RASTER | GDAL_OF_VECTOR);
7731+
AddOutputFormatArg(&m_format).SetDefault(m_format).SetChoices("json",
7732+
"text");
7733+
AddOutputStringArg(&m_output);
7734+
}
7735+
7736+
protected:
7737+
bool RunImpl(GDALProgressFunc, void *) override
7738+
{
7739+
auto poDS = dynamic_cast<PDFDataset *>(m_dataset.GetDatasetRef());
7740+
if (!poDS)
7741+
{
7742+
ReportError(CE_Failure, CPLE_AppDefined, "%s is not a PDF",
7743+
m_dataset.GetName().c_str());
7744+
return false;
7745+
}
7746+
if (m_format == "json")
7747+
{
7748+
CPLJSonStreamingWriter oWriter(nullptr, nullptr);
7749+
oWriter.StartArray();
7750+
for (const auto &[key, value] : cpl::IterateNameValue(
7751+
const_cast<CSLConstList>(poDS->GetMetadata("LAYERS"))))
7752+
{
7753+
CPL_IGNORE_RET_VAL(key);
7754+
oWriter.Add(value);
7755+
}
7756+
oWriter.EndArray();
7757+
m_output = oWriter.GetString();
7758+
m_output += '\n';
7759+
}
7760+
else
7761+
{
7762+
for (const auto &[key, value] : cpl::IterateNameValue(
7763+
const_cast<CSLConstList>(poDS->GetMetadata("LAYERS"))))
7764+
{
7765+
CPL_IGNORE_RET_VAL(key);
7766+
m_output += value;
7767+
m_output += '\n';
7768+
}
7769+
}
7770+
return true;
7771+
}
7772+
7773+
private:
7774+
GDALArgDatasetValue m_dataset{};
7775+
std::string m_format = "json";
7776+
std::string m_output{};
7777+
};
7778+
7779+
/************************************************************************/
7780+
/* GDALPDFInstantiateAlgorithm() */
7781+
/************************************************************************/
7782+
7783+
static GDALAlgorithm *
7784+
GDALPDFInstantiateAlgorithm(const std::vector<std::string> &aosPath)
7785+
{
7786+
if (aosPath.size() == 1 && aosPath[0] == "list-layers")
7787+
{
7788+
return std::make_unique<GDALPDFListLayersAlgorithm>().release();
7789+
}
7790+
else
7791+
{
7792+
return nullptr;
7793+
}
7794+
}
7795+
7796+
#endif // HAVE_PDF_READ_SUPPORT
7797+
77147798
/************************************************************************/
77157799
/* GDALRegister_PDF() */
77167800
/************************************************************************/
@@ -7729,6 +7813,7 @@ void GDALRegister_PDF()
77297813

77307814
#ifdef HAVE_PDF_READ_SUPPORT
77317815
poDriver->pfnOpen = PDFDataset::OpenWrapper;
7816+
poDriver->pfnInstantiateAlgorithm = GDALPDFInstantiateAlgorithm;
77327817
#endif // HAVE_PDF_READ_SUPPORT
77337818

77347819
poDriver->pfnCreateCopy = GDALPDFCreateCopy;

Diff for: frmts/pdf/pdfdrivercore.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ void PDFDriverSetCommonMetadata(GDALDriver *poDriver)
234234
poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES");
235235
poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS,
236236
"GeoTransform SRS GCPs DatasetMetadata");
237+
238+
poDriver->DeclareAlgorithm({"list-layers"});
237239
#endif
238240

239241
poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");

0 commit comments

Comments
 (0)