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