Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: PNG Driver
4 : * Purpose: Implement GDAL PNG Support
5 : * Author: Frank Warmerdam, warmerda@home.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2000, Frank Warmerdam
9 : * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ******************************************************************************
13 : *
14 : * ISSUES:
15 : * o CollectMetadata() will only capture TEXT chunks before the image
16 : * data as the code is currently structured.
17 : * o Interlaced images are read entirely into memory for use. This is
18 : * bad for large images.
19 : * o Image reading is always strictly sequential. Reading backwards will
20 : * cause the file to be rewound, and access started again from the
21 : * beginning.
22 : * o 16 bit alpha values are not scaled by to eight bit.
23 : *
24 : */
25 :
26 : #include "cpl_string.h"
27 : #include "gdal_frmts.h"
28 : #include "gdal_pam.h"
29 :
30 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
31 : // Disabled for now since currently this only works for libpng 1.2
32 : // libpng 1.6 requires additional includes. See #6928
33 : // #define DISABLE_CRC_CHECK
34 : #endif
35 :
36 : #ifdef DISABLE_CRC_CHECK
37 : // Needs to be defined before including png.h
38 : #define PNG_INTERNAL
39 : #endif
40 :
41 : #include "png.h"
42 :
43 : #include <csetjmp>
44 :
45 : #include <algorithm>
46 : #include <array>
47 :
48 : #ifdef _MSC_VER
49 : #pragma warning(disable : 4611)
50 : #endif
51 :
52 : #ifdef USE_NEON_OPTIMIZATIONS
53 : #define HAVE_SSE2
54 : #include "include_sse2neon.h"
55 : #elif defined(__SSE2__) || defined(_M_X64) || \
56 : (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
57 : #define HAVE_SSE2
58 : #include <emmintrin.h>
59 : #endif
60 :
61 : #ifdef HAVE_SSE2
62 : #define ENABLE_WHOLE_IMAGE_OPTIMIZATION
63 : #endif
64 :
65 : /************************************************************************/
66 : /* ==================================================================== */
67 : /* PNGDataset */
68 : /* ==================================================================== */
69 : /************************************************************************/
70 :
71 : class PNGRasterBand;
72 :
73 : #ifdef _MSC_VER
74 : #pragma warning(push)
75 : // 'PNGDataset': structure was padded due to __declspec(align()) at line where
76 : // we use `jmp_buf`.
77 : #pragma warning(disable : 4324)
78 : #endif
79 :
80 : class PNGDataset final : public GDALPamDataset
81 : {
82 : friend class PNGRasterBand;
83 :
84 : VSILFILE *fpImage{};
85 : png_structp hPNG{};
86 : png_infop psPNGInfo{};
87 : int nBitDepth{8};
88 : int nColorType{}; // PNG_COLOR_TYPE_*
89 : int bInterlaced{};
90 :
91 : int nBufferStartLine{};
92 : int nBufferLines{};
93 : int nLastLineRead{-1};
94 : GByte *pabyBuffer{};
95 :
96 : std::unique_ptr<GDALColorTable> poColorTable{};
97 :
98 : int bGeoTransformValid{};
99 : GDALGeoTransform m_gt{};
100 :
101 : void CollectMetadata();
102 :
103 : int bHasReadXMPMetadata{};
104 : void CollectXMPMetadata();
105 :
106 : CPLErr LoadScanline(int);
107 : CPLErr LoadInterlacedChunk(int);
108 : void Restart();
109 :
110 : int bHasTriedLoadWorldFile{};
111 : void LoadWorldFile();
112 : CPLString osWldFilename{};
113 :
114 : int bHasReadICCMetadata{};
115 : void LoadICCProfile();
116 :
117 : bool m_bByteOrderIsLittleEndian = false;
118 : bool m_bHasRewind = false;
119 :
120 : static void WriteMetadataAsText(jmp_buf sSetJmpContext, png_structp hPNG,
121 : png_infop psPNGInfo, const char *pszKey,
122 : const char *pszValue);
123 : static GDALDataset *OpenStage2(GDALOpenInfo *, PNGDataset *&);
124 :
125 : CPL_DISALLOW_COPY_ASSIGN(PNGDataset)
126 :
127 : public:
128 : PNGDataset();
129 : ~PNGDataset() override;
130 :
131 : CPLErr Close(GDALProgressFunc = nullptr, void * = nullptr) override;
132 :
133 : static GDALDataset *Open(GDALOpenInfo *);
134 : static GDALDataset *CreateCopy(const char *pszFilename,
135 : GDALDataset *poSrcDS, int bStrict,
136 : CSLConstList papszOptions,
137 : GDALProgressFunc pfnProgress,
138 : void *pProgressData);
139 :
140 : char **GetFileList(void) override;
141 :
142 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
143 : CPLErr FlushCache(bool bAtClosing) override;
144 :
145 : char **GetMetadataDomainList() override;
146 :
147 : CSLConstList GetMetadata(const char *pszDomain = "") override;
148 : virtual const char *
149 : GetMetadataItem(const char *pszName,
150 : const char *pszDomain = nullptr) override;
151 :
152 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
153 : GDALDataType, int, BANDMAP_TYPE, GSpacing, GSpacing,
154 : GSpacing, GDALRasterIOExtraArg *psExtraArg) override;
155 :
156 : #ifdef ENABLE_WHOLE_IMAGE_OPTIMIZATION
157 : bool IsCompatibleOfSingleBlock() const;
158 : CPLErr LoadWholeImage(void *pSingleBuffer, GSpacing nPixelSpace,
159 : GSpacing nLineSpace, GSpacing nBandSpace,
160 : void *apabyBuffers[4]);
161 : #endif
162 :
163 : jmp_buf sSetJmpContext{}; // Semi-private.
164 :
165 : #ifdef SUPPORT_CREATE
166 : int m_nBitDepth;
167 : GByte *m_pabyBuffer;
168 : png_byte *m_pabyAlpha;
169 : png_structp m_hPNG;
170 : png_infop m_psPNGInfo;
171 : png_color *m_pasPNGColors;
172 : VSILFILE *m_fpImage;
173 : int m_bGeoTransformValid;
174 : double m_adfGeoTransform[6];
175 : char *m_pszFilename;
176 : int m_nColorType; // PNG_COLOR_TYPE_*
177 :
178 : virtual CPLErr SetGeoTransform(double *);
179 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
180 : int nBands, GDALDataType,
181 : CSLConstList papszParamList);
182 :
183 : protected:
184 : CPLErr write_png_header();
185 :
186 : #endif
187 : };
188 :
189 : #ifdef _MSC_VER
190 : #pragma warning(pop)
191 : #endif
192 :
193 : /************************************************************************/
194 : /* ==================================================================== */
195 : /* PNGRasterBand */
196 : /* ==================================================================== */
197 : /************************************************************************/
198 :
199 : class PNGRasterBand final : public GDALPamRasterBand
200 : {
201 : friend class PNGDataset;
202 :
203 : public:
204 : PNGRasterBand(PNGDataset *, int);
205 :
206 : CPLErr IReadBlock(int, int, void *) override;
207 :
208 : virtual GDALSuggestedBlockAccessPattern
209 0 : GetSuggestedBlockAccessPattern() const override
210 : {
211 0 : return GSBAP_TOP_TO_BOTTOM;
212 : }
213 :
214 : GDALColorInterp GetColorInterpretation() override;
215 : GDALColorTable *GetColorTable() override;
216 : CPLErr SetNoDataValue(double dfNewValue) override;
217 : double GetNoDataValue(int *pbSuccess = nullptr) override;
218 :
219 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
220 : GDALDataType, GSpacing, GSpacing,
221 : GDALRasterIOExtraArg *psExtraArg) override;
222 :
223 : int bHaveNoData;
224 : double dfNoDataValue;
225 :
226 : #ifdef SUPPORT_CREATE
227 : virtual CPLErr SetColorTable(GDALColorTable *);
228 : CPLErr IWriteBlock(int, int, void *) override;
229 :
230 : protected:
231 : int m_bBandProvided[5];
232 :
233 : void reset_band_provision_flags()
234 : {
235 : PNGDataset &ds = *reinterpret_cast<PNGDataset *>(poDS);
236 :
237 : for (size_t i = 0; i < static_cast<size_t>(ds.nBands); i++)
238 : m_bBandProvided[i] = FALSE;
239 : }
240 : #endif
241 : };
|