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 "memdataset.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 : int TestCapability(const char *) const 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 : int TestCapability(const char *) const override;
102 : 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 : GDALGeoTransform m_gt{};
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 GuessDPIAndBandCount(GDALPDFDictionary *poPageDict, double &dfPI,
253 : int &nBandsGuessed);
254 : void FindXMP(GDALPDFObject *poObj);
255 : void ParseInfo(GDALPDFObject *poObj);
256 :
257 : CPL_DISALLOW_COPY_ASSIGN(PDFDataset)
258 :
259 : #ifdef HAVE_POPPLER
260 : std::unique_ptr<Object> m_poCatalogObjectPoppler{};
261 : #endif
262 : GDALPDFObject *m_poCatalogObject = nullptr;
263 : GDALPDFObject *GetCatalog();
264 : GDALPDFArray *GetPagesKids();
265 :
266 : #if defined(HAVE_POPPLER) || defined(HAVE_PDFIUM)
267 : void AddLayer(const std::string &osName, int iPage);
268 : void CreateLayerList();
269 : std::string
270 : BuildPostfixedLayerNameAndAddLayer(const std::string &osName,
271 : const std::pair<int, int> &oOCGRef,
272 : int iPageOfInterest, int nPageCount);
273 : #endif
274 :
275 : #if defined(HAVE_POPPLER)
276 : void ExploreLayersPoppler(GDALPDFArray *poArray, int iPageOfInterest,
277 : int nPageCount, CPLString osTopLayer,
278 : int nRecLevel, int &nVisited, bool &bStop);
279 : void FindLayersPoppler(int iPageOfInterest);
280 : void TurnLayersOnOffPoppler();
281 : std::vector<std::pair<CPLString, OptionalContentGroup *>>
282 : m_oLayerOCGListPoppler{};
283 : #endif
284 :
285 : #ifdef HAVE_PDFIUM
286 : void ExploreLayersPdfium(GDALPDFArray *poArray, int iPageOfInterest,
287 : int nPageCount, int nRecLevel,
288 : CPLString osTopLayer = "");
289 : void FindLayersPdfium(int iPageOfInterest);
290 : void PDFiumRenderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x,
291 : int start_y, int size_x, int size_y,
292 : const char *pszRenderingOptions);
293 : void TurnLayersOnOffPdfium();
294 :
295 : public:
296 : typedef enum
297 : {
298 : VISIBILITY_DEFAULT,
299 : VISIBILITY_ON,
300 : VISIBILITY_OFF
301 : } VisibilityState;
302 :
303 : VisibilityState GetVisibilityStateForOGCPdfium(int nNum, int nGen);
304 :
305 : private:
306 : std::map<CPLString, std::pair<int, int>> m_oMapLayerNameToOCGNumGenPdfium{};
307 : std::map<std::pair<int, int>, VisibilityState>
308 : m_oMapOCGNumGenToVisibilityStatePdfium{};
309 : #endif
310 :
311 : // Map OCGs identified by their (number, generation) to the list of pages
312 : // where they are referenced from.
313 : std::map<std::pair<int, int>, std::vector<int>> m_oMapOCGNumGenToPages{};
314 :
315 : struct LayerStruct
316 : {
317 : std::string osName{};
318 : int nInsertIdx = 0;
319 : int iPage = 0;
320 : };
321 :
322 : std::vector<LayerStruct> m_oLayerNameSet{};
323 : CPLStringList m_aosLayerNames{};
324 :
325 : void SortLayerList();
326 :
327 : struct LayerWithRef
328 : {
329 : CPLString osName{};
330 : GDALPDFObjectNum nOCGNum{};
331 : int nOCGGen = 0;
332 :
333 368 : LayerWithRef(const CPLString &osNameIn,
334 : const GDALPDFObjectNum &nOCGNumIn, int nOCGGenIn)
335 368 : : osName(osNameIn), nOCGNum(nOCGNumIn), nOCGGen(nOCGGenIn)
336 : {
337 368 : }
338 : };
339 :
340 : std::vector<LayerWithRef> m_aoLayerWithRef{};
341 :
342 : CPLString FindLayerOCG(GDALPDFDictionary *poPageDict,
343 : const char *pszLayerName);
344 : void FindLayersGeneric(GDALPDFDictionary *poPageDict);
345 :
346 : void MapOCGsToPages();
347 :
348 : bool m_bUseOCG = false;
349 :
350 : static const char *GetOption(char **papszOpenOptions,
351 : const char *pszOptionName,
352 : const char *pszDefaultVal);
353 :
354 : bool m_bHasLoadedLayers = false;
355 : std::vector<std::unique_ptr<OGRPDFLayer>> m_apoLayers{};
356 :
357 : double m_dfPageWidth = 0;
358 : double m_dfPageHeight = 0;
359 : void PDFCoordsToSRSCoords(double x, double y, double &X, double &Y);
360 :
361 : std::map<int, std::unique_ptr<OGRGeometry>> m_oMapMCID{};
362 : void CleanupIntermediateResources();
363 :
364 : std::map<CPLString, int> m_oMapOperators{};
365 : void InitMapOperators();
366 :
367 : bool m_bSetStyle = false;
368 :
369 : bool ExploreTree(GDALPDFObject *poObj,
370 : std::set<std::pair<int, int>> &aoSetAlreadyVisited,
371 : int nRecLevel, bool bDryRun);
372 : void ExploreContents(GDALPDFObject *poObj, GDALPDFObject *poResources,
373 : int nDepth, int &nVisited, bool &bStop);
374 :
375 : void ExploreContentsNonStructuredInternal(
376 : GDALPDFObject *poContents, GDALPDFObject *poResources,
377 : const std::map<CPLString, OGRPDFLayer *> &oMapPropertyToLayer,
378 : const std::map<std::pair<int, int>, OGRPDFLayer *> &oMapNumGenToLayer,
379 : OGRPDFLayer *poSingleLayer);
380 : void ExploreContentsNonStructured(GDALPDFObject *poObj,
381 : GDALPDFObject *poResources);
382 :
383 : int UnstackTokens(const char *pszToken, int nRequiredArgs,
384 : char aszTokenStack[TOKEN_STACK_SIZE][MAX_TOKEN_SIZE],
385 : int &nTokenStackSize, double *adfCoords);
386 :
387 : struct GraphicState
388 : {
389 : std::array<double, 6> adfCM = {1, 0, 0, 1, 0, 0};
390 : std::array<double, 3> adfStrokeColor = {0.0, 0.0, 0.0};
391 : std::array<double, 3> adfFillColor = {1.0, 1.0, 1.0};
392 :
393 : void PreMultiplyBy(double adfMatrix[6]);
394 : void ApplyMatrix(double adfCoords[2]) const;
395 : };
396 :
397 : OGRGeometry *ParseContent(
398 : const char *pszContent, GDALPDFObject *poResources,
399 : bool bCollectAllObjects, bool bInitBDCStack, bool bMatchQ,
400 : const std::map<CPLString, OGRPDFLayer *> &oMapPropertyToLayer,
401 : const std::map<std::pair<int, int>, OGRPDFLayer *> &oMapNumGenToLayer,
402 : const GraphicState &graphicStateIn, OGRPDFLayer *poCurLayer,
403 : int nRecLevel);
404 : std::unique_ptr<OGRGeometry> BuildGeometry(std::vector<double> &oCoords,
405 : int bHasFoundFill,
406 : int bHasMultiPart);
407 :
408 : bool OpenVectorLayers(GDALPDFDictionary *poPageDict);
409 :
410 : void InitOverviews();
411 :
412 : public:
413 : PDFDataset(PDFDataset *poParentDS = nullptr, int nXSize = 0,
414 : int nYSize = 0);
415 : ~PDFDataset() override;
416 :
417 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
418 :
419 : CPLErr SetGeoTransform(const GDALGeoTransform >) override;
420 :
421 : const OGRSpatialReference *GetSpatialRef() const override;
422 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
423 :
424 : char **GetMetadataDomainList() override;
425 : CSLConstList GetMetadata(const char *pszDomain = "") override;
426 : CPLErr SetMetadata(CSLConstList papszMetadata,
427 : const char *pszDomain = "") override;
428 : virtual const char *GetMetadataItem(const char *pszName,
429 : const char *pszDomain = "") override;
430 : CPLErr SetMetadataItem(const char *pszName, const char *pszValue,
431 : const char *pszDomain = "") override;
432 :
433 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
434 : GDALDataType, int, BANDMAP_TYPE, GSpacing nPixelSpace,
435 : GSpacing nLineSpace, GSpacing nBandSpace,
436 : GDALRasterIOExtraArg *psExtraArg) override;
437 :
438 : int GetGCPCount() override;
439 : const OGRSpatialReference *GetGCPSpatialRef() const override;
440 : const GDAL_GCP *GetGCPs() override;
441 : CPLErr SetGCPs(int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
442 : const OGRSpatialReference *poSRS) override;
443 :
444 : CPLErr ReadPixels(int nReqXOff, int nReqYOff, int nReqXSize, int nReqYSize,
445 : GSpacing nPixelSpace, GSpacing nLineSpace,
446 : GSpacing nBandSpace, GByte *pabyData);
447 :
448 : int GetLayerCount() const override;
449 : const OGRLayer *GetLayer(int) const override;
450 :
451 : int TestCapability(const char *) const override;
452 :
453 : OGRGeometry *GetGeometryFromMCID(int nMCID);
454 :
455 4 : GDALPDFObject *GetPageObj()
456 : {
457 4 : return m_poPageObj;
458 : }
459 :
460 4 : double GetPageWidth() const
461 : {
462 4 : return m_dfPageWidth;
463 : }
464 :
465 4 : double GetPageHeight() const
466 : {
467 4 : return m_dfPageHeight;
468 : }
469 :
470 : static PDFDataset *Open(GDALOpenInfo *);
471 :
472 174 : static GDALDataset *OpenWrapper(GDALOpenInfo *poOpenInfo)
473 : {
474 174 : return Open(poOpenInfo);
475 : }
476 :
477 : CPLErr IBuildOverviews(const char *, int, const int *, int, const int *,
478 : GDALProgressFunc, void *,
479 : CSLConstList papszOptions) override;
480 :
481 : #ifdef HAVE_PDFIUM
482 : static bool g_bPdfiumInit;
483 : #endif
484 : };
485 :
486 : /************************************************************************/
487 : /* ==================================================================== */
488 : /* PDFRasterBand */
489 : /* ==================================================================== */
490 : /************************************************************************/
491 :
492 : class PDFRasterBand CPL_NON_FINAL : public GDALPamRasterBand
493 : {
494 : friend class PDFDataset;
495 :
496 : int nResolutionLevel;
497 :
498 : CPLErr IReadBlockFromTile(int, int, void *);
499 :
500 : void SetSize(int nXSize, int nYSize);
501 :
502 : public:
503 : PDFRasterBand(PDFDataset *, int, int);
504 : ~PDFRasterBand() override;
505 :
506 : virtual GDALSuggestedBlockAccessPattern
507 : GetSuggestedBlockAccessPattern() const override;
508 :
509 : int GetOverviewCount() override;
510 : GDALRasterBand *GetOverview(int) override;
511 :
512 : CPLErr IReadBlock(int, int, void *) override;
513 : GDALColorInterp GetColorInterpretation() override;
514 :
515 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
516 : GDALDataType, GSpacing nPixelSpace, GSpacing nLineSpace,
517 : GDALRasterIOExtraArg *psExtraArg) override;
518 : };
519 :
520 : #endif /* HAVE_PDF_READ_SUPPORT */
521 :
522 : /************************************************************************/
523 : /* PDFWritableDataset */
524 : /************************************************************************/
525 :
526 : class PDFWritableVectorDataset final : public GDALDataset
527 : {
528 : char **papszOptions;
529 :
530 : int nLayers;
531 : OGRLayer **papoLayers;
532 :
533 : int bModified;
534 :
535 : CPL_DISALLOW_COPY_ASSIGN(PDFWritableVectorDataset)
536 :
537 : public:
538 : PDFWritableVectorDataset();
539 : ~PDFWritableVectorDataset() override;
540 :
541 0 : bool CanReopenWithCurrentDescription() const override
542 : {
543 : #ifdef HAVE_PDF_READ_SUPPORT
544 0 : return true;
545 : #else
546 : return false;
547 : #endif
548 : }
549 :
550 : virtual OGRLayer *ICreateLayer(const char *pszName,
551 : const OGRGeomFieldDefn *poGeomFieldDefn,
552 : CSLConstList papszOptions) override;
553 :
554 : CPLErr Close(GDALProgressFunc = nullptr, void * = nullptr) override;
555 : CPLErr FlushCache(bool bAtClosing) override;
556 :
557 : int GetLayerCount() const override;
558 : const OGRLayer *GetLayer(int) const override;
559 :
560 : int TestCapability(const char *) const override;
561 :
562 : static GDALDataset *Create(const char *pszName, int nXSize, int nYSize,
563 : int nBands, GDALDataType eType,
564 : CSLConstList papszOptions);
565 :
566 141 : void SetModified()
567 : {
568 141 : bModified = TRUE;
569 141 : }
570 : };
571 :
572 : GDALDataset *GDALPDFOpen(const char *pszFilename, GDALAccess eAccess);
573 : CPLString PDFSanitizeLayerName(const char *pszName);
574 :
575 : #endif /* ndef GDAL_PDF_H_INCLUDED */
|