Coverage Report

Created: 2025-06-09 07:43

/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