1 /******************************************************************************
2  * $Id: pdfcreatefromcomposition.h 842d122d2f23aaebb28362e083b52d6bc7dbcde2 2019-08-11 17:42:34 +0200 Even Rouault $
3  *
4  * Project:  PDF driver
5  * Purpose:  GDALDataset driver for PDF dataset.
6  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
7  *
8  ******************************************************************************
9  * Copyright (c) 2019, Even Rouault <even dot rouault at spatialys dot com>
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  ****************************************************************************/
29 
30 #ifndef PDFCREATEFROMCOMPOSITION_H_INCLUDED
31 #define PDFCREATEFROMCOMPOSITION_H_INCLUDED
32 
33 #include "gdal_pdf.h"
34 #include "pdfcreatecopy.h"
35 #include "cpl_minixml.h"
36 #include "ogrsf_frmts.h"
37 #include "ogr_geometry.h"
38 
39 #include <map>
40 #include <memory>
41 #include <vector>
42 
43 class GDALPDFComposerWriter final: public GDALPDFBaseWriter
44 {
45         CPLString m_osJPEG2000Driver{};
46         struct TreeOfOCG
47         {
48             GDALPDFObjectNum                        m_nNum{};
49             bool                                    m_bInitiallyVisible{true};
50             std::vector<std::unique_ptr<TreeOfOCG>> m_children{};
51         };
52         bool m_bDisplayLayersOnlyOnVisiblePages = false;
53         TreeOfOCG m_oTreeOfOGC{};
54         std::map<CPLString, std::vector<GDALPDFObjectNum>> m_oMapExclusiveOCGIdToOCGs{};
55 
56         std::map<CPLString, GDALPDFObjectNum> m_oMapLayerIdToOCG{};
57 
58         struct xyPair
59         {
60             double x = 0;
61             double y = 0;
xxyPair62             xyPair(double xin = 0.0, double yin = 0.0): x(xin), y(yin) {}
63         };
64 
65         struct Georeferencing
66         {
67             CPLString           m_osID{};
68             OGRSpatialReference m_oSRS{};
69             double              m_bboxX1{};
70             double              m_bboxY1{};
71             double              m_bboxX2{};
72             double              m_bboxY2{};
73             double              m_adfGT[6]{0,1,0,0,0,1};
74         };
75 
76         std::vector<GDALPDFObjectNum> m_anParentElements;
77         std::vector<GDALPDFObjectNum> m_anFeatureLayerId;
78         std::map<CPLString, GDALPDFObjectNum> m_oMapPageIdToObjectNum;
79         struct PageContext
80         {
81             double m_dfWidthInUserUnit = 0;
82             double m_dfHeightInUserUnit = 0;
83             CPLString m_osDrawingStream{};
84             std::vector<GDALPDFObjectNum> m_anFeatureUserProperties;
85             int m_nMCID = 0;
86             PDFCompressMethod m_eStreamCompressMethod = COMPRESS_DEFLATE;
87             std::map<CPLString, GDALPDFObjectNum> m_oXObjects{};
88             std::map<CPLString, GDALPDFObjectNum> m_oProperties{};
89             std::map<CPLString, GDALPDFObjectNum> m_oExtGState{};
90             std::vector<GDALPDFObjectNum> m_anAnnotationsId{};
91             std::map<CPLString, Georeferencing> m_oMapGeoreferencedId{};
92         };
93 
94         bool CreateLayerTree(const CPLXMLNode* psNode,
95                              const GDALPDFObjectNum& nParentId,
96                              TreeOfOCG* parent);
97 
98         struct Action
99         {
100             virtual ~Action() = default;
101         };
102 
103         struct GotoPageAction final: public Action
104         {
105             GDALPDFObjectNum m_nPageDestId{};
106             double m_dfX1 = 0;
107             double m_dfX2 = 0;
108             double m_dfY1 = 0;
109             double m_dfY2 = 0;
110         };
111 
112         struct SetLayerStateAction final: public Action
113         {
114             std::set<GDALPDFObjectNum> m_anONLayers{};
115             std::set<GDALPDFObjectNum> m_anOFFLayers{};
116         };
117 
118         struct JavascriptAction final: public Action
119         {
120             CPLString m_osScript{};
121         };
122 
123         bool ParseActions(const CPLXMLNode* psNode,
124                             std::vector<std::unique_ptr<Action>>& actions);
125         static GDALPDFDictionaryRW* SerializeActions(
126                         GDALPDFDictionaryRW* poDictForDest,
127                         const std::vector<std::unique_ptr<Action>>& actions);
128 
129         struct OutlineItem
130         {
131             GDALPDFObjectNum m_nObjId{};
132             CPLString m_osName{};
133             bool m_bOpen = true;
134             int m_nFlags = 0;
135             std::vector<std::unique_ptr<Action>> m_aoActions{};
136             std::vector<std::unique_ptr<OutlineItem>> m_aoKids{};
137             int m_nKidsRecCount = 0;
138         };
139         GDALPDFObjectNum m_nOutlinesId{};
140 
141         bool CreateOutlineFirstPass(const CPLXMLNode* psNode,
142                                     OutlineItem* poParentItem);
143         bool SerializeOutlineKids(const OutlineItem* poParentItem);
144         bool CreateOutline(const CPLXMLNode* psNode);
145 
146         void WritePages();
147 
148         static GDALPDFArrayRW* CreateOCGOrder(const TreeOfOCG* parent);
149         static void CollectOffOCG(std::vector<GDALPDFObjectNum>& ar,
150                                           const TreeOfOCG* parent);
151         bool GeneratePage(const CPLXMLNode* psPage);
152         bool GenerateGeoreferencing(const CPLXMLNode* psGeoreferencing,
153                                     double dfWidthInUserUnit,
154                                     double dfHeightInUserUnit,
155                                     GDALPDFObjectNum& nViewportId,
156                                     GDALPDFObjectNum& nLGIDictId,
157                                     Georeferencing& georeferencing);
158 
159         GDALPDFObjectNum GenerateISO32000_Georeferencing(
160             OGRSpatialReferenceH hSRS,
161             double bboxX1, double bboxY1, double bboxX2, double bboxY2,
162             const std::vector<GDAL_GCP>& aGCPs,
163             const std::vector<xyPair>& aBoundingPolygon);
164 
165         GDALPDFObjectNum GenerateOGC_BP_Georeferencing(
166             OGRSpatialReferenceH hSRS,
167             double bboxX1, double bboxY1, double bboxX2, double bboxY2,
168             const std::vector<GDAL_GCP>& aGCPs,
169             const std::vector<xyPair>& aBoundingPolygon);
170 
171         bool ExploreContent(const CPLXMLNode* psNode, PageContext& oPageContext);
172         bool WriteRaster(const CPLXMLNode* psNode, PageContext& oPageContext);
173         bool WriteVector(const CPLXMLNode* psNode, PageContext& oPageContext);
174         bool WriteVectorLabel(const CPLXMLNode* psNode, PageContext& oPageContext);
175         void StartBlending(const CPLXMLNode* psNode, PageContext& oPageContext,
176                            double& dfOpacity);
177         static void EndBlending(const CPLXMLNode* psNode, PageContext& oPageContext);
178 
179         static bool SetupVectorGeoreferencing(
180             const char* pszGeoreferencingId,
181             OGRLayer* poLayer,
182             const PageContext& oPageContext,
183             double& dfClippingMinX,
184             double& dfClippingMinY,
185             double& dfClippingMaxX,
186             double& dfClippingMaxY,
187             double adfMatrix[4],
188             std::unique_ptr<OGRCoordinateTransformation>& poCT);
189 
190 #ifdef HAVE_PDF_READ_SUPPORT
191         bool WritePDF(const CPLXMLNode* psNode, PageContext& oPageContext);
192 
193         typedef std::map< std::pair<int, int>, GDALPDFObjectNum> RemapType;
194         GDALPDFObjectNum EmitNewObject(GDALPDFObject* poObj,
195                                        RemapType& oRemapObjectRefs);
196         GDALPDFObjectNum SerializeAndRenumber(GDALPDFObject* poObj);
197         bool SerializeAndRenumber(CPLString& osStr,
198             GDALPDFObject* poObj,
199             RemapType& oRemapObjectRefs);
200         bool SerializeAndRenumberIgnoreRef(CPLString& osStr,
201             GDALPDFObject* poObj,
202             RemapType& oRemapObjectRefs);
203 #endif
204 
205     public:
206         explicit GDALPDFComposerWriter(VSILFILE* fp);
207         ~GDALPDFComposerWriter();
208 
209         bool Generate(const CPLXMLNode* psComposition);
210         void Close();
211 };
212 
213 GDALDataset* GDALPDFCreateFromCompositionFile(const char* pszPDFFilename,
214                                               const char *pszXMLFilename);
215 
216 
217 #endif // PDFCREATEFROMCOMPOSITION_H_INCLUDED
218