Coverage Report

Created: 2025-12-03 08:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/pdf/pdfcreatefromcomposition.h
Line
Count
Source
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
0
        explicit xyPair(double xin = 0.0, double yin = 0.0) : x(xin), y(yin)
50
0
        {
51
0
        }
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
        GDALGeoTransform m_gt{};
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
    struct Action /* non final */
88
    {
89
        virtual ~Action();
90
    };
91
92
    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
    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
    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