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 : 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 : virtual ~PNGDataset();
130 :
131 : static GDALDataset *Open(GDALOpenInfo *);
132 : static GDALDataset *CreateCopy(const char *pszFilename,
133 : GDALDataset *poSrcDS, int bStrict,
134 : char **papszOptions,
135 : GDALProgressFunc pfnProgress,
136 : void *pProgressData);
137 :
138 : virtual char **GetFileList(void) override;
139 :
140 : virtual CPLErr GetGeoTransform(GDALGeoTransform >) const override;
141 : virtual CPLErr FlushCache(bool bAtClosing) override;
142 :
143 : virtual char **GetMetadataDomainList() override;
144 :
145 : virtual char **GetMetadata(const char *pszDomain = "") override;
146 : virtual const char *
147 : GetMetadataItem(const char *pszName,
148 : const char *pszDomain = nullptr) override;
149 :
150 : virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
151 : GDALDataType, int, BANDMAP_TYPE, GSpacing,
152 : GSpacing, GSpacing,
153 : GDALRasterIOExtraArg *psExtraArg) override;
154 :
155 : #ifdef ENABLE_WHOLE_IMAGE_OPTIMIZATION
156 : bool IsCompatibleOfSingleBlock() const;
157 : CPLErr LoadWholeImage(void *pSingleBuffer, GSpacing nPixelSpace,
158 : GSpacing nLineSpace, GSpacing nBandSpace,
159 : void *apabyBuffers[4]);
160 : #endif
161 :
162 : jmp_buf sSetJmpContext{}; // Semi-private.
163 :
164 : #ifdef SUPPORT_CREATE
165 : int m_nBitDepth;
166 : GByte *m_pabyBuffer;
167 : png_byte *m_pabyAlpha;
168 : png_structp m_hPNG;
169 : png_infop m_psPNGInfo;
170 : png_color *m_pasPNGColors;
171 : VSILFILE *m_fpImage;
172 : int m_bGeoTransformValid;
173 : double m_adfGeoTransform[6];
174 : char *m_pszFilename;
175 : int m_nColorType; // PNG_COLOR_TYPE_*
176 :
177 : virtual CPLErr SetGeoTransform(double *);
178 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
179 : int nBands, GDALDataType, char **papszParamList);
180 :
181 : protected:
182 : CPLErr write_png_header();
183 :
184 : #endif
185 : };
186 :
187 : #ifdef _MSC_VER
188 : #pragma warning(pop)
189 : #endif
190 :
191 : /************************************************************************/
192 : /* ==================================================================== */
193 : /* PNGRasterBand */
194 : /* ==================================================================== */
195 : /************************************************************************/
196 :
197 : class PNGRasterBand final : public GDALPamRasterBand
198 : {
199 : friend class PNGDataset;
200 :
201 : public:
202 : PNGRasterBand(PNGDataset *, int);
203 :
204 50224 : virtual ~PNGRasterBand()
205 25112 : {
206 50224 : }
207 :
208 : virtual CPLErr IReadBlock(int, int, void *) override;
209 :
210 : virtual GDALSuggestedBlockAccessPattern
211 0 : GetSuggestedBlockAccessPattern() const override
212 : {
213 0 : return GSBAP_TOP_TO_BOTTOM;
214 : }
215 :
216 : virtual GDALColorInterp GetColorInterpretation() override;
217 : virtual GDALColorTable *GetColorTable() override;
218 : CPLErr SetNoDataValue(double dfNewValue) override;
219 : virtual double GetNoDataValue(int *pbSuccess = nullptr) override;
220 :
221 : virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
222 : GDALDataType, GSpacing, GSpacing,
223 : GDALRasterIOExtraArg *psExtraArg) override;
224 :
225 : int bHaveNoData;
226 : double dfNoDataValue;
227 :
228 : #ifdef SUPPORT_CREATE
229 : virtual CPLErr SetColorTable(GDALColorTable *);
230 : virtual CPLErr IWriteBlock(int, int, void *) override;
231 :
232 : protected:
233 : int m_bBandProvided[5];
234 :
235 : void reset_band_provision_flags()
236 : {
237 : PNGDataset &ds = *reinterpret_cast<PNGDataset *>(poDS);
238 :
239 : for (size_t i = 0; i < static_cast<size_t>(ds.nBands); i++)
240 : m_bBandProvided[i] = FALSE;
241 : }
242 : #endif
243 : };
|