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