/src/gdal/frmts/jpeg/jpgdataset.h
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * $Id: jpgdataset.cpp 37340 2017-02-11 18:28:02Z goatbar |
3 | | * |
4 | | * Project: JPEG JFIF Driver |
5 | | * Purpose: Implement GDAL JPEG Support based on IJG libjpeg. |
6 | | * Author: Frank Warmerdam, warmerdam@pobox.com |
7 | | * |
8 | | ****************************************************************************** |
9 | | * Copyright (c) 2000, Frank Warmerdam |
10 | | * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com> |
11 | | * |
12 | | * Portions Copyright (c) Her majesty the Queen in right of Canada as |
13 | | * represented by the Minister of National Defence, 2006. |
14 | | * |
15 | | * SPDX-License-Identifier: MIT |
16 | | ****************************************************************************/ |
17 | | |
18 | | #include "cpl_port.h" |
19 | | |
20 | | // TODO(schwehr): Run IWYU. |
21 | | #include <cerrno> |
22 | | #include <climits> |
23 | | #include <cstddef> |
24 | | #include <cstdio> |
25 | | #include <cstdlib> |
26 | | #include <cstring> |
27 | | #if HAVE_FCNTL_H |
28 | | #include <fcntl.h> |
29 | | #endif |
30 | | #include <setjmp.h> |
31 | | |
32 | | #include <algorithm> |
33 | | #include <mutex> |
34 | | #include <string> |
35 | | |
36 | | #include "cpl_conv.h" |
37 | | #include "cpl_error.h" |
38 | | #include "cpl_progress.h" |
39 | | #include "cpl_string.h" |
40 | | #include "cpl_vsi.h" |
41 | | #include "gdal.h" |
42 | | #include "gdal_frmts.h" |
43 | | #include "gdal_pam.h" |
44 | | #include "gdal_priv.h" |
45 | | |
46 | | CPL_C_START |
47 | | |
48 | | // So that D_LOSSLESS_SUPPORTED is visible if defined in jmorecfg of libjpeg-turbo >= 2.2 |
49 | | #define JPEG_INTERNAL_OPTIONS |
50 | | |
51 | | #ifdef LIBJPEG_12_PATH |
52 | | #include LIBJPEG_12_PATH |
53 | | #else |
54 | | #include "jpeglib.h" |
55 | | #endif |
56 | | CPL_C_END |
57 | | #include "memdataset.h" |
58 | | #include "vsidataio.h" |
59 | | |
60 | | // TIFF header. |
61 | | typedef struct |
62 | | { |
63 | | GUInt16 tiff_magic; // Magic number (defines byte order). |
64 | | GUInt16 tiff_version; // TIFF version number. |
65 | | GUInt32 tiff_diroff; // byte offset to first directory. |
66 | | } TIFFHeader; |
67 | | |
68 | | // Ok to use setjmp(). |
69 | | #ifdef _MSC_VER |
70 | | #pragma warning(disable : 4611) |
71 | | #endif |
72 | | |
73 | | struct JPGDatasetOpenArgs |
74 | | { |
75 | | const char *pszFilename = nullptr; |
76 | | VSILFILE *fpLin = nullptr; |
77 | | CSLConstList papszSiblingFiles = nullptr; |
78 | | int nScaleFactor = 1; |
79 | | bool bDoPAMInitialize = false; |
80 | | bool bUseInternalOverviews = false; |
81 | | bool bIsLossless = false; |
82 | | }; |
83 | | |
84 | | class JPGDatasetCommon; |
85 | | |
86 | | #if defined(JPEG_DUAL_MODE_8_12) && !defined(JPGDataset) |
87 | | JPGDatasetCommon *JPEGDataset12Open(JPGDatasetOpenArgs *psArgs); |
88 | | GDALDataset *JPEGDataset12CreateCopy(const char *pszFilename, |
89 | | GDALDataset *poSrcDS, int bStrict, |
90 | | char **papszOptions, |
91 | | GDALProgressFunc pfnProgress, |
92 | | void *pProgressData); |
93 | | #endif |
94 | | |
95 | | GDALRasterBand *JPGCreateBand(JPGDatasetCommon *poDS, int nBand); |
96 | | |
97 | | typedef void (*my_jpeg_write_m_header)(void *cinfo, int marker, |
98 | | unsigned int datalen); |
99 | | typedef void (*my_jpeg_write_m_byte)(void *cinfo, int val); |
100 | | |
101 | | CPLErr JPGAppendMask(const char *pszJPGFilename, GDALRasterBand *poMask, |
102 | | GDALProgressFunc pfnProgress, void *pProgressData); |
103 | | void JPGAddEXIF(GDALDataType eWorkDT, GDALDataset *poSrcDS, char **papszOptions, |
104 | | void *cinfo, my_jpeg_write_m_header p_jpeg_write_m_header, |
105 | | my_jpeg_write_m_byte p_jpeg_write_m_byte, |
106 | | GDALDataset *(pCreateCopy)(const char *, GDALDataset *, int, |
107 | | char **, |
108 | | GDALProgressFunc pfnProgress, |
109 | | void *pProgressData)); |
110 | | void JPGAddICCProfile(void *pInfo, const char *pszICCProfile, |
111 | | my_jpeg_write_m_header p_jpeg_write_m_header, |
112 | | my_jpeg_write_m_byte p_jpeg_write_m_byte); |
113 | | |
114 | | class GDALJPEGUserData |
115 | | { |
116 | | public: |
117 | | jmp_buf setjmp_buffer; |
118 | | bool bNonFatalErrorEncountered = false; |
119 | | void (*p_previous_emit_message)(j_common_ptr cinfo, |
120 | | int msg_level) = nullptr; |
121 | | int nMaxScans; |
122 | | |
123 | | GDALJPEGUserData() |
124 | 0 | : nMaxScans(atoi( |
125 | 0 | CPLGetConfigOption("GDAL_JPEG_MAX_ALLOWED_SCAN_NUMBER", "100"))) |
126 | 0 | { |
127 | 0 | memset(&setjmp_buffer, 0, sizeof(setjmp_buffer)); |
128 | 0 | } Unexecuted instantiation: GDALJPEGUserData::GDALJPEGUserData() Unexecuted instantiation: GDALJPEGUserData12::GDALJPEGUserData12() |
129 | | }; |
130 | | |
131 | | /************************************************************************/ |
132 | | /* ==================================================================== */ |
133 | | /* JPGDatasetCommon */ |
134 | | /* ==================================================================== */ |
135 | | /************************************************************************/ |
136 | | |
137 | | class JPGRasterBand; |
138 | | class JPGMaskBand; |
139 | | |
140 | | class JPGDatasetCommon CPL_NON_FINAL : public GDALPamDataset |
141 | | { |
142 | | protected: |
143 | | friend class JPGDataset; |
144 | | friend class JPGRasterBand; |
145 | | friend class JPGMaskBand; |
146 | | |
147 | | int nScaleFactor; |
148 | | bool bHasInitInternalOverviews; |
149 | | int nInternalOverviewsCurrent; |
150 | | int nInternalOverviewsToFree; |
151 | | GDALDataset **papoInternalOverviews; |
152 | | JPGDatasetCommon *poActiveDS = nullptr; /* only valid in parent DS */ |
153 | | JPGDatasetCommon **ppoActiveDS = |
154 | | nullptr; /* &poActiveDS of poActiveDS from parentDS */ |
155 | | void InitInternalOverviews(); |
156 | | GDALDataset *InitEXIFOverview(); |
157 | | |
158 | | mutable OGRSpatialReference m_oSRS{}; |
159 | | bool bGeoTransformValid; |
160 | | double adfGeoTransform[6]; |
161 | | std::vector<gdal::GCP> m_aoGCPs{}; |
162 | | |
163 | | VSILFILE *m_fpImage; |
164 | | GUIntBig nSubfileOffset; |
165 | | |
166 | | int nLoadedScanline; |
167 | | GByte *m_pabyScanline; |
168 | | |
169 | | bool bHasReadEXIFMetadata; |
170 | | bool bHasReadXMPMetadata; |
171 | | bool bHasReadICCMetadata; |
172 | | bool bHasReadFLIRMetadata = false; |
173 | | bool bHasReadImageStructureMetadata = false; |
174 | | char **papszMetadata; |
175 | | int nExifOffset; |
176 | | int nInterOffset; |
177 | | int nGPSOffset; |
178 | | bool bSwabflag; |
179 | | int nTiffDirStart; |
180 | | int nTIFFHEADER; |
181 | | bool bHasDoneJpegCreateDecompress; |
182 | | bool bHasDoneJpegStartDecompress; |
183 | | |
184 | | int m_nSubdatasetCount = 0; |
185 | | |
186 | | // FLIR raw thermal image |
187 | | bool m_bRawThermalLittleEndian = false; |
188 | | int m_nRawThermalImageWidth = 0; |
189 | | int m_nRawThermalImageHeight = 0; |
190 | | std::vector<GByte> m_abyRawThermalImage{}; |
191 | | |
192 | | virtual CPLErr LoadScanline(int, GByte *outBuffer = nullptr) = 0; |
193 | | virtual void StopDecompress() = 0; |
194 | | virtual CPLErr Restart() = 0; |
195 | | |
196 | | virtual int GetDataPrecision() = 0; |
197 | | virtual int GetOutColorSpace() = 0; |
198 | | virtual int GetJPEGColorSpace() = 0; |
199 | | |
200 | | bool EXIFInit(VSILFILE *); |
201 | | void ReadICCProfile(); |
202 | | |
203 | | void CheckForMask(); |
204 | | void DecompressMask(); |
205 | | |
206 | | void LoadForMetadataDomain(const char *pszDomain); |
207 | | |
208 | | void ReadImageStructureMetadata(); |
209 | | void ReadEXIFMetadata(); |
210 | | void ReadXMPMetadata(); |
211 | | void ReadFLIRMetadata(); |
212 | | GDALDataset *OpenFLIRRawThermalImage(); |
213 | | |
214 | | bool bHasCheckedForMask; |
215 | | JPGMaskBand *poMaskBand; |
216 | | GByte *pabyBitMask; |
217 | | bool bMaskLSBOrder; |
218 | | |
219 | | GByte *pabyCMask; |
220 | | int nCMaskSize; |
221 | | |
222 | | // Color space exposed by GDAL. Not necessarily the in_color_space nor |
223 | | // the out_color_space of JPEG library. |
224 | | /*J_COLOR_SPACE*/ int eGDALColorSpace; |
225 | | |
226 | | bool bIsSubfile; |
227 | | bool bHasTriedLoadWorldFileOrTab; |
228 | | void LoadWorldFileOrTab(); |
229 | | CPLString osWldFilename; |
230 | | |
231 | | virtual int CloseDependentDatasets() override; |
232 | | |
233 | | virtual CPLErr IBuildOverviews(const char *, int, const int *, int, |
234 | | const int *, GDALProgressFunc, void *, |
235 | | CSLConstList papszOptions) override; |
236 | | |
237 | | public: |
238 | | JPGDatasetCommon(); |
239 | | virtual ~JPGDatasetCommon(); |
240 | | |
241 | | virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int, |
242 | | GDALDataType, int, BANDMAP_TYPE, |
243 | | GSpacing nPixelSpace, GSpacing nLineSpace, |
244 | | GSpacing nBandSpace, |
245 | | GDALRasterIOExtraArg *psExtraArg) override; |
246 | | |
247 | | virtual CPLErr GetGeoTransform(double *) override; |
248 | | |
249 | | virtual int GetGCPCount() override; |
250 | | const OGRSpatialReference *GetGCPSpatialRef() const override; |
251 | | virtual const GDAL_GCP *GetGCPs() override; |
252 | | |
253 | | const OGRSpatialReference *GetSpatialRef() const override; |
254 | | |
255 | | virtual char **GetMetadataDomainList() override; |
256 | | virtual char **GetMetadata(const char *pszDomain = "") override; |
257 | | virtual const char *GetMetadataItem(const char *pszName, |
258 | | const char *pszDomain = "") override; |
259 | | |
260 | | virtual char **GetFileList(void) override; |
261 | | |
262 | | virtual CPLErr FlushCache(bool bAtClosing) override; |
263 | | |
264 | | CPLStringList GetCompressionFormats(int nXOff, int nYOff, int nXSize, |
265 | | int nYSize, int nBandCount, |
266 | | const int *panBandList) override; |
267 | | CPLErr ReadCompressedData(const char *pszFormat, int nXOff, int nYOff, |
268 | | int nXSize, int nYSize, int nBandCount, |
269 | | const int *panBandList, void **ppBuffer, |
270 | | size_t *pnBufferSize, |
271 | | char **ppszDetailedFormat) override; |
272 | | |
273 | | static GDALDataset *Open(GDALOpenInfo *); |
274 | | }; |
275 | | |
276 | | /************************************************************************/ |
277 | | /* ==================================================================== */ |
278 | | /* JPGDataset */ |
279 | | /* ==================================================================== */ |
280 | | /************************************************************************/ |
281 | | |
282 | | class JPGDataset final : public JPGDatasetCommon |
283 | | { |
284 | | GDALJPEGUserData sUserData; |
285 | | |
286 | | bool ErrorOutOnNonFatalError(); |
287 | | |
288 | | static void EmitMessage(j_common_ptr cinfo, int msg_level); |
289 | | static void ProgressMonitor(j_common_ptr cinfo); |
290 | | |
291 | | struct jpeg_decompress_struct sDInfo; |
292 | | struct jpeg_error_mgr sJErr; |
293 | | struct jpeg_progress_mgr sJProgress; |
294 | | |
295 | | virtual CPLErr LoadScanline(int, GByte *outBuffer) override; |
296 | | CPLErr StartDecompress(); |
297 | | virtual void StopDecompress() override; |
298 | | virtual CPLErr Restart() override; |
299 | | |
300 | | virtual int GetDataPrecision() override |
301 | 0 | { |
302 | 0 | return sDInfo.data_precision; |
303 | 0 | } Unexecuted instantiation: JPGDataset::GetDataPrecision() Unexecuted instantiation: JPGDataset12::GetDataPrecision() |
304 | | |
305 | | virtual int GetOutColorSpace() override |
306 | 0 | { |
307 | 0 | return sDInfo.out_color_space; |
308 | 0 | } Unexecuted instantiation: JPGDataset::GetOutColorSpace() Unexecuted instantiation: JPGDataset12::GetOutColorSpace() |
309 | | |
310 | | virtual int GetJPEGColorSpace() override |
311 | 0 | { |
312 | 0 | return sDInfo.jpeg_color_space; |
313 | 0 | } Unexecuted instantiation: JPGDataset::GetJPEGColorSpace() Unexecuted instantiation: JPGDataset12::GetJPEGColorSpace() |
314 | | |
315 | | int nQLevel; |
316 | | #if !defined(JPGDataset) |
317 | | void LoadDefaultTables(int); |
318 | | #endif |
319 | | void SetScaleNumAndDenom(); |
320 | | |
321 | | static JPGDatasetCommon *OpenStage2(JPGDatasetOpenArgs *psArgs, |
322 | | JPGDataset *&poDS); |
323 | | |
324 | | public: |
325 | | JPGDataset(); |
326 | | virtual ~JPGDataset(); |
327 | | |
328 | | static JPGDatasetCommon *Open(JPGDatasetOpenArgs *psArgs); |
329 | | static GDALDataset *CreateCopy(const char *pszFilename, |
330 | | GDALDataset *poSrcDS, int bStrict, |
331 | | char **papszOptions, |
332 | | GDALProgressFunc pfnProgress, |
333 | | void *pProgressData); |
334 | | static GDALDataset *CreateCopyStage2( |
335 | | const char *pszFilename, GDALDataset *poSrcDS, char **papszOptions, |
336 | | GDALProgressFunc pfnProgress, void *pProgressData, VSILFILE *fpImage, |
337 | | GDALDataType eDT, int nQuality, bool bAppendMask, |
338 | | GDALJPEGUserData &sUserData, struct jpeg_compress_struct &sCInfo, |
339 | | struct jpeg_error_mgr &sJErr, GByte *&pabyScanline); |
340 | | static void ErrorExit(j_common_ptr cinfo); |
341 | | static void OutputMessage(j_common_ptr cinfo); |
342 | | }; |
343 | | |
344 | | /************************************************************************/ |
345 | | /* ==================================================================== */ |
346 | | /* JPGRasterBand */ |
347 | | /* ==================================================================== */ |
348 | | /************************************************************************/ |
349 | | |
350 | | class JPGRasterBand final : public GDALPamRasterBand |
351 | | { |
352 | | friend class JPGDatasetCommon; |
353 | | |
354 | | // We have to keep a pointer to the JPGDataset that this JPGRasterBand |
355 | | // belongs to. In some case, we may have this->poGDS != this->poDS |
356 | | // For example for a JPGRasterBand that is set to a NITFDataset. |
357 | | // In other words, this->poDS doesn't necessary point to a JPGDataset |
358 | | // See ticket #1807. |
359 | | JPGDatasetCommon *poGDS; |
360 | | |
361 | | public: |
362 | | JPGRasterBand(JPGDatasetCommon *, int); |
363 | | |
364 | | virtual ~JPGRasterBand() |
365 | 0 | { |
366 | 0 | } |
367 | | |
368 | | virtual CPLErr IReadBlock(int, int, void *) override; |
369 | | virtual GDALColorInterp GetColorInterpretation() override; |
370 | | |
371 | | virtual GDALSuggestedBlockAccessPattern |
372 | | GetSuggestedBlockAccessPattern() const override |
373 | 0 | { |
374 | 0 | return GSBAP_TOP_TO_BOTTOM; |
375 | 0 | } |
376 | | |
377 | | virtual GDALRasterBand *GetMaskBand() override; |
378 | | virtual int GetMaskFlags() override; |
379 | | |
380 | | virtual GDALRasterBand *GetOverview(int i) override; |
381 | | virtual int GetOverviewCount() override; |
382 | | }; |
383 | | |
384 | | #if !defined(JPGDataset) |
385 | | |
386 | | /************************************************************************/ |
387 | | /* ==================================================================== */ |
388 | | /* JPGMaskBand */ |
389 | | /* ==================================================================== */ |
390 | | /************************************************************************/ |
391 | | |
392 | | class JPGMaskBand final : public GDALRasterBand |
393 | | { |
394 | | protected: |
395 | | virtual CPLErr IReadBlock(int, int, void *) override; |
396 | | |
397 | | public: |
398 | | explicit JPGMaskBand(JPGDatasetCommon *poDS); |
399 | | |
400 | | virtual ~JPGMaskBand() |
401 | 0 | { |
402 | 0 | } |
403 | | }; |
404 | | |
405 | | /************************************************************************/ |
406 | | /* GDALRegister_JPEG() */ |
407 | | /************************************************************************/ |
408 | | |
409 | | class GDALJPGDriver final : public GDALDriver |
410 | | { |
411 | | public: |
412 | 2 | GDALJPGDriver() = default; |
413 | | |
414 | | char **GetMetadata(const char *pszDomain = "") override; |
415 | | const char *GetMetadataItem(const char *pszName, |
416 | | const char *pszDomain = "") override; |
417 | | |
418 | | private: |
419 | | std::mutex m_oMutex{}; |
420 | | bool m_bMetadataInitialized = false; |
421 | | void InitializeMetadata(); |
422 | | }; |
423 | | |
424 | | #endif // !defined(JPGDataset) |