Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: PDF driver
4 : * Purpose: GDALDataset driver for PDF dataset.
5 : * Author: Even Rouault, <even dot rouault at spatialys dot com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2019, Even Rouault <even dot rouault at spatialys dot com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #ifndef PDFCREATEFROMCOMPOSITION_H_INCLUDED
14 : #define PDFCREATEFROMCOMPOSITION_H_INCLUDED
15 :
16 : #include "gdal_pdf.h"
17 : #include "pdfcreatecopy.h"
18 : #include "cpl_minixml.h"
19 : #include "ogrsf_frmts.h"
20 : #include "ogr_geometry.h"
21 :
22 : #include <map>
23 : #include <memory>
24 : #include <vector>
25 :
26 : class GDALPDFComposerWriter final : public GDALPDFBaseWriter
27 : {
28 : CPLString m_osJPEG2000Driver{};
29 :
30 : struct TreeOfOCG
31 : {
32 : GDALPDFObjectNum m_nNum{};
33 : bool m_bInitiallyVisible{true};
34 : std::vector<std::unique_ptr<TreeOfOCG>> m_children{};
35 : };
36 :
37 : bool m_bDisplayLayersOnlyOnVisiblePages = false;
38 : TreeOfOCG m_oTreeOfOGC{};
39 : std::map<CPLString, std::vector<GDALPDFObjectNum>>
40 : m_oMapExclusiveOCGIdToOCGs{};
41 :
42 : std::map<CPLString, GDALPDFObjectNum> m_oMapLayerIdToOCG{};
43 :
44 : struct xyPair
45 : {
46 : double x = 0;
47 : double y = 0;
48 :
49 10 : explicit xyPair(double xin = 0.0, double yin = 0.0) : x(xin), y(yin)
50 : {
51 10 : }
52 : };
53 :
54 : struct Georeferencing
55 : {
56 : CPLString m_osID{};
57 : OGRSpatialReference m_oSRS{};
58 : double m_bboxX1{};
59 : double m_bboxY1{};
60 : double m_bboxX2{};
61 : double m_bboxY2{};
62 : double m_adfGT[6]{0, 1, 0, 0, 0, 1};
63 : };
64 :
65 : std::vector<GDALPDFObjectNum> m_anParentElements{};
66 : std::vector<GDALPDFObjectNum> m_anFeatureLayerId{};
67 : std::map<CPLString, GDALPDFObjectNum> m_oMapPageIdToObjectNum{};
68 :
69 : struct PageContext
70 : {
71 : double m_dfWidthInUserUnit = 0;
72 : double m_dfHeightInUserUnit = 0;
73 : CPLString m_osDrawingStream{};
74 : std::vector<GDALPDFObjectNum> m_anFeatureUserProperties{};
75 : int m_nMCID = 0;
76 : PDFCompressMethod m_eStreamCompressMethod = COMPRESS_DEFLATE;
77 : std::map<CPLString, GDALPDFObjectNum> m_oXObjects{};
78 : std::map<CPLString, GDALPDFObjectNum> m_oProperties{};
79 : std::map<CPLString, GDALPDFObjectNum> m_oExtGState{};
80 : std::vector<GDALPDFObjectNum> m_anAnnotationsId{};
81 : std::map<CPLString, Georeferencing> m_oMapGeoreferencedId{};
82 : };
83 :
84 : bool CreateLayerTree(const CPLXMLNode *psNode,
85 : const GDALPDFObjectNum &nParentId, TreeOfOCG *parent);
86 :
87 12 : struct Action
88 : {
89 : virtual ~Action();
90 : };
91 :
92 14 : struct GotoPageAction final : public Action
93 : {
94 : ~GotoPageAction() override;
95 :
96 : GDALPDFObjectNum m_nPageDestId{};
97 : double m_dfX1 = 0;
98 : double m_dfX2 = 0;
99 : double m_dfY1 = 0;
100 : double m_dfY2 = 0;
101 : };
102 :
103 8 : struct SetLayerStateAction final : public Action
104 : {
105 : ~SetLayerStateAction() override;
106 :
107 : std::set<GDALPDFObjectNum> m_anONLayers{};
108 : std::set<GDALPDFObjectNum> m_anOFFLayers{};
109 : };
110 :
111 2 : struct JavascriptAction final : public Action
112 : {
113 : ~JavascriptAction() override;
114 :
115 : CPLString m_osScript{};
116 : };
117 :
118 : bool ParseActions(const CPLXMLNode *psNode,
119 : std::vector<std::unique_ptr<Action>> &actions);
120 : static GDALPDFDictionaryRW *
121 : SerializeActions(GDALPDFDictionaryRW *poDictForDest,
122 : const std::vector<std::unique_ptr<Action>> &actions);
123 :
124 : struct OutlineItem
125 : {
126 : GDALPDFObjectNum m_nObjId{};
127 : CPLString m_osName{};
128 : bool m_bOpen = true;
129 : int m_nFlags = 0;
130 : std::vector<std::unique_ptr<Action>> m_aoActions{};
131 : std::vector<std::unique_ptr<OutlineItem>> m_aoKids{};
132 : int m_nKidsRecCount = 0;
133 : };
134 :
135 : GDALPDFObjectNum m_nOutlinesId{};
136 :
137 : bool CreateOutlineFirstPass(const CPLXMLNode *psNode,
138 : OutlineItem *poParentItem);
139 : bool SerializeOutlineKids(const OutlineItem *poParentItem);
140 : bool CreateOutline(const CPLXMLNode *psNode);
141 :
142 : void WritePages();
143 :
144 : static GDALPDFArrayRW *CreateOCGOrder(const TreeOfOCG *parent);
145 : static void CollectOffOCG(std::vector<GDALPDFObjectNum> &ar,
146 : const TreeOfOCG *parent);
147 : bool GeneratePage(const CPLXMLNode *psPage);
148 : bool GenerateGeoreferencing(const CPLXMLNode *psGeoreferencing,
149 : double dfWidthInUserUnit,
150 : double dfHeightInUserUnit,
151 : GDALPDFObjectNum &nViewportId,
152 : Georeferencing &georeferencing);
153 :
154 : GDALPDFObjectNum GenerateISO32000_Georeferencing(
155 : OGRSpatialReferenceH hSRS, double bboxX1, double bboxY1, double bboxX2,
156 : double bboxY2, const std::vector<gdal::GCP> &aGCPs,
157 : const std::vector<xyPair> &aBoundingPolygon);
158 :
159 : bool ExploreContent(const CPLXMLNode *psNode, PageContext &oPageContext);
160 : bool WriteRaster(const CPLXMLNode *psNode, PageContext &oPageContext);
161 : bool WriteVector(const CPLXMLNode *psNode, PageContext &oPageContext);
162 : bool WriteVectorLabel(const CPLXMLNode *psNode, PageContext &oPageContext);
163 : void StartBlending(const CPLXMLNode *psNode, PageContext &oPageContext,
164 : double &dfOpacity);
165 : static void EndBlending(const CPLXMLNode *psNode,
166 : PageContext &oPageContext);
167 :
168 : static bool SetupVectorGeoreferencing(
169 : const char *pszGeoreferencingId, OGRLayer *poLayer,
170 : const PageContext &oPageContext, double &dfClippingMinX,
171 : double &dfClippingMinY, double &dfClippingMaxX, double &dfClippingMaxY,
172 : double adfMatrix[4],
173 : std::unique_ptr<OGRCoordinateTransformation> &poCT);
174 :
175 : #ifdef HAVE_PDF_READ_SUPPORT
176 : bool WritePDF(const CPLXMLNode *psNode, PageContext &oPageContext);
177 :
178 : typedef std::map<std::pair<int, int>, GDALPDFObjectNum> RemapType;
179 : GDALPDFObjectNum EmitNewObject(GDALPDFObject *poObj,
180 : RemapType &oRemapObjectRefs);
181 : GDALPDFObjectNum SerializeAndRenumber(GDALPDFObject *poObj);
182 : bool SerializeAndRenumber(CPLString &osStr, GDALPDFObject *poObj,
183 : RemapType &oRemapObjectRefs);
184 : bool SerializeAndRenumberIgnoreRef(CPLString &osStr, GDALPDFObject *poObj,
185 : RemapType &oRemapObjectRefs);
186 : #endif
187 :
188 : public:
189 : explicit GDALPDFComposerWriter(VSILFILE *fp);
190 : ~GDALPDFComposerWriter();
191 :
192 : bool Generate(const CPLXMLNode *psComposition);
193 : void Close();
194 : };
195 :
196 : GDALDataset *GDALPDFCreateFromCompositionFile(const char *pszPDFFilename,
197 : const char *pszXMLFilename);
198 :
199 : #endif // PDFCREATEFROMCOMPOSITION_H_INCLUDED
|