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