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