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