Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: PDF Translator
4 : * Purpose: Definition of classes for OGR .pdf driver.
5 : * Author: Even Rouault, even dot rouault at spatialys.com
6 : *
7 : ******************************************************************************
8 : *
9 : * Support for open-source PDFium library
10 : *
11 : * Copyright (C) 2015 Klokan Technologies GmbH (http://www.klokantech.com/)
12 : * Author: Martin Mikita <martin.mikita@klokantech.com>, xmikit00 @ FIT VUT Brno
13 : *
14 : ******************************************************************************
15 : * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys.com>
16 : *
17 : * SPDX-License-Identifier: MIT
18 : ****************************************************************************/
19 :
20 : #ifndef GDAL_PDF_H_INCLUDED
21 : #define GDAL_PDF_H_INCLUDED
22 :
23 : /* hack for PDF driver and poppler >= 0.15.0 that defines incompatible "typedef
24 : * bool GBool" */
25 : /* in include/poppler/goo/gtypes.h with the one defined in cpl_port.h */
26 : #define CPL_GBOOL_DEFINED
27 : #define OGR_FEATURESTYLE_INCLUDE
28 : #include "cpl_port.h"
29 :
30 : #include <array>
31 : #include <map>
32 : #include <set>
33 : #include <stack>
34 : #include <utility>
35 : #include <bitset> // For detecting usage of PDF library
36 : #include <algorithm>
37 :
38 : #include "pdfsdk_headers_all.h"
39 :
40 : #include "pdfdrivercore.h"
41 :
42 : #include "cpl_vsi_virtual.h"
43 :
44 : #include "gdal_pam.h"
45 : #include "ogrsf_frmts.h"
46 :
47 : #include "ogr_mem.h"
48 : #include "pdfobject.h"
49 :
50 : #define PDFLIB_POPPLER 0
51 : #define PDFLIB_PODOFO 1
52 : #define PDFLIB_PDFIUM 2
53 : #define PDFLIB_COUNT 3
54 :
55 : /************************************************************************/
56 : /* OGRPDFLayer */
57 : /************************************************************************/
58 :
59 : #ifdef HAVE_PDF_READ_SUPPORT
60 :
61 : class PDFDataset;
62 :
63 : class OGRPDFLayer final : public OGRMemLayer
64 : {
65 : PDFDataset *poDS;
66 : int bGeomTypeSet;
67 : int bGeomTypeMixed;
68 :
69 : CPL_DISALLOW_COPY_ASSIGN(OGRPDFLayer)
70 :
71 : public:
72 : OGRPDFLayer(PDFDataset *poDS, const char *pszName,
73 : OGRSpatialReference *poSRS, OGRwkbGeometryType eGeomType);
74 :
75 : void Fill(GDALPDFArray *poArray);
76 :
77 : virtual int TestCapability(const char *) override;
78 :
79 : GDALDataset *GetDataset() override;
80 : };
81 :
82 : #endif
83 :
84 : /************************************************************************/
85 : /* OGRPDFWritableLayer */
86 : /************************************************************************/
87 :
88 : class PDFWritableVectorDataset;
89 :
90 : class OGRPDFWritableLayer final : public OGRMemLayer
91 : {
92 : PDFWritableVectorDataset *poDS;
93 :
94 : CPL_DISALLOW_COPY_ASSIGN(OGRPDFWritableLayer)
95 :
96 : public:
97 : OGRPDFWritableLayer(PDFWritableVectorDataset *poDS, const char *pszName,
98 : OGRSpatialReference *poSRS,
99 : OGRwkbGeometryType eGeomType);
100 :
101 : virtual int TestCapability(const char *) override;
102 : virtual OGRErr ICreateFeature(OGRFeature *poFeature) override;
103 :
104 : GDALDataset *GetDataset() override;
105 : };
106 :
107 : /************************************************************************/
108 : /* GDALPDFTileDesc */
109 : /************************************************************************/
110 :
111 : typedef struct
112 : {
113 : GDALPDFObject *poImage;
114 : double adfCM[6];
115 : double dfWidth;
116 : double dfHeight;
117 : int nBands;
118 : } GDALPDFTileDesc;
119 :
120 : #ifdef HAVE_PDFIUM
121 : /**
122 : * Structures for Document and Document's Page for PDFium library,
123 : * which does not support multi-threading.
124 : * Structures keeps objects for PDFium library and exclusive mutex locks
125 : * for one-per-time access of PDFium library methods with multi-threading GDAL
126 : * Structures also keeps only one object per each opened PDF document
127 : * - this saves time for opening and memory for opened objects
128 : * Document is closed after closing all pages object.
129 : */
130 :
131 : /************************************************************************/
132 : /* TPdfiumPageStruct */
133 : /************************************************************************/
134 :
135 : // Map of Pdfium pages in following structure
136 : typedef struct
137 : {
138 : int pageNum;
139 : CPDF_Page *page;
140 : CPLMutex *readMutex;
141 : int sharedNum;
142 : } TPdfiumPageStruct;
143 :
144 : typedef std::map<int, TPdfiumPageStruct *> TMapPdfiumPages;
145 :
146 : /************************************************************************/
147 : /* TPdfiumDocumentStruct */
148 : /************************************************************************/
149 :
150 : // Structure for Mutex on File
151 : struct TPdfiumDocumentStruct
152 : {
153 : char *filename = nullptr;
154 : CPDF_Document *doc = nullptr;
155 : TMapPdfiumPages pages{};
156 : FPDF_FILEACCESS *psFileAccess = nullptr;
157 : };
158 :
159 : #endif // ~ HAVE_PDFIUM
160 :
161 : /************************************************************************/
162 : /* ==================================================================== */
163 : /* PDFDataset */
164 : /* ==================================================================== */
165 : /************************************************************************/
166 :
167 : class PDFRasterBand;
168 : class PDFImageRasterBand;
169 :
170 : #ifdef HAVE_POPPLER
171 : class ObjectAutoFree;
172 : #endif
173 :
174 : #define MAX_TOKEN_SIZE 256
175 : #define TOKEN_STACK_SIZE 8
176 :
177 : #define GDAL_DEFAULT_DPI 150.0
178 :
179 : #ifdef HAVE_PDF_READ_SUPPORT
180 :
181 : class PDFDataset final : public GDALPamDataset
182 : {
183 : friend class PDFRasterBand;
184 : friend class PDFImageRasterBand;
185 :
186 : VSIVirtualHandleUniquePtr m_fp{};
187 : bool m_bIsOvrDS = false;
188 :
189 : CPLString m_osFilename{};
190 : CPLString m_osUserPwd{};
191 : OGRSpatialReference m_oSRS{};
192 : double m_dfDPI = GDAL_DEFAULT_DPI;
193 : bool m_bHasCTM = false;
194 : std::array<double, 6> m_adfCTM = {{0, 0, 0, 0, 0, 0}};
195 : std::array<double, 6> m_adfGeoTransform = {{0, 1, 0, 0, 0, 1}};
196 : bool m_bGeoTransformValid = false;
197 : int m_nGCPCount = 0;
198 : GDAL_GCP *m_pasGCPList = nullptr;
199 : bool m_bProjDirty = false;
200 : bool m_bNeatLineDirty = false;
201 :
202 : GDALMultiDomainMetadata m_oMDMD_PDF{};
203 : bool m_bInfoDirty = false;
204 : bool m_bXMPDirty = false;
205 :
206 : std::bitset<PDFLIB_COUNT> m_bUseLib{};
207 : #ifdef HAVE_POPPLER
208 : PDFDoc *m_poDocPoppler = nullptr;
209 : #endif
210 : #ifdef HAVE_PODOFO
211 : PoDoFo::PdfMemDocument *m_poDocPodofo = nullptr;
212 : bool m_bPdfToPpmFailed = false;
213 : #endif
214 : #ifdef HAVE_PDFIUM
215 : TPdfiumDocumentStruct *m_poDocPdfium = nullptr;
216 : TPdfiumPageStruct *m_poPagePdfium = nullptr;
217 : #endif
218 : std::vector<std::unique_ptr<PDFDataset>> m_apoOvrDS{};
219 : std::vector<std::unique_ptr<PDFDataset>> m_apoOvrDSBackup{};
220 : GDALPDFObject *m_poPageObj = nullptr;
221 :
222 : int m_iPage = -1;
223 :
224 : GDALPDFObject *m_poImageObj = nullptr;
225 :
226 : double m_dfMaxArea = 0;
227 : int ParseLGIDictObject(GDALPDFObject *poLGIDict);
228 : int ParseLGIDictDictFirstPass(GDALPDFDictionary *poLGIDict,
229 : int *pbIsBestCandidate = nullptr);
230 : int ParseLGIDictDictSecondPass(GDALPDFDictionary *poLGIDict);
231 : int ParseProjDict(GDALPDFDictionary *poProjDict);
232 : int ParseVP(GDALPDFObject *poVP, double dfMediaBoxWidth,
233 : double dfMediaBoxHeight);
234 : int ParseMeasure(GDALPDFObject *poMeasure, double dfMediaBoxWidth,
235 : double dfMediaBoxHeight, double dfULX, double dfULY,
236 : double dfLRX, double dfLRY);
237 :
238 : bool m_bTried = false;
239 : GByte *m_pabyCachedData = nullptr;
240 : int m_nLastBlockXOff = -1;
241 : int m_nLastBlockYOff = -1;
242 : bool m_bCacheBlocksForOtherBands = false;
243 :
244 : OGRPolygon *m_poNeatLine = nullptr;
245 :
246 : std::vector<GDALPDFTileDesc> m_asTiles{}; /* in the order of the PDF file */
247 : std::vector<int> m_aiTiles{}; /* in the order of blocks */
248 : int m_nBlockXSize = 0;
249 : int m_nBlockYSize = 0;
250 : int CheckTiledRaster();
251 :
252 : void GuessDPI(GDALPDFDictionary *poPageDict, int *pnBands);
253 : void FindXMP(GDALPDFObject *poObj);
254 : void ParseInfo(GDALPDFObject *poObj);
255 :
256 : CPL_DISALLOW_COPY_ASSIGN(PDFDataset)
257 :
258 : #ifdef HAVE_POPPLER
259 : std::unique_ptr<Object> m_poCatalogObjectPoppler{};
260 : #endif
261 : GDALPDFObject *m_poCatalogObject = nullptr;
262 : GDALPDFObject *GetCatalog();
263 : GDALPDFArray *GetPagesKids();
264 :
265 : #if defined(HAVE_POPPLER) || defined(HAVE_PDFIUM)
266 : void AddLayer(const std::string &osName, int iPage);
267 : void CreateLayerList();
268 : std::string
269 : BuildPostfixedLayerNameAndAddLayer(const std::string &osName,
270 : const std::pair<int, int> &oOCGRef,
271 : int iPageOfInterest, int nPageCount);
272 : #endif
273 :
274 : #if defined(HAVE_POPPLER)
275 : void ExploreLayersPoppler(GDALPDFArray *poArray, int iPageOfInterest,
276 : int nPageCount, CPLString osTopLayer,
277 : int nRecLevel, int &nVisited, bool &bStop);
278 : void FindLayersPoppler(int iPageOfInterest);
279 : void TurnLayersOnOffPoppler();
280 : std::vector<std::pair<CPLString, OptionalContentGroup *>>
281 : m_oLayerOCGListPoppler{};
282 : #endif
283 :
284 : #ifdef HAVE_PDFIUM
285 : void ExploreLayersPdfium(GDALPDFArray *poArray, int iPageOfInterest,
286 : int nPageCount, int nRecLevel,
287 : CPLString osTopLayer = "");
288 : void FindLayersPdfium(int iPageOfInterest);
289 : void PDFiumRenderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x,
290 : int start_y, int size_x, int size_y,
291 : const char *pszRenderingOptions);
292 : void TurnLayersOnOffPdfium();
293 :
294 : public:
295 : typedef enum
296 : {
297 : VISIBILITY_DEFAULT,
298 : VISIBILITY_ON,
299 : VISIBILITY_OFF
300 : } VisibilityState;
301 :
302 : VisibilityState GetVisibilityStateForOGCPdfium(int nNum, int nGen);
303 :
304 : private:
305 : std::map<CPLString, std::pair<int, int>> m_oMapLayerNameToOCGNumGenPdfium{};
306 : std::map<std::pair<int, int>, VisibilityState>
307 : m_oMapOCGNumGenToVisibilityStatePdfium{};
308 : #endif
309 :
310 : // Map OCGs identified by their (number, generation) to the list of pages
311 : // where they are referenced from.
312 : std::map<std::pair<int, int>, std::vector<int>> m_oMapOCGNumGenToPages{};
313 :
314 : struct LayerStruct
315 : {
316 : std::string osName{};
317 : int nInsertIdx = 0;
318 : int iPage = 0;
319 : };
320 :
321 : std::vector<LayerStruct> m_oLayerNameSet{};
322 : CPLStringList m_aosLayerNames{};
323 :
324 : struct LayerWithRef
325 : {
326 : CPLString osName{};
327 : GDALPDFObjectNum nOCGNum{};
328 : int nOCGGen = 0;
329 :
330 468 : LayerWithRef(const CPLString &osNameIn,
331 : const GDALPDFObjectNum &nOCGNumIn, int nOCGGenIn)
332 468 : : osName(osNameIn), nOCGNum(nOCGNumIn), nOCGGen(nOCGGenIn)
333 : {
334 468 : }
335 : };
336 :
337 : std::vector<LayerWithRef> m_aoLayerWithRef{};
338 :
339 : CPLString FindLayerOCG(GDALPDFDictionary *poPageDict,
340 : const char *pszLayerName);
341 : void FindLayersGeneric(GDALPDFDictionary *poPageDict);
342 :
343 : void MapOCGsToPages();
344 :
345 : bool m_bUseOCG = false;
346 :
347 : static const char *GetOption(char **papszOpenOptions,
348 : const char *pszOptionName,
349 : const char *pszDefaultVal);
350 :
351 : bool m_bHasLoadedLayers = false;
352 : std::vector<std::unique_ptr<OGRPDFLayer>> m_apoLayers{};
353 :
354 : double m_dfPageWidth = 0;
355 : double m_dfPageHeight = 0;
356 : void PDFCoordsToSRSCoords(double x, double y, double &X, double &Y);
357 :
358 : std::map<int, OGRGeometry *> m_oMapMCID{};
359 : void CleanupIntermediateResources();
360 :
361 : std::map<CPLString, int> m_oMapOperators{};
362 : void InitMapOperators();
363 :
364 : bool m_bSetStyle = false;
365 :
366 : bool ExploreTree(GDALPDFObject *poObj,
367 : std::set<std::pair<int, int>> &aoSetAlreadyVisited,
368 : int nRecLevel, bool bDryRun);
369 : void ExploreContents(GDALPDFObject *poObj, GDALPDFObject *poResources,
370 : int nDepth, int &nVisited, bool &bStop);
371 :
372 : void ExploreContentsNonStructuredInternal(
373 : GDALPDFObject *poContents, GDALPDFObject *poResources,
374 : const std::map<CPLString, OGRPDFLayer *> &oMapPropertyToLayer,
375 : const std::map<std::pair<int, int>, OGRPDFLayer *> &oMapNumGenToLayer,
376 : OGRPDFLayer *poSingleLayer);
377 : void ExploreContentsNonStructured(GDALPDFObject *poObj,
378 : GDALPDFObject *poResources);
379 :
380 : int UnstackTokens(const char *pszToken, int nRequiredArgs,
381 : char aszTokenStack[TOKEN_STACK_SIZE][MAX_TOKEN_SIZE],
382 : int &nTokenStackSize, double *adfCoords);
383 :
384 : struct GraphicState
385 : {
386 : std::array<double, 6> adfCM = {1, 0, 0, 1, 0, 0};
387 : std::array<double, 3> adfStrokeColor = {0.0, 0.0, 0.0};
388 : std::array<double, 3> adfFillColor = {1.0, 1.0, 1.0};
389 :
390 : void PreMultiplyBy(double adfMatrix[6]);
391 : void ApplyMatrix(double adfCoords[2]) const;
392 : };
393 :
394 : OGRGeometry *ParseContent(
395 : const char *pszContent, GDALPDFObject *poResources,
396 : bool bCollectAllObjects, bool bInitBDCStack, bool bMatchQ,
397 : const std::map<CPLString, OGRPDFLayer *> &oMapPropertyToLayer,
398 : const std::map<std::pair<int, int>, OGRPDFLayer *> &oMapNumGenToLayer,
399 : const GraphicState &graphicStateIn, OGRPDFLayer *poCurLayer,
400 : int nRecLevel);
401 : OGRGeometry *BuildGeometry(std::vector<double> &oCoords, int bHasFoundFill,
402 : int bHasMultiPart);
403 :
404 : bool OpenVectorLayers(GDALPDFDictionary *poPageDict);
405 :
406 : void InitOverviews();
407 :
408 : public:
409 : PDFDataset(PDFDataset *poParentDS = nullptr, int nXSize = 0,
410 : int nYSize = 0);
411 : virtual ~PDFDataset();
412 :
413 : virtual CPLErr GetGeoTransform(double *) override;
414 :
415 : virtual CPLErr SetGeoTransform(double *padfGeoTransform) override;
416 :
417 : const OGRSpatialReference *GetSpatialRef() const override;
418 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
419 :
420 : virtual char **GetMetadataDomainList() override;
421 : virtual char **GetMetadata(const char *pszDomain = "") override;
422 : virtual CPLErr SetMetadata(char **papszMetadata,
423 : const char *pszDomain = "") override;
424 : virtual const char *GetMetadataItem(const char *pszName,
425 : const char *pszDomain = "") override;
426 : virtual CPLErr SetMetadataItem(const char *pszName, const char *pszValue,
427 : const char *pszDomain = "") override;
428 :
429 : virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
430 : GDALDataType, int, BANDMAP_TYPE,
431 : GSpacing nPixelSpace, GSpacing nLineSpace,
432 : GSpacing nBandSpace,
433 : GDALRasterIOExtraArg *psExtraArg) override;
434 :
435 : virtual int GetGCPCount() override;
436 : const OGRSpatialReference *GetGCPSpatialRef() const override;
437 : virtual const GDAL_GCP *GetGCPs() override;
438 : CPLErr SetGCPs(int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
439 : const OGRSpatialReference *poSRS) override;
440 :
441 : CPLErr ReadPixels(int nReqXOff, int nReqYOff, int nReqXSize, int nReqYSize,
442 : GSpacing nPixelSpace, GSpacing nLineSpace,
443 : GSpacing nBandSpace, GByte *pabyData);
444 :
445 : virtual int GetLayerCount() override;
446 : virtual OGRLayer *GetLayer(int) override;
447 :
448 : virtual int TestCapability(const char *) override;
449 :
450 : OGRGeometry *GetGeometryFromMCID(int nMCID);
451 :
452 8 : GDALPDFObject *GetPageObj()
453 : {
454 8 : return m_poPageObj;
455 : }
456 :
457 8 : double GetPageWidth() const
458 : {
459 8 : return m_dfPageWidth;
460 : }
461 :
462 8 : double GetPageHeight() const
463 : {
464 8 : return m_dfPageHeight;
465 : }
466 :
467 : static PDFDataset *Open(GDALOpenInfo *);
468 :
469 298 : static GDALDataset *OpenWrapper(GDALOpenInfo *poOpenInfo)
470 : {
471 298 : return Open(poOpenInfo);
472 : }
473 :
474 : virtual CPLErr IBuildOverviews(const char *, int, const int *, int,
475 : const int *, GDALProgressFunc, void *,
476 : CSLConstList papszOptions) override;
477 :
478 : #ifdef HAVE_PDFIUM
479 : static bool g_bPdfiumInit;
480 : #endif
481 : };
482 :
483 : /************************************************************************/
484 : /* ==================================================================== */
485 : /* PDFRasterBand */
486 : /* ==================================================================== */
487 : /************************************************************************/
488 :
489 : class PDFRasterBand CPL_NON_FINAL : public GDALPamRasterBand
490 : {
491 : friend class PDFDataset;
492 :
493 : int nResolutionLevel;
494 :
495 : CPLErr IReadBlockFromTile(int, int, void *);
496 :
497 : public:
498 : PDFRasterBand(PDFDataset *, int, int);
499 : virtual ~PDFRasterBand();
500 :
501 : virtual GDALSuggestedBlockAccessPattern
502 : GetSuggestedBlockAccessPattern() const override;
503 :
504 : virtual int GetOverviewCount() override;
505 : virtual GDALRasterBand *GetOverview(int) override;
506 :
507 : virtual CPLErr IReadBlock(int, int, void *) override;
508 : virtual GDALColorInterp GetColorInterpretation() override;
509 :
510 : virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
511 : GDALDataType, GSpacing nPixelSpace,
512 : GSpacing nLineSpace,
513 : GDALRasterIOExtraArg *psExtraArg) override;
514 : };
515 :
516 : #endif /* HAVE_PDF_READ_SUPPORT */
517 :
518 : /************************************************************************/
519 : /* PDFWritableDataset */
520 : /************************************************************************/
521 :
522 : class PDFWritableVectorDataset final : public GDALDataset
523 : {
524 : char **papszOptions;
525 :
526 : int nLayers;
527 : OGRLayer **papoLayers;
528 :
529 : int bModified;
530 :
531 : CPL_DISALLOW_COPY_ASSIGN(PDFWritableVectorDataset)
532 :
533 : public:
534 : PDFWritableVectorDataset();
535 : virtual ~PDFWritableVectorDataset();
536 :
537 : virtual OGRLayer *ICreateLayer(const char *pszName,
538 : const OGRGeomFieldDefn *poGeomFieldDefn,
539 : CSLConstList papszOptions) override;
540 :
541 : virtual OGRErr SyncToDisk();
542 :
543 : virtual int GetLayerCount() override;
544 : virtual OGRLayer *GetLayer(int) override;
545 :
546 : virtual int TestCapability(const char *) override;
547 :
548 : static GDALDataset *Create(const char *pszName, int nXSize, int nYSize,
549 : int nBands, GDALDataType eType,
550 : char **papszOptions);
551 :
552 171 : void SetModified()
553 : {
554 171 : bModified = TRUE;
555 171 : }
556 : };
557 :
558 : GDALDataset *GDALPDFOpen(const char *pszFilename, GDALAccess eAccess);
559 : CPLString PDFSanitizeLayerName(const char *pszName);
560 :
561 : #endif /* ndef GDAL_PDF_H_INCLUDED */
|