Line data Source code
1 : /******************************************************************************
2 : * $Id$
3 : *
4 : * Project: PNG Driver
5 : * Purpose: Implement GDAL PNG Support
6 : * Author: Frank Warmerdam, warmerda@home.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2000, Frank Warmerdam
10 : * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ******************************************************************************
30 : *
31 : * ISSUES:
32 : * o CollectMetadata() will only capture TEXT chunks before the image
33 : * data as the code is currently structured.
34 : * o Interlaced images are read entirely into memory for use. This is
35 : * bad for large images.
36 : * o Image reading is always strictly sequential. Reading backwards will
37 : * cause the file to be rewound, and access started again from the
38 : * beginning.
39 : * o 16 bit alpha values are not scaled by to eight bit.
40 : *
41 : */
42 :
43 : #include "cpl_string.h"
44 : #include "gdal_frmts.h"
45 : #include "gdal_pam.h"
46 :
47 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
48 : // Disabled for now since currently this only works for libpng 1.2
49 : // libpng 1.6 requires additional includes. See #6928
50 : // #define DISABLE_CRC_CHECK
51 : #endif
52 :
53 : #ifdef DISABLE_CRC_CHECK
54 : // Needs to be defined before including png.h
55 : #define PNG_INTERNAL
56 : #endif
57 :
58 : #include "png.h"
59 :
60 : #include <csetjmp>
61 :
62 : #include <algorithm>
63 :
64 : #ifdef _MSC_VER
65 : #pragma warning(disable : 4611)
66 : #endif
67 :
68 : #if defined(__SSE2__) || defined(_M_X64) || \
69 : (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
70 : #define HAVE_SSE2
71 : #include <emmintrin.h>
72 : #endif
73 :
74 : #ifdef HAVE_SSE2
75 : #define ENABLE_WHOLE_IMAGE_OPTIMIZATION
76 : #endif
77 :
78 : /************************************************************************/
79 : /* ==================================================================== */
80 : /* PNGDataset */
81 : /* ==================================================================== */
82 : /************************************************************************/
83 :
84 : class PNGRasterBand;
85 :
86 : #ifdef _MSC_VER
87 : #pragma warning(push)
88 : // 'PNGDataset': structure was padded due to __declspec(align()) at line where
89 : // we use `jmp_buf`.
90 : #pragma warning(disable : 4324)
91 : #endif
92 :
93 : class PNGDataset final : public GDALPamDataset
94 : {
95 : friend class PNGRasterBand;
96 :
97 : VSILFILE *fpImage;
98 : png_structp hPNG;
99 : png_infop psPNGInfo;
100 : int nBitDepth;
101 : int nColorType; // PNG_COLOR_TYPE_*
102 : int bInterlaced;
103 :
104 : int nBufferStartLine;
105 : int nBufferLines;
106 : int nLastLineRead;
107 : GByte *pabyBuffer;
108 :
109 : GDALColorTable *poColorTable;
110 :
111 : int bGeoTransformValid;
112 : double adfGeoTransform[6];
113 :
114 : void CollectMetadata();
115 :
116 : int bHasReadXMPMetadata;
117 : void CollectXMPMetadata();
118 :
119 : CPLErr LoadScanline(int);
120 : CPLErr LoadInterlacedChunk(int);
121 : void Restart();
122 :
123 : int bHasTriedLoadWorldFile;
124 : void LoadWorldFile();
125 : CPLString osWldFilename;
126 :
127 : int bHasReadICCMetadata;
128 : void LoadICCProfile();
129 :
130 : static void WriteMetadataAsText(jmp_buf sSetJmpContext, png_structp hPNG,
131 : png_infop psPNGInfo, const char *pszKey,
132 : const char *pszValue);
133 : static GDALDataset *OpenStage2(GDALOpenInfo *, PNGDataset *&);
134 :
135 : public:
136 : PNGDataset();
137 : virtual ~PNGDataset();
138 :
139 : static GDALDataset *Open(GDALOpenInfo *);
140 : static GDALDataset *CreateCopy(const char *pszFilename,
141 : GDALDataset *poSrcDS, int bStrict,
142 : char **papszOptions,
143 : GDALProgressFunc pfnProgress,
144 : void *pProgressData);
145 :
146 : virtual char **GetFileList(void) override;
147 :
148 : virtual CPLErr GetGeoTransform(double *) override;
149 : virtual CPLErr FlushCache(bool bAtClosing) override;
150 :
151 : virtual char **GetMetadataDomainList() override;
152 :
153 : virtual char **GetMetadata(const char *pszDomain = "") override;
154 : virtual const char *
155 : GetMetadataItem(const char *pszName,
156 : const char *pszDomain = nullptr) override;
157 :
158 : virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
159 : GDALDataType, int, int *, GSpacing, GSpacing,
160 : GSpacing,
161 : GDALRasterIOExtraArg *psExtraArg) override;
162 :
163 : #ifdef ENABLE_WHOLE_IMAGE_OPTIMIZATION
164 : bool IsCompatibleOfSingleBlock() const;
165 : CPLErr LoadWholeImage(void *pSingleBuffer, GSpacing nPixelSpace,
166 : GSpacing nLineSpace, GSpacing nBandSpace,
167 : void *apabyBuffers[4]);
168 : #endif
169 :
170 : jmp_buf sSetJmpContext; // Semi-private.
171 :
172 : #ifdef SUPPORT_CREATE
173 : int m_nBitDepth;
174 : GByte *m_pabyBuffer;
175 : png_byte *m_pabyAlpha;
176 : png_structp m_hPNG;
177 : png_infop m_psPNGInfo;
178 : png_color *m_pasPNGColors;
179 : VSILFILE *m_fpImage;
180 : int m_bGeoTransformValid;
181 : double m_adfGeoTransform[6];
182 : char *m_pszFilename;
183 : int m_nColorType; // PNG_COLOR_TYPE_*
184 :
185 : virtual CPLErr SetGeoTransform(double *);
186 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
187 : int nBands, GDALDataType, char **papszParamList);
188 :
189 : protected:
190 : CPLErr write_png_header();
191 :
192 : #endif
193 : };
194 :
195 : #ifdef _MSC_VER
196 : #pragma warning(pop)
197 : #endif
198 :
199 : /************************************************************************/
200 : /* ==================================================================== */
201 : /* PNGRasterBand */
202 : /* ==================================================================== */
203 : /************************************************************************/
204 :
205 : class PNGRasterBand final : public GDALPamRasterBand
206 : {
207 : friend class PNGDataset;
208 :
209 : public:
210 : PNGRasterBand(PNGDataset *, int);
211 :
212 38438 : virtual ~PNGRasterBand()
213 19219 : {
214 38438 : }
215 :
216 : virtual CPLErr IReadBlock(int, int, void *) override;
217 :
218 : virtual GDALSuggestedBlockAccessPattern
219 0 : GetSuggestedBlockAccessPattern() const override
220 : {
221 0 : return GSBAP_TOP_TO_BOTTOM;
222 : }
223 :
224 : virtual GDALColorInterp GetColorInterpretation() override;
225 : virtual GDALColorTable *GetColorTable() override;
226 : CPLErr SetNoDataValue(double dfNewValue) override;
227 : virtual double GetNoDataValue(int *pbSuccess = nullptr) override;
228 :
229 : virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
230 : GDALDataType, GSpacing, GSpacing,
231 : GDALRasterIOExtraArg *psExtraArg) override;
232 :
233 : int bHaveNoData;
234 : double dfNoDataValue;
235 :
236 : #ifdef SUPPORT_CREATE
237 : virtual CPLErr SetColorTable(GDALColorTable *);
238 : virtual CPLErr IWriteBlock(int, int, void *) override;
239 :
240 : protected:
241 : int m_bBandProvided[5];
242 :
243 : void reset_band_provision_flags()
244 : {
245 : PNGDataset &ds = *reinterpret_cast<PNGDataset *>(poDS);
246 :
247 : for (size_t i = 0; i < static_cast<size_t>(ds.nBands); i++)
248 : m_bBandProvided[i] = FALSE;
249 : }
250 : #endif
251 : };
|