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