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 :
47 : #ifdef _MSC_VER
48 : #pragma warning(disable : 4611)
49 : #endif
50 :
51 : #ifdef USE_NEON_OPTIMIZATIONS
52 : #define HAVE_SSE2
53 : #include "include_sse2neon.h"
54 : #elif defined(__SSE2__) || defined(_M_X64) || \
55 : (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
56 : #define HAVE_SSE2
57 : #include <emmintrin.h>
58 : #endif
59 :
60 : #ifdef HAVE_SSE2
61 : #define ENABLE_WHOLE_IMAGE_OPTIMIZATION
62 : #endif
63 :
64 : /************************************************************************/
65 : /* ==================================================================== */
66 : /* PNGDataset */
67 : /* ==================================================================== */
68 : /************************************************************************/
69 :
70 : class PNGRasterBand;
71 :
72 : #ifdef _MSC_VER
73 : #pragma warning(push)
74 : // 'PNGDataset': structure was padded due to __declspec(align()) at line where
75 : // we use `jmp_buf`.
76 : #pragma warning(disable : 4324)
77 : #endif
78 :
79 : class PNGDataset final : public GDALPamDataset
80 : {
81 : friend class PNGRasterBand;
82 :
83 : VSILFILE *fpImage;
84 : png_structp hPNG;
85 : png_infop psPNGInfo;
86 : int nBitDepth;
87 : int nColorType; // PNG_COLOR_TYPE_*
88 : int bInterlaced;
89 :
90 : int nBufferStartLine;
91 : int nBufferLines;
92 : int nLastLineRead;
93 : GByte *pabyBuffer;
94 :
95 : GDALColorTable *poColorTable;
96 :
97 : int bGeoTransformValid;
98 : double adfGeoTransform[6];
99 :
100 : void CollectMetadata();
101 :
102 : int bHasReadXMPMetadata;
103 : void CollectXMPMetadata();
104 :
105 : CPLErr LoadScanline(int);
106 : CPLErr LoadInterlacedChunk(int);
107 : void Restart();
108 :
109 : int bHasTriedLoadWorldFile;
110 : void LoadWorldFile();
111 : CPLString osWldFilename;
112 :
113 : int bHasReadICCMetadata;
114 : void LoadICCProfile();
115 :
116 : static void WriteMetadataAsText(jmp_buf sSetJmpContext, png_structp hPNG,
117 : png_infop psPNGInfo, const char *pszKey,
118 : const char *pszValue);
119 : static GDALDataset *OpenStage2(GDALOpenInfo *, PNGDataset *&);
120 :
121 : public:
122 : PNGDataset();
123 : virtual ~PNGDataset();
124 :
125 : static GDALDataset *Open(GDALOpenInfo *);
126 : static GDALDataset *CreateCopy(const char *pszFilename,
127 : GDALDataset *poSrcDS, int bStrict,
128 : char **papszOptions,
129 : GDALProgressFunc pfnProgress,
130 : void *pProgressData);
131 :
132 : virtual char **GetFileList(void) override;
133 :
134 : virtual CPLErr GetGeoTransform(double *) override;
135 : virtual CPLErr FlushCache(bool bAtClosing) override;
136 :
137 : virtual char **GetMetadataDomainList() override;
138 :
139 : virtual char **GetMetadata(const char *pszDomain = "") override;
140 : virtual const char *
141 : GetMetadataItem(const char *pszName,
142 : const char *pszDomain = nullptr) override;
143 :
144 : virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
145 : GDALDataType, int, BANDMAP_TYPE, GSpacing,
146 : GSpacing, GSpacing,
147 : GDALRasterIOExtraArg *psExtraArg) override;
148 :
149 : #ifdef ENABLE_WHOLE_IMAGE_OPTIMIZATION
150 : bool IsCompatibleOfSingleBlock() const;
151 : CPLErr LoadWholeImage(void *pSingleBuffer, GSpacing nPixelSpace,
152 : GSpacing nLineSpace, GSpacing nBandSpace,
153 : void *apabyBuffers[4]);
154 : #endif
155 :
156 : jmp_buf sSetJmpContext; // Semi-private.
157 :
158 : #ifdef SUPPORT_CREATE
159 : int m_nBitDepth;
160 : GByte *m_pabyBuffer;
161 : png_byte *m_pabyAlpha;
162 : png_structp m_hPNG;
163 : png_infop m_psPNGInfo;
164 : png_color *m_pasPNGColors;
165 : VSILFILE *m_fpImage;
166 : int m_bGeoTransformValid;
167 : double m_adfGeoTransform[6];
168 : char *m_pszFilename;
169 : int m_nColorType; // PNG_COLOR_TYPE_*
170 :
171 : virtual CPLErr SetGeoTransform(double *);
172 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
173 : int nBands, GDALDataType, char **papszParamList);
174 :
175 : protected:
176 : CPLErr write_png_header();
177 :
178 : #endif
179 : };
180 :
181 : #ifdef _MSC_VER
182 : #pragma warning(pop)
183 : #endif
184 :
185 : /************************************************************************/
186 : /* ==================================================================== */
187 : /* PNGRasterBand */
188 : /* ==================================================================== */
189 : /************************************************************************/
190 :
191 : class PNGRasterBand final : public GDALPamRasterBand
192 : {
193 : friend class PNGDataset;
194 :
195 : public:
196 : PNGRasterBand(PNGDataset *, int);
197 :
198 39834 : virtual ~PNGRasterBand()
199 19917 : {
200 39834 : }
201 :
202 : virtual CPLErr IReadBlock(int, int, void *) override;
203 :
204 : virtual GDALSuggestedBlockAccessPattern
205 0 : GetSuggestedBlockAccessPattern() const override
206 : {
207 0 : return GSBAP_TOP_TO_BOTTOM;
208 : }
209 :
210 : virtual GDALColorInterp GetColorInterpretation() override;
211 : virtual GDALColorTable *GetColorTable() override;
212 : CPLErr SetNoDataValue(double dfNewValue) override;
213 : virtual double GetNoDataValue(int *pbSuccess = nullptr) override;
214 :
215 : virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
216 : GDALDataType, GSpacing, GSpacing,
217 : GDALRasterIOExtraArg *psExtraArg) override;
218 :
219 : int bHaveNoData;
220 : double dfNoDataValue;
221 :
222 : #ifdef SUPPORT_CREATE
223 : virtual CPLErr SetColorTable(GDALColorTable *);
224 : virtual CPLErr IWriteBlock(int, int, void *) override;
225 :
226 : protected:
227 : int m_bBandProvided[5];
228 :
229 : void reset_band_provision_flags()
230 : {
231 : PNGDataset &ds = *reinterpret_cast<PNGDataset *>(poDS);
232 :
233 : for (size_t i = 0; i < static_cast<size_t>(ds.nBands); i++)
234 : m_bBandProvided[i] = FALSE;
235 : }
236 : #endif
237 : };
|