/src/gdal/frmts/pdf/pdfcreatecopy.h
Line | Count | Source (jump to first uncovered line) |
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) 2012-2019, Even Rouault <even dot rouault at spatialys dot com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #ifndef PDFCREATECOPY_H_INCLUDED |
14 | | #define PDFCREATECOPY_H_INCLUDED |
15 | | |
16 | | #include "pdfobject.h" |
17 | | #include "gdal_priv.h" |
18 | | #include <vector> |
19 | | #include <map> |
20 | | |
21 | | #include "ogr_api.h" |
22 | | #include "ogr_spatialref.h" |
23 | | |
24 | | /* Cf PDF reference v1.7, Appendix C, page 993 */ |
25 | 0 | #define MAXIMUM_SIZE_IN_UNITS 14400 |
26 | | |
27 | 0 | #define APPLY_GT_X(gt, x, y) ((gt)[0] + (x) * (gt)[1] + (y) * (gt)[2]) |
28 | 0 | #define APPLY_GT_Y(gt, x, y) ((gt)[3] + (x) * (gt)[4] + (y) * (gt)[5]) |
29 | | |
30 | | typedef enum |
31 | | { |
32 | | COMPRESS_NONE, |
33 | | COMPRESS_DEFLATE, |
34 | | COMPRESS_JPEG, |
35 | | COMPRESS_JPEG2000, |
36 | | COMPRESS_DEFAULT |
37 | | } PDFCompressMethod; |
38 | | |
39 | | struct PDFMargins |
40 | | { |
41 | | int nLeft = 0; |
42 | | int nRight = 0; |
43 | | int nTop = 0; |
44 | | int nBottom = 0; |
45 | | }; |
46 | | |
47 | | class GDALFakePDFDataset final : public GDALDataset |
48 | | { |
49 | | public: |
50 | 0 | GDALFakePDFDataset() = default; |
51 | | ~GDALFakePDFDataset() override; |
52 | | }; |
53 | | |
54 | | /************************************************************************/ |
55 | | /* GDALPDFWriter */ |
56 | | /************************************************************************/ |
57 | | |
58 | | class GDALXRefEntry |
59 | | { |
60 | | public: |
61 | | vsi_l_offset nOffset = 0; |
62 | | int nGen = 0; |
63 | | int bFree = FALSE; |
64 | | |
65 | 0 | GDALXRefEntry() = default; |
66 | | |
67 | | explicit GDALXRefEntry(vsi_l_offset nOffsetIn, int nGenIn = 0) |
68 | | : nOffset(nOffsetIn), nGen(nGenIn) |
69 | 0 | { |
70 | 0 | } |
71 | | |
72 | | GDALXRefEntry(const GDALXRefEntry &oOther) |
73 | 0 | : nOffset(oOther.nOffset), nGen(oOther.nGen), bFree(oOther.bFree) |
74 | 0 | { |
75 | 0 | } |
76 | | |
77 | | GDALXRefEntry &operator=(const GDALXRefEntry &oOther) |
78 | 0 | { |
79 | 0 | nOffset = oOther.nOffset; |
80 | 0 | nGen = oOther.nGen; |
81 | 0 | bFree = oOther.bFree; |
82 | 0 | return *this; |
83 | 0 | } |
84 | | }; |
85 | | |
86 | | class GDALPDFImageDesc |
87 | | { |
88 | | public: |
89 | | GDALPDFObjectNum nImageId{}; |
90 | | double dfXOff = 0; |
91 | | double dfYOff = 0; |
92 | | double dfXSize = 0; |
93 | | double dfYSize = 0; |
94 | | }; |
95 | | |
96 | | class GDALPDFLayerDesc |
97 | | { |
98 | | public: |
99 | | GDALPDFObjectNum nOCGId{}; |
100 | | GDALPDFObjectNum nOCGTextId{}; |
101 | | GDALPDFObjectNum nFeatureLayerId{}; |
102 | | CPLString osLayerName{}; |
103 | | int bWriteOGRAttributes{false}; |
104 | | std::vector<GDALPDFObjectNum> aIds{}; |
105 | | std::vector<GDALPDFObjectNum> aIdsText{}; |
106 | | std::vector<GDALPDFObjectNum> aUserPropertiesIds{}; |
107 | | std::vector<CPLString> aFeatureNames{}; |
108 | | std::vector<CPLString> aosIncludedFields{}; |
109 | | }; |
110 | | |
111 | | class GDALPDFRasterDesc |
112 | | { |
113 | | public: |
114 | | GDALPDFObjectNum nOCGRasterId{}; |
115 | | std::vector<GDALPDFImageDesc> asImageDesc{}; |
116 | | }; |
117 | | |
118 | | class GDALPDFPageContext |
119 | | { |
120 | | public: |
121 | | GDALDataset *poClippingDS = nullptr; |
122 | | PDFCompressMethod eStreamCompressMethod = COMPRESS_NONE; |
123 | | double dfDPI{0}; |
124 | | PDFMargins sMargins{}; |
125 | | GDALPDFObjectNum nPageId{}; |
126 | | GDALPDFObjectNum nContentId{}; |
127 | | GDALPDFObjectNum nResourcesId{}; |
128 | | std::vector<GDALPDFLayerDesc> asVectorDesc{}; |
129 | | std::vector<GDALPDFRasterDesc> asRasterDesc{}; |
130 | | GDALPDFObjectNum nAnnotsId{}; |
131 | | std::vector<GDALPDFObjectNum> anAnnotationsId{}; |
132 | | }; |
133 | | |
134 | | class GDALPDFOCGDesc |
135 | | { |
136 | | public: |
137 | | GDALPDFObjectNum nId{}; |
138 | | GDALPDFObjectNum nParentId{}; |
139 | | CPLString osLayerName{}; |
140 | | }; |
141 | | |
142 | | class GDALPDFBaseWriter |
143 | | { |
144 | | protected: |
145 | | VSILFILE *m_fp = nullptr; |
146 | | bool m_bInWriteObj = false; |
147 | | std::vector<GDALXRefEntry> m_asXRefEntries{}; |
148 | | GDALPDFObjectNum m_nPageResourceId{}; |
149 | | GDALPDFObjectNum m_nCatalogId{}; |
150 | | int m_nCatalogGen = 0; |
151 | | GDALPDFObjectNum m_nInfoId{}; |
152 | | int m_nInfoGen = 0; |
153 | | GDALPDFObjectNum m_nXMPId{}; |
154 | | int m_nXMPGen = 0; |
155 | | GDALPDFObjectNum m_nStructTreeRootId{}; |
156 | | GDALPDFObjectNum m_nNamesId{}; |
157 | | |
158 | | GDALPDFObjectNum m_nContentLengthId{}; |
159 | | VSILFILE *m_fpBack = nullptr; |
160 | | VSILFILE *m_fpGZip = nullptr; |
161 | | vsi_l_offset m_nStreamStart = 0; |
162 | | |
163 | | std::vector<GDALPDFObjectNum> m_asPageId{}; |
164 | | std::vector<GDALPDFOCGDesc> m_asOCGs{}; |
165 | | std::map<CPLString, GDALPDFImageDesc> m_oMapSymbolFilenameToDesc{}; |
166 | | |
167 | | public: |
168 | | struct ObjectStyle |
169 | | { |
170 | | unsigned int nPenR = 0; |
171 | | unsigned int nPenG = 0; |
172 | | unsigned int nPenB = 0; |
173 | | unsigned int nPenA = 255; |
174 | | unsigned int nBrushR = 127; |
175 | | unsigned int nBrushG = 127; |
176 | | unsigned int nBrushB = 127; |
177 | | unsigned int nBrushA = 127; |
178 | | unsigned int nTextR = 0; |
179 | | unsigned int nTextG = 0; |
180 | | unsigned int nTextB = 0; |
181 | | unsigned int nTextA = 255; |
182 | | int bSymbolColorDefined = FALSE; |
183 | | unsigned int nSymbolR = 0; |
184 | | unsigned int nSymbolG = 0; |
185 | | unsigned int nSymbolB = 0; |
186 | | unsigned int nSymbolA = 255; |
187 | | bool bHasPenBrushOrSymbol = false; |
188 | | CPLString osTextFont{}; |
189 | | bool bTextBold = false; |
190 | | bool bTextItalic = false; |
191 | | double dfTextSize = 12.0; |
192 | | double dfTextAngle = 0.0; |
193 | | double dfTextStretch = 1.0; |
194 | | double dfTextDx = 0.0; |
195 | | double dfTextDy = 0.0; |
196 | | int nTextAnchor = 1; |
197 | | double dfPenWidth = 1.0; |
198 | | double dfSymbolSize = 5.0; |
199 | | CPLString osDashArray{}; |
200 | | CPLString osLabelText{}; |
201 | | CPLString osSymbolId{}; |
202 | | GDALPDFObjectNum nImageSymbolId{}; |
203 | | int nImageWidth = 0; |
204 | | int nImageHeight = 0; |
205 | | }; |
206 | | |
207 | | protected: |
208 | | explicit GDALPDFBaseWriter(VSILFILE *fp); |
209 | | ~GDALPDFBaseWriter(); |
210 | | |
211 | | GDALPDFObjectNum AllocNewObject(); |
212 | | |
213 | | void StartObj(const GDALPDFObjectNum &nObjectId, int nGen = 0); |
214 | | void EndObj(); |
215 | | |
216 | | void StartObjWithStream(const GDALPDFObjectNum &nObjectId, |
217 | | GDALPDFDictionaryRW &oDict, bool bDeflate); |
218 | | void EndObjWithStream(); |
219 | | |
220 | | void StartNewDoc(); |
221 | | void Close(); |
222 | | |
223 | | void WriteXRefTableAndTrailer(bool bUpdate, vsi_l_offset nLastStartXRef); |
224 | | |
225 | | GDALPDFObjectNum WriteSRS_ISO32000(GDALDataset *poSrcDS, double dfUserUnit, |
226 | | const char *pszNEATLINE, |
227 | | PDFMargins *psMargins, |
228 | | int bWriteViewport); |
229 | | |
230 | | GDALPDFObjectNum |
231 | | WriteOCG(const char *pszLayerName, |
232 | | const GDALPDFObjectNum &nParentId = GDALPDFObjectNum()); |
233 | | |
234 | | GDALPDFObjectNum |
235 | | WriteBlock(GDALDataset *poSrcDS, int nXOff, int nYOff, int nReqXSize, |
236 | | int nReqYSize, const GDALPDFObjectNum &nColorTableIdIn, |
237 | | PDFCompressMethod eCompressMethod, int nPredictor, |
238 | | int nJPEGQuality, const char *pszJPEG2000_DRIVER, |
239 | | GDALProgressFunc pfnProgress, void *pProgressData); |
240 | | GDALPDFObjectNum WriteMask(GDALDataset *poSrcDS, int nXOff, int nYOff, |
241 | | int nReqXSize, int nReqYSize, |
242 | | PDFCompressMethod eCompressMethod); |
243 | | |
244 | | GDALPDFObjectNum WriteColorTable(GDALDataset *poSrcDS); |
245 | | |
246 | | void GetObjectStyle( |
247 | | const char *pszStyleString, OGRFeatureH hFeat, |
248 | | const double adfMatrix[4], |
249 | | std::map<CPLString, GDALPDFImageDesc> oMapSymbolFilenameToDesc, |
250 | | ObjectStyle &os); |
251 | | static CPLString GenerateDrawingStream(OGRGeometryH hGeom, |
252 | | const double adfMatrix[4], |
253 | | ObjectStyle &os, double dfRadius); |
254 | | GDALPDFObjectNum |
255 | | WriteAttributes(OGRFeatureH hFeat, |
256 | | const std::vector<CPLString> &aosIncludedFields, |
257 | | const char *pszOGRDisplayField, int nMCID, |
258 | | const GDALPDFObjectNum &oParent, |
259 | | const GDALPDFObjectNum &oPage, CPLString &osOutFeatureName); |
260 | | |
261 | | GDALPDFObjectNum WriteLabel(OGRGeometryH hGeom, const double adfMatrix[4], |
262 | | ObjectStyle &os, |
263 | | PDFCompressMethod eStreamCompressMethod, |
264 | | double bboxXMin, double bboxYMin, |
265 | | double bboxXMax, double bboxYMax); |
266 | | |
267 | | GDALPDFObjectNum WriteLink(OGRFeatureH hFeat, const char *pszOGRLinkField, |
268 | | const double adfMatrix[4], int bboxXMin, |
269 | | int bboxYMin, int bboxXMax, int bboxYMax); |
270 | | |
271 | | static void ComputeIntBBox(OGRGeometryH hGeom, const OGREnvelope &sEnvelope, |
272 | | const double adfMatrix[4], const ObjectStyle &os, |
273 | | double dfRadius, int &bboxXMin, int &bboxYMin, |
274 | | int &bboxXMax, int &bboxYMax); |
275 | | |
276 | | GDALPDFObjectNum WriteJavascript(const char *pszJavascript, bool bDeflate); |
277 | | |
278 | | public: |
279 | | GDALPDFObjectNum SetInfo(GDALDataset *poSrcDS, char **papszOptions); |
280 | | GDALPDFObjectNum SetInfo(const char *pszAUTHOR, const char *pszPRODUCER, |
281 | | const char *pszCREATOR, |
282 | | const char *pszCREATION_DATE, |
283 | | const char *pszSUBJECT, const char *pszTITLE, |
284 | | const char *pszKEYWORDS); |
285 | | GDALPDFObjectNum SetXMP(GDALDataset *poSrcDS, const char *pszXMP); |
286 | | |
287 | | private: |
288 | | CPL_DISALLOW_COPY_ASSIGN(GDALPDFBaseWriter) |
289 | | }; |
290 | | |
291 | | class GDALPDFUpdateWriter final : public GDALPDFBaseWriter |
292 | | { |
293 | | bool m_bUpdateNeeded = false; |
294 | | vsi_l_offset m_nLastStartXRef = 0; |
295 | | int m_nLastXRefSize = 0; |
296 | | |
297 | | public: |
298 | | explicit GDALPDFUpdateWriter(VSILFILE *fpIn); |
299 | | ~GDALPDFUpdateWriter(); |
300 | | |
301 | | void Close(); |
302 | | |
303 | | const GDALPDFObjectNum &GetCatalogNum() const |
304 | 0 | { |
305 | 0 | return m_nCatalogId; |
306 | 0 | } |
307 | | |
308 | | int GetCatalogGen() const |
309 | 0 | { |
310 | 0 | return m_nCatalogGen; |
311 | 0 | } |
312 | | |
313 | | int ParseTrailerAndXRef(); |
314 | | void UpdateProj(GDALDataset *poSrcDS, double dfDPI, |
315 | | GDALPDFDictionaryRW *poPageDict, |
316 | | const GDALPDFObjectNum &nPageId, int nPageGen); |
317 | | void UpdateInfo(GDALDataset *poSrcDS); |
318 | | void UpdateXMP(GDALDataset *poSrcDS, GDALPDFDictionaryRW *poCatalogDict); |
319 | | }; |
320 | | |
321 | | class GDALPDFWriter final : public GDALPDFBaseWriter |
322 | | { |
323 | | GDALPDFPageContext oPageContext{}; |
324 | | |
325 | | CPLString m_osOffLayers{}; |
326 | | CPLString m_osExclusiveLayers{}; |
327 | | |
328 | | void WritePages(); |
329 | | |
330 | | public: |
331 | | explicit GDALPDFWriter(VSILFILE *fpIn); |
332 | | ~GDALPDFWriter(); |
333 | | |
334 | | void Close(); |
335 | | |
336 | | bool StartPage(GDALDataset *poSrcDS, double dfDPI, bool bWriteUserUnit, |
337 | | const char *pszGEO_ENCODING, const char *pszNEATLINE, |
338 | | PDFMargins *psMargins, |
339 | | PDFCompressMethod eStreamCompressMethod, int bHasOGRData); |
340 | | |
341 | | bool WriteImagery(GDALDataset *poDS, const char *pszLayerName, |
342 | | PDFCompressMethod eCompressMethod, int nPredictor, |
343 | | int nJPEGQuality, const char *pszJPEG2000_DRIVER, |
344 | | int nBlockXSize, int nBlockYSize, |
345 | | GDALProgressFunc pfnProgress, void *pProgressData); |
346 | | |
347 | | bool WriteClippedImagery(GDALDataset *poDS, const char *pszLayerName, |
348 | | PDFCompressMethod eCompressMethod, int nPredictor, |
349 | | int nJPEGQuality, const char *pszJPEG2000_DRIVER, |
350 | | int nBlockXSize, int nBlockYSize, |
351 | | GDALProgressFunc pfnProgress, void *pProgressData); |
352 | | bool WriteOGRDataSource(const char *pszOGRDataSource, |
353 | | const char *pszOGRDisplayField, |
354 | | const char *pszOGRDisplayLayerNames, |
355 | | const char *pszOGRLinkField, |
356 | | int bWriteOGRAttributes); |
357 | | |
358 | | GDALPDFLayerDesc StartOGRLayer(const std::string &osLayerName, |
359 | | int bWriteOGRAttributes); |
360 | | void EndOGRLayer(GDALPDFLayerDesc &osVectorDesc); |
361 | | |
362 | | int WriteOGRLayer(GDALDatasetH hDS, int iLayer, |
363 | | const char *pszOGRDisplayField, |
364 | | const char *pszOGRLinkField, |
365 | | const std::string &osLayerName, int bWriteOGRAttributes, |
366 | | int &iObj); |
367 | | |
368 | | int WriteOGRFeature(GDALPDFLayerDesc &osVectorDesc, OGRFeatureH hFeat, |
369 | | OGRCoordinateTransformationH hCT, |
370 | | const char *pszOGRDisplayField, |
371 | | const char *pszOGRLinkField, int bWriteOGRAttributes, |
372 | | int &iObj); |
373 | | |
374 | | GDALPDFObjectNum WriteJavascript(const char *pszJavascript); |
375 | | GDALPDFObjectNum WriteJavascriptFile(const char *pszJavascriptFile); |
376 | | |
377 | | int EndPage(const char *pszExtraImages, const char *pszExtraStream, |
378 | | const char *pszExtraLayerName, const char *pszOffLayers, |
379 | | const char *pszExclusiveLayers); |
380 | | }; |
381 | | |
382 | | GDALDataset *GDALPDFCreateCopy(const char *, GDALDataset *, int, char **, |
383 | | GDALProgressFunc pfnProgress, |
384 | | void *pProgressData); |
385 | | |
386 | | #endif // PDFCREATECOPY_H_INCLUDED |