Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GeoTIFF Driver
4 : * Purpose: Specialized copy of JPEG content into TIFF.
5 : * Author: Even Rouault, <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2012, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "cpl_port.h"
30 :
31 : #include "gt_jpeg_copy.h"
32 :
33 : #include "cpl_vsi.h"
34 :
35 : #if defined(JPEG_DIRECT_COPY) || defined(HAVE_LIBJPEG)
36 : #include "vrt/vrtdataset.h"
37 : #endif
38 :
39 : #include <algorithm>
40 :
41 : // Note: JPEG_DIRECT_COPY is not defined by default, because it is mainly
42 : // useful for debugging purposes.
43 :
44 : #if defined(JPEG_DIRECT_COPY) || defined(HAVE_LIBJPEG)
45 :
46 : /************************************************************************/
47 : /* GetUnderlyingDataset() */
48 : /************************************************************************/
49 :
50 1080 : static GDALDataset *GetUnderlyingDataset(GDALDataset *poSrcDS)
51 : {
52 : // Test if we can directly copy original JPEG content if available.
53 1080 : if (auto poVRTDS = dynamic_cast<VRTDataset *>(poSrcDS))
54 : {
55 345 : poSrcDS = poVRTDS->GetSingleSimpleSource();
56 : }
57 :
58 1080 : return poSrcDS;
59 : }
60 :
61 : #endif // defined(JPEG_DIRECT_COPY) || defined(HAVE_LIBJPEG)
62 :
63 : #ifdef JPEG_DIRECT_COPY
64 :
65 : /************************************************************************/
66 : /* IsBaselineDCTJPEG() */
67 : /************************************************************************/
68 :
69 : static bool IsBaselineDCTJPEG(VSILFILE *fp)
70 : {
71 : GByte abyBuf[4] = {0};
72 :
73 : if (VSIFReadL(abyBuf, 1, 2, fp) != 2 || abyBuf[0] != 0xff ||
74 : abyBuf[1] != 0xd8)
75 : {
76 : CPLError(CE_Failure, CPLE_AppDefined, "Not a valid JPEG file");
77 : return false;
78 : }
79 :
80 : int nOffset = 2;
81 : while (true)
82 : {
83 : VSIFSeekL(fp, nOffset, SEEK_SET);
84 : if (VSIFReadL(abyBuf, 1, 4, fp) != 4 || abyBuf[0] != 0xFF)
85 : {
86 : CPLError(CE_Failure, CPLE_AppDefined, "Not a valid JPEG file");
87 : return false;
88 : }
89 :
90 : const int nMarker = abyBuf[1];
91 :
92 : // Start of Frame 0 = Baseline DCT.
93 : if (nMarker == 0xC0)
94 : return true;
95 :
96 : if (nMarker == 0xD9)
97 : return false;
98 :
99 : if (nMarker == 0xF7 || // JPEG Extension 7, JPEG-LS
100 : nMarker == 0xF8 || // JPEG Extension 8, JPEG-LS Extension.
101 : // Other Start of Frames that we don't want to support.
102 : (nMarker >= 0xC1 && nMarker <= 0xCF))
103 : {
104 : CPLError(CE_Failure, CPLE_AppDefined,
105 : "Unsupported type of JPEG file for JPEG_DIRECT_COPY mode");
106 : return false;
107 : }
108 :
109 : nOffset += 2 + abyBuf[2] * 256 + abyBuf[3];
110 : }
111 : }
112 :
113 : /************************************************************************/
114 : /* GTIFF_CanDirectCopyFromJPEG() */
115 : /************************************************************************/
116 :
117 : int GTIFF_CanDirectCopyFromJPEG(GDALDataset *poSrcDS,
118 : char **&papszCreateOptions)
119 : {
120 : poSrcDS = GetUnderlyingDataset(poSrcDS);
121 : if (poSrcDS == NULL)
122 : return FALSE;
123 : if (poSrcDS->GetDriver() == NULL)
124 : return FALSE;
125 : if (!EQUAL(GDALGetDriverShortName(poSrcDS->GetDriver()), "JPEG"))
126 : return FALSE;
127 :
128 : const char *pszCompress = CSLFetchNameValue(papszCreateOptions, "COMPRESS");
129 : if (pszCompress != NULL && !EQUAL(pszCompress, "JPEG"))
130 : return FALSE;
131 :
132 : const char *pszSrcColorSpace =
133 : poSrcDS->GetMetadataItem("SOURCE_COLOR_SPACE", "IMAGE_STRUCTURE");
134 : if (pszSrcColorSpace != NULL &&
135 : (EQUAL(pszSrcColorSpace, "CMYK") || EQUAL(pszSrcColorSpace, "YCbCrK")))
136 : return FALSE;
137 :
138 : bool bJPEGDirectCopy = false;
139 :
140 : VSILFILE *fpJPEG = VSIFOpenL(poSrcDS->GetDescription(), "rb");
141 : if (fpJPEG && IsBaselineDCTJPEG(fpJPEG))
142 : {
143 : bJPEGDirectCopy = true;
144 :
145 : if (pszCompress == NULL)
146 : papszCreateOptions =
147 : CSLSetNameValue(papszCreateOptions, "COMPRESS", "JPEG");
148 :
149 : papszCreateOptions =
150 : CSLSetNameValue(papszCreateOptions, "BLOCKXSIZE", NULL);
151 : papszCreateOptions =
152 : CSLSetNameValue(papszCreateOptions, "BLOCKYSIZE",
153 : CPLSPrintf("%d", poSrcDS->GetRasterYSize()));
154 :
155 : if (pszSrcColorSpace != NULL && EQUAL(pszSrcColorSpace, "YCbCr"))
156 : papszCreateOptions =
157 : CSLSetNameValue(papszCreateOptions, "PHOTOMETRIC", "YCBCR");
158 : else
159 : papszCreateOptions =
160 : CSLSetNameValue(papszCreateOptions, "PHOTOMETRIC", NULL);
161 :
162 : if (poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte)
163 : papszCreateOptions =
164 : CSLSetNameValue(papszCreateOptions, "NBITS", "12");
165 : else
166 : papszCreateOptions =
167 : CSLSetNameValue(papszCreateOptions, "NBITS", NULL);
168 :
169 : papszCreateOptions = CSLSetNameValue(papszCreateOptions, "TILED", NULL);
170 : papszCreateOptions =
171 : CSLSetNameValue(papszCreateOptions, "JPEG_QUALITY", NULL);
172 : }
173 : if (fpJPEG)
174 : {
175 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpJPEG));
176 : }
177 :
178 : return bJPEGDirectCopy;
179 : }
180 :
181 : /************************************************************************/
182 : /* GTIFF_DirectCopyFromJPEG() */
183 : /************************************************************************/
184 :
185 : CPLErr GTIFF_DirectCopyFromJPEG(GDALDataset *poDS, GDALDataset *poSrcDS,
186 : GDALProgressFunc pfnProgress,
187 : void *pProgressData,
188 : bool &bShouldFallbackToNormalCopyIfFail)
189 : {
190 : bShouldFallbackToNormalCopyIfFail = true;
191 :
192 : poSrcDS = GetUnderlyingDataset(poSrcDS);
193 : if (poSrcDS == NULL)
194 : return CE_Failure;
195 :
196 : VSILFILE *fpJPEG = VSIFOpenL(poSrcDS->GetDescription(), "rb");
197 : if (fpJPEG == NULL)
198 : return CE_Failure;
199 :
200 : CPLErr eErr = CE_None;
201 :
202 : VSIFSeekL(fpJPEG, 0, SEEK_END);
203 : tmsize_t nSize = static_cast<tmsize_t>(VSIFTellL(fpJPEG));
204 : VSIFSeekL(fpJPEG, 0, SEEK_SET);
205 :
206 : void *pabyJPEGData = VSIMalloc(nSize);
207 : if (pabyJPEGData == NULL)
208 : {
209 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpJPEG));
210 : return CE_Failure;
211 : }
212 :
213 : if (pabyJPEGData != NULL && static_cast<tmsize_t>(VSIFReadL(
214 : pabyJPEGData, 1, nSize, fpJPEG)) == nSize)
215 : {
216 : bShouldFallbackToNormalCopyIfFail = false;
217 :
218 : TIFF *hTIFF = (TIFF *)poDS->GetInternalHandle(NULL);
219 : if (TIFFWriteRawStrip(hTIFF, 0, pabyJPEGData, nSize) != nSize)
220 : eErr = CE_Failure;
221 :
222 : if (!pfnProgress(1.0, NULL, pProgressData))
223 : eErr = CE_Failure;
224 : }
225 : else
226 : {
227 : eErr = CE_Failure;
228 : }
229 :
230 : VSIFree(pabyJPEGData);
231 : if (VSIFCloseL(fpJPEG) != 0)
232 : eErr = CE_Failure;
233 :
234 : return eErr;
235 : }
236 :
237 : #endif // JPEG_DIRECT_COPY
238 :
239 : #ifdef HAVE_LIBJPEG
240 :
241 : #define jpeg_vsiio_src GTIFF_jpeg_vsiio_src
242 : #define jpeg_vsiio_dest GTIFF_jpeg_vsiio_dest
243 : #include "../jpeg/vsidataio.h"
244 : #include "../jpeg/vsidataio.cpp"
245 :
246 : #include <setjmp.h>
247 :
248 : /*
249 : * We are using width_in_blocks which is supposed to be private to
250 : * libjpeg. Unfortunately, the libjpeg delivered with Cygwin has
251 : * renamed this member to width_in_data_units. Since the header has
252 : * also renamed a define, use that unique define name in order to
253 : * detect the problem header and adjust to suit.
254 : */
255 : #if defined(D_MAX_DATA_UNITS_IN_MCU)
256 : #define width_in_blocks width_in_data_units
257 : #endif
258 :
259 : #ifdef EXPECTED_JPEG_LIB_VERSION
260 : #if EXPECTED_JPEG_LIB_VERSION != JPEG_LIB_VERSION
261 : #error EXPECTED_JPEG_LIB_VERSION != JPEG_LIB_VERSION
262 : #endif
263 : #endif
264 :
265 : /************************************************************************/
266 : /* GTIFF_CanCopyFromJPEG() */
267 : /************************************************************************/
268 :
269 1056 : int GTIFF_CanCopyFromJPEG(GDALDataset *poSrcDS, char **&papszCreateOptions)
270 : {
271 1056 : poSrcDS = GetUnderlyingDataset(poSrcDS);
272 1056 : if (poSrcDS == nullptr)
273 245 : return FALSE;
274 811 : if (poSrcDS->GetDriver() == nullptr)
275 67 : return FALSE;
276 744 : if (!EQUAL(GDALGetDriverShortName(poSrcDS->GetDriver()), "JPEG"))
277 730 : return FALSE;
278 :
279 14 : const char *pszCompress = CSLFetchNameValue(papszCreateOptions, "COMPRESS");
280 14 : if (pszCompress == nullptr || !EQUAL(pszCompress, "JPEG"))
281 1 : return FALSE;
282 :
283 : const int nBlockXSize =
284 13 : atoi(CSLFetchNameValueDef(papszCreateOptions, "BLOCKXSIZE", "0"));
285 : const int nBlockYSize =
286 13 : atoi(CSLFetchNameValueDef(papszCreateOptions, "BLOCKYSIZE", "0"));
287 13 : int nMCUSize = 8;
288 : const char *pszSrcColorSpace =
289 13 : poSrcDS->GetMetadataItem("SOURCE_COLOR_SPACE", "IMAGE_STRUCTURE");
290 13 : if (pszSrcColorSpace != nullptr && EQUAL(pszSrcColorSpace, "YCbCr"))
291 5 : nMCUSize = 16;
292 :
293 13 : const int nXSize = poSrcDS->GetRasterXSize();
294 13 : const int nYSize = poSrcDS->GetRasterYSize();
295 13 : const int nBands = poSrcDS->GetRasterCount();
296 :
297 : const char *pszPhotometric =
298 13 : CSLFetchNameValue(papszCreateOptions, "PHOTOMETRIC");
299 :
300 : const bool bCompatiblePhotometric =
301 2 : pszPhotometric == nullptr ||
302 2 : (nMCUSize == 16 && EQUAL(pszPhotometric, "YCbCr")) ||
303 2 : (nMCUSize == 8 && nBands == 4 &&
304 2 : poSrcDS->GetRasterBand(1)->GetColorInterpretation() == GCI_CyanBand &&
305 2 : poSrcDS->GetRasterBand(2)->GetColorInterpretation() ==
306 2 : GCI_MagentaBand &&
307 2 : poSrcDS->GetRasterBand(3)->GetColorInterpretation() ==
308 2 : GCI_YellowBand &&
309 2 : poSrcDS->GetRasterBand(4)->GetColorInterpretation() ==
310 0 : GCI_BlackBand) ||
311 15 : (nMCUSize == 8 && EQUAL(pszPhotometric, "RGB") && nBands == 3) ||
312 0 : (nMCUSize == 8 && EQUAL(pszPhotometric, "MINISBLACK") && nBands == 1);
313 13 : if (!bCompatiblePhotometric)
314 0 : return FALSE;
315 :
316 3 : if (nBands == 4 && pszPhotometric == nullptr &&
317 1 : poSrcDS->GetRasterBand(1)->GetColorInterpretation() == GCI_CyanBand &&
318 1 : poSrcDS->GetRasterBand(2)->GetColorInterpretation() ==
319 1 : GCI_MagentaBand &&
320 17 : poSrcDS->GetRasterBand(3)->GetColorInterpretation() == GCI_YellowBand &&
321 1 : poSrcDS->GetRasterBand(4)->GetColorInterpretation() == GCI_BlackBand)
322 : {
323 1 : papszCreateOptions =
324 1 : CSLSetNameValue(papszCreateOptions, "PHOTOMETRIC", "CMYK");
325 : }
326 :
327 : const char *pszInterleave =
328 13 : CSLFetchNameValue(papszCreateOptions, "INTERLEAVE");
329 :
330 13 : const bool bCompatibleInterleave =
331 2 : pszInterleave == nullptr ||
332 15 : (nBands > 1 && EQUAL(pszInterleave, "PIXEL")) || nBands == 1;
333 13 : if (!bCompatibleInterleave)
334 1 : return FALSE;
335 :
336 : // We don't want to apply lossy JPEG on a source using lossless JPEG !
337 24 : const char *pszReversibility = poSrcDS->GetMetadataItem(
338 12 : "COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE");
339 12 : if (pszReversibility && EQUAL(pszReversibility, "LOSSLESS"))
340 0 : return FALSE;
341 :
342 12 : if ((nBlockXSize == nXSize || (nBlockXSize % nMCUSize) == 0) &&
343 9 : (nBlockYSize == nYSize || (nBlockYSize % nMCUSize) == 0) &&
344 12 : poSrcDS->GetRasterBand(1)->GetRasterDataType() == GDT_Byte &&
345 36 : CSLFetchNameValue(papszCreateOptions, "NBITS") == nullptr &&
346 12 : CSLFetchNameValue(papszCreateOptions, "JPEG_QUALITY") == nullptr)
347 : {
348 12 : if (nMCUSize == 16 && pszPhotometric == nullptr)
349 4 : papszCreateOptions =
350 4 : CSLSetNameValue(papszCreateOptions, "PHOTOMETRIC", "YCBCR");
351 12 : return TRUE;
352 : }
353 :
354 0 : return FALSE;
355 : }
356 :
357 : /************************************************************************/
358 : /* GTIFF_ErrorExitJPEG() */
359 : /************************************************************************/
360 :
361 0 : static void GTIFF_ErrorExitJPEG(j_common_ptr cinfo)
362 : {
363 0 : jmp_buf *setjmp_buffer = static_cast<jmp_buf *>(cinfo->client_data);
364 0 : char buffer[JMSG_LENGTH_MAX] = {'\0'};
365 :
366 : // Create the message.
367 0 : (*cinfo->err->format_message)(cinfo, buffer);
368 :
369 0 : CPLError(CE_Failure, CPLE_AppDefined, "libjpeg: %s", buffer);
370 :
371 : // Return control to the setjmp point.
372 0 : longjmp(*setjmp_buffer, 1);
373 : }
374 :
375 : /************************************************************************/
376 : /* GTIFF_Set_TIFFTAG_JPEGTABLES() */
377 : /************************************************************************/
378 :
379 12 : static void GTIFF_Set_TIFFTAG_JPEGTABLES(TIFF *hTIFF,
380 : jpeg_decompress_struct &sDInfo,
381 : jpeg_compress_struct &sCInfo)
382 : {
383 12 : char szTmpFilename[128] = {'\0'};
384 12 : snprintf(szTmpFilename, sizeof(szTmpFilename), "/vsimem/tables_%p",
385 : &sDInfo);
386 12 : VSILFILE *fpTABLES = VSIFOpenL(szTmpFilename, "wb+");
387 :
388 12 : uint16_t nPhotometric = 0;
389 12 : TIFFGetField(hTIFF, TIFFTAG_PHOTOMETRIC, &nPhotometric);
390 :
391 12 : jpeg_vsiio_dest(&sCInfo, fpTABLES);
392 :
393 : // Avoid unnecessary tables to be emitted.
394 12 : if (nPhotometric != PHOTOMETRIC_YCBCR)
395 : {
396 8 : JQUANT_TBL *qtbl = sCInfo.quant_tbl_ptrs[1];
397 8 : if (qtbl != nullptr)
398 8 : qtbl->sent_table = TRUE;
399 8 : JHUFF_TBL *htbl = sCInfo.dc_huff_tbl_ptrs[1];
400 8 : if (htbl != nullptr)
401 8 : htbl->sent_table = TRUE;
402 8 : htbl = sCInfo.ac_huff_tbl_ptrs[1];
403 8 : if (htbl != nullptr)
404 8 : htbl->sent_table = TRUE;
405 : }
406 12 : jpeg_write_tables(&sCInfo);
407 :
408 12 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTABLES));
409 :
410 12 : vsi_l_offset nSizeTables = 0;
411 : GByte *pabyJPEGTablesData =
412 12 : VSIGetMemFileBuffer(szTmpFilename, &nSizeTables, FALSE);
413 12 : TIFFSetField(hTIFF, TIFFTAG_JPEGTABLES, static_cast<int>(nSizeTables),
414 : pabyJPEGTablesData);
415 :
416 12 : VSIUnlink(szTmpFilename);
417 12 : }
418 :
419 : /************************************************************************/
420 : /* GTIFF_CopyFromJPEG_WriteAdditionalTags() */
421 : /************************************************************************/
422 :
423 12 : CPLErr GTIFF_CopyFromJPEG_WriteAdditionalTags(TIFF *hTIFF, GDALDataset *poSrcDS)
424 : {
425 12 : poSrcDS = GetUnderlyingDataset(poSrcDS);
426 12 : if (poSrcDS == nullptr)
427 0 : return CE_Failure;
428 :
429 : /* -------------------------------------------------------------------- */
430 : /* Write TIFFTAG_JPEGTABLES */
431 : /* -------------------------------------------------------------------- */
432 :
433 12 : VSILFILE *fpJPEG = VSIFOpenL(poSrcDS->GetDescription(), "rb");
434 12 : if (fpJPEG == nullptr)
435 0 : return CE_Failure;
436 :
437 : struct jpeg_error_mgr sJErr;
438 : struct jpeg_decompress_struct sDInfo;
439 : jmp_buf setjmp_buffer;
440 :
441 12 : volatile bool bCallDestroyDecompress = false;
442 12 : volatile bool bCallDestroyCompress = false;
443 :
444 : struct jpeg_compress_struct sCInfo;
445 :
446 12 : if (setjmp(setjmp_buffer))
447 : {
448 0 : if (bCallDestroyCompress)
449 : {
450 0 : jpeg_abort_compress(&sCInfo);
451 0 : jpeg_destroy_compress(&sCInfo);
452 : }
453 0 : if (bCallDestroyDecompress)
454 : {
455 0 : jpeg_abort_decompress(&sDInfo);
456 0 : jpeg_destroy_decompress(&sDInfo);
457 : }
458 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpJPEG));
459 0 : return CE_Failure;
460 : }
461 :
462 12 : sDInfo.err = jpeg_std_error(&sJErr);
463 12 : sJErr.error_exit = GTIFF_ErrorExitJPEG;
464 12 : sDInfo.client_data = &setjmp_buffer;
465 :
466 12 : bCallDestroyDecompress = true;
467 12 : jpeg_CreateDecompress(&sDInfo, JPEG_LIB_VERSION, sizeof(sDInfo));
468 :
469 12 : jpeg_vsiio_src(&sDInfo, fpJPEG);
470 12 : jpeg_read_header(&sDInfo, TRUE);
471 :
472 12 : sCInfo.err = jpeg_std_error(&sJErr);
473 12 : sJErr.error_exit = GTIFF_ErrorExitJPEG;
474 12 : sCInfo.client_data = &setjmp_buffer;
475 :
476 12 : jpeg_CreateCompress(&sCInfo, JPEG_LIB_VERSION, sizeof(sCInfo));
477 12 : bCallDestroyCompress = true;
478 12 : jpeg_copy_critical_parameters(&sDInfo, &sCInfo);
479 12 : GTIFF_Set_TIFFTAG_JPEGTABLES(hTIFF, sDInfo, sCInfo);
480 12 : bCallDestroyCompress = false;
481 12 : jpeg_abort_compress(&sCInfo);
482 12 : jpeg_destroy_compress(&sCInfo);
483 12 : CPL_IGNORE_RET_VAL(bCallDestroyCompress);
484 :
485 : /* -------------------------------------------------------------------- */
486 : /* Write TIFFTAG_REFERENCEBLACKWHITE if needed. */
487 : /* -------------------------------------------------------------------- */
488 :
489 12 : uint16_t nPhotometric = 0;
490 12 : if (!TIFFGetField(hTIFF, TIFFTAG_PHOTOMETRIC, &(nPhotometric)))
491 0 : nPhotometric = PHOTOMETRIC_MINISBLACK;
492 :
493 12 : uint16_t nBitsPerSample = 0;
494 12 : if (!TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &(nBitsPerSample)))
495 0 : nBitsPerSample = 1;
496 :
497 12 : if (nPhotometric == PHOTOMETRIC_YCBCR)
498 : {
499 : /*
500 : * A ReferenceBlackWhite field *must* be present since the
501 : * default value is inappropriate for YCbCr. Fill in the
502 : * proper value if application didn't set it.
503 : */
504 4 : float *ref = nullptr;
505 4 : if (!TIFFGetField(hTIFF, TIFFTAG_REFERENCEBLACKWHITE, &ref))
506 : {
507 0 : long top = 1L << nBitsPerSample;
508 0 : float refbw[6] = {0.0};
509 0 : refbw[1] = static_cast<float>(top - 1L);
510 0 : refbw[2] = static_cast<float>(top >> 1);
511 0 : refbw[3] = refbw[1];
512 0 : refbw[4] = refbw[2];
513 0 : refbw[5] = refbw[1];
514 0 : TIFFSetField(hTIFF, TIFFTAG_REFERENCEBLACKWHITE, refbw);
515 : }
516 : }
517 :
518 : /* -------------------------------------------------------------------- */
519 : /* Write TIFFTAG_YCBCRSUBSAMPLING if needed. */
520 : /* -------------------------------------------------------------------- */
521 :
522 12 : if (nPhotometric == PHOTOMETRIC_YCBCR && sDInfo.num_components == 3)
523 : {
524 4 : if ((sDInfo.comp_info[0].h_samp_factor == 1 ||
525 4 : sDInfo.comp_info[0].h_samp_factor == 2) &&
526 4 : (sDInfo.comp_info[0].v_samp_factor == 1 ||
527 4 : sDInfo.comp_info[0].v_samp_factor == 2) &&
528 4 : sDInfo.comp_info[1].h_samp_factor == 1 &&
529 4 : sDInfo.comp_info[1].v_samp_factor == 1 &&
530 4 : sDInfo.comp_info[2].h_samp_factor == 1 &&
531 4 : sDInfo.comp_info[2].v_samp_factor == 1)
532 : {
533 4 : TIFFSetField(hTIFF, TIFFTAG_YCBCRSUBSAMPLING,
534 4 : sDInfo.comp_info[0].h_samp_factor,
535 4 : sDInfo.comp_info[0].v_samp_factor);
536 : }
537 : else
538 : {
539 0 : CPLDebug("GTiff", "Unusual sampling factors. "
540 : "TIFFTAG_YCBCRSUBSAMPLING not written.");
541 : }
542 : }
543 :
544 : /* -------------------------------------------------------------------- */
545 : /* Cleanup. */
546 : /* -------------------------------------------------------------------- */
547 :
548 12 : bCallDestroyDecompress = false;
549 12 : jpeg_abort_decompress(&sDInfo);
550 12 : jpeg_destroy_decompress(&sDInfo);
551 12 : CPL_IGNORE_RET_VAL(bCallDestroyDecompress);
552 :
553 12 : if (VSIFCloseL(fpJPEG) != 0)
554 0 : return CE_Failure;
555 :
556 12 : return CE_None;
557 : }
558 :
559 : /************************************************************************/
560 : /* GTIFF_CopyBlockFromJPEG() */
561 : /************************************************************************/
562 :
563 : typedef struct
564 : {
565 : TIFF *hTIFF;
566 : jpeg_decompress_struct *psDInfo;
567 : int iX;
568 : int iY;
569 : int nXBlocks;
570 : int nXSize;
571 : int nYSize;
572 : int nBlockXSize;
573 : int nBlockYSize;
574 : int iMCU_sample_width;
575 : int iMCU_sample_height;
576 : jvirt_barray_ptr *pSrcCoeffs;
577 : } GTIFF_CopyBlockFromJPEGArgs;
578 :
579 45 : static CPLErr GTIFF_CopyBlockFromJPEG(GTIFF_CopyBlockFromJPEGArgs *psArgs)
580 : {
581 90 : CPLString osTmpFilename(CPLSPrintf("/vsimem/%p", psArgs->psDInfo));
582 45 : VSILFILE *fpMEM = VSIFOpenL(osTmpFilename, "wb+");
583 :
584 : /* -------------------------------------------------------------------- */
585 : /* Initialization of the compressor */
586 : /* -------------------------------------------------------------------- */
587 : jmp_buf setjmp_buffer;
588 45 : if (setjmp(setjmp_buffer))
589 : {
590 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpMEM));
591 0 : VSIUnlink(osTmpFilename);
592 0 : return CE_Failure;
593 : }
594 :
595 45 : TIFF *hTIFF = psArgs->hTIFF;
596 45 : jpeg_decompress_struct *psDInfo = psArgs->psDInfo;
597 45 : const int iX = psArgs->iX;
598 45 : const int iY = psArgs->iY;
599 45 : const int nXBlocks = psArgs->nXBlocks;
600 45 : const int nXSize = psArgs->nXSize;
601 45 : const int nYSize = psArgs->nYSize;
602 45 : const int nBlockXSize = psArgs->nBlockXSize;
603 45 : const int nBlockYSize = psArgs->nBlockYSize;
604 45 : const int iMCU_sample_width = psArgs->iMCU_sample_width;
605 45 : const int iMCU_sample_height = psArgs->iMCU_sample_height;
606 45 : jvirt_barray_ptr *pSrcCoeffs = psArgs->pSrcCoeffs;
607 :
608 : struct jpeg_error_mgr sJErr;
609 : struct jpeg_compress_struct sCInfo;
610 45 : sCInfo.err = jpeg_std_error(&sJErr);
611 45 : sJErr.error_exit = GTIFF_ErrorExitJPEG;
612 45 : sCInfo.client_data = &setjmp_buffer;
613 :
614 : // Initialize destination compression parameters from source values.
615 45 : jpeg_CreateCompress(&sCInfo, JPEG_LIB_VERSION, sizeof(sCInfo));
616 45 : jpeg_copy_critical_parameters(psDInfo, &sCInfo);
617 :
618 : // Ensure libjpeg won't write any extraneous markers.
619 45 : sCInfo.write_JFIF_header = FALSE;
620 45 : sCInfo.write_Adobe_marker = FALSE;
621 :
622 : /* -------------------------------------------------------------------- */
623 : /* Allocated destination coefficient array */
624 : /* -------------------------------------------------------------------- */
625 45 : const bool bIsTiled = CPL_TO_BOOL(TIFFIsTiled(hTIFF));
626 :
627 45 : int nJPEGWidth = nBlockXSize;
628 45 : int nJPEGHeight = nBlockYSize;
629 45 : if (!bIsTiled)
630 : {
631 37 : nJPEGWidth = std::min(nBlockXSize, nXSize - iX * nBlockXSize);
632 37 : nJPEGHeight = std::min(nBlockYSize, nYSize - iY * nBlockYSize);
633 : }
634 :
635 : // Code partially derived from libjpeg transupp.c.
636 :
637 : // Correct the destination's image dimensions as necessary.
638 : #if JPEG_LIB_VERSION >= 70
639 45 : sCInfo.jpeg_width = nJPEGWidth;
640 45 : sCInfo.jpeg_height = nJPEGHeight;
641 : #else
642 : sCInfo.image_width = nJPEGWidth;
643 : sCInfo.image_height = nJPEGHeight;
644 : #endif
645 :
646 : // Save x/y offsets measured in iMCUs.
647 45 : const int x_crop_offset = (iX * nBlockXSize) / iMCU_sample_width;
648 45 : const int y_crop_offset = (iY * nBlockYSize) / iMCU_sample_height;
649 :
650 : jvirt_barray_ptr *pDstCoeffs =
651 90 : static_cast<jvirt_barray_ptr *>((*sCInfo.mem->alloc_small)(
652 : reinterpret_cast<j_common_ptr>(&sCInfo), JPOOL_IMAGE,
653 45 : sizeof(jvirt_barray_ptr) * sCInfo.num_components));
654 :
655 168 : for (int ci = 0; ci < sCInfo.num_components; ci++)
656 : {
657 123 : jpeg_component_info *compptr = sCInfo.comp_info + ci;
658 : int h_samp_factor, v_samp_factor;
659 123 : if (sCInfo.num_components == 1)
660 : {
661 : // Force samp factors to 1x1 in this case.
662 9 : h_samp_factor = 1;
663 9 : v_samp_factor = 1;
664 : }
665 : else
666 : {
667 114 : h_samp_factor = compptr->h_samp_factor;
668 114 : v_samp_factor = compptr->v_samp_factor;
669 : }
670 123 : int width_in_iMCUs =
671 123 : (nJPEGWidth + iMCU_sample_width - 1) / iMCU_sample_width;
672 123 : int height_in_iMCUs =
673 123 : (nJPEGHeight + iMCU_sample_height - 1) / iMCU_sample_height;
674 123 : int nWidth_in_blocks = width_in_iMCUs * h_samp_factor;
675 123 : int nHeight_in_blocks = height_in_iMCUs * v_samp_factor;
676 123 : pDstCoeffs[ci] = (*sCInfo.mem->request_virt_barray)(
677 : reinterpret_cast<j_common_ptr>(&sCInfo), JPOOL_IMAGE, FALSE,
678 : nWidth_in_blocks, nHeight_in_blocks,
679 : static_cast<JDIMENSION>(v_samp_factor));
680 : }
681 :
682 45 : jpeg_vsiio_dest(&sCInfo, fpMEM);
683 :
684 : // Start compressor (note no image data is actually written here).
685 45 : jpeg_write_coefficients(&sCInfo, pDstCoeffs);
686 :
687 45 : jpeg_suppress_tables(&sCInfo, TRUE);
688 :
689 : // Must copy the right amount of data (the destination's image size)
690 : // starting at the given X and Y offsets in the source.
691 168 : for (int ci = 0; ci < sCInfo.num_components; ci++)
692 : {
693 123 : jpeg_component_info *compptr = sCInfo.comp_info + ci;
694 123 : const int x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
695 123 : const int y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
696 123 : const JDIMENSION nSrcWidthInBlocks =
697 123 : psDInfo->comp_info[ci].width_in_blocks;
698 123 : const JDIMENSION nSrcHeightInBlocks =
699 123 : psDInfo->comp_info[ci].height_in_blocks;
700 :
701 123 : JDIMENSION nXBlocksToCopy = compptr->width_in_blocks;
702 123 : if (x_crop_blocks + compptr->width_in_blocks > nSrcWidthInBlocks)
703 8 : nXBlocksToCopy = nSrcWidthInBlocks - x_crop_blocks;
704 :
705 590 : for (JDIMENSION dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
706 467 : dst_blk_y += compptr->v_samp_factor)
707 : {
708 934 : JBLOCKARRAY dst_buffer = (*psDInfo->mem->access_virt_barray)(
709 467 : reinterpret_cast<j_common_ptr>(psDInfo), pDstCoeffs[ci],
710 467 : dst_blk_y, static_cast<JDIMENSION>(compptr->v_samp_factor),
711 : TRUE);
712 :
713 467 : int offset_y = 0;
714 467 : if (bIsTiled && dst_blk_y + y_crop_blocks + compptr->v_samp_factor >
715 : nSrcHeightInBlocks)
716 : {
717 94 : const int nYBlocks =
718 94 : static_cast<int>(nSrcHeightInBlocks) -
719 94 : static_cast<int>(dst_blk_y + y_crop_blocks);
720 94 : if (nYBlocks > 0)
721 : {
722 : JBLOCKARRAY src_buffer =
723 2 : (*psDInfo->mem->access_virt_barray)(
724 : reinterpret_cast<j_common_ptr>(psDInfo),
725 2 : pSrcCoeffs[ci], dst_blk_y + y_crop_blocks,
726 : static_cast<JDIMENSION>(1), FALSE);
727 4 : for (; offset_y < nYBlocks; offset_y++)
728 : {
729 2 : memcpy(dst_buffer[offset_y],
730 2 : src_buffer[offset_y] + x_crop_blocks,
731 2 : nXBlocksToCopy * (DCTSIZE2 * sizeof(JCOEF)));
732 2 : if (nXBlocksToCopy < compptr->width_in_blocks)
733 : {
734 1 : memset(dst_buffer[offset_y] + nXBlocksToCopy, 0,
735 1 : (compptr->width_in_blocks - nXBlocksToCopy) *
736 : (DCTSIZE2 * sizeof(JCOEF)));
737 : }
738 : }
739 : }
740 :
741 218 : for (; offset_y < compptr->v_samp_factor; offset_y++)
742 : {
743 124 : memset(dst_buffer[offset_y], 0,
744 124 : compptr->width_in_blocks * DCTSIZE2 * sizeof(JCOEF));
745 94 : }
746 : }
747 : else
748 : {
749 373 : JBLOCKARRAY src_buffer = (*psDInfo->mem->access_virt_barray)(
750 373 : reinterpret_cast<j_common_ptr>(psDInfo), pSrcCoeffs[ci],
751 373 : dst_blk_y + y_crop_blocks,
752 373 : static_cast<JDIMENSION>(compptr->v_samp_factor), FALSE);
753 829 : for (; offset_y < compptr->v_samp_factor; offset_y++)
754 : {
755 456 : memcpy(dst_buffer[offset_y],
756 456 : src_buffer[offset_y] + x_crop_blocks,
757 456 : nXBlocksToCopy * (DCTSIZE2 * sizeof(JCOEF)));
758 456 : if (nXBlocksToCopy < compptr->width_in_blocks)
759 : {
760 69 : memset(dst_buffer[offset_y] + nXBlocksToCopy, 0,
761 69 : (compptr->width_in_blocks - nXBlocksToCopy) *
762 : (DCTSIZE2 * sizeof(JCOEF)));
763 : }
764 : }
765 : }
766 : }
767 : }
768 :
769 45 : jpeg_finish_compress(&sCInfo);
770 45 : jpeg_destroy_compress(&sCInfo);
771 :
772 45 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpMEM));
773 :
774 : /* -------------------------------------------------------------------- */
775 : /* Write the JPEG content with libtiff raw API */
776 : /* -------------------------------------------------------------------- */
777 45 : vsi_l_offset nSize = 0;
778 45 : GByte *pabyJPEGData = VSIGetMemFileBuffer(osTmpFilename, &nSize, FALSE);
779 :
780 45 : CPLErr eErr = CE_None;
781 :
782 45 : if (bIsTiled)
783 : {
784 8 : if (static_cast<vsi_l_offset>(
785 8 : TIFFWriteRawTile(hTIFF, iX + iY * nXBlocks, pabyJPEGData,
786 8 : static_cast<tmsize_t>(nSize))) != nSize)
787 0 : eErr = CE_Failure;
788 : }
789 : else
790 : {
791 37 : if (static_cast<vsi_l_offset>(
792 37 : TIFFWriteRawStrip(hTIFF, iX + iY * nXBlocks, pabyJPEGData,
793 37 : static_cast<tmsize_t>(nSize))) != nSize)
794 0 : eErr = CE_Failure;
795 : }
796 :
797 45 : VSIUnlink(osTmpFilename);
798 :
799 45 : return eErr;
800 : }
801 :
802 : /************************************************************************/
803 : /* GTIFF_CopyFromJPEG() */
804 : /************************************************************************/
805 :
806 12 : CPLErr GTIFF_CopyFromJPEG(GDALDataset *poDS, GDALDataset *poSrcDS,
807 : GDALProgressFunc pfnProgress, void *pProgressData,
808 : bool &bShouldFallbackToNormalCopyIfFail)
809 : {
810 12 : bShouldFallbackToNormalCopyIfFail = true;
811 :
812 12 : poSrcDS = GetUnderlyingDataset(poSrcDS);
813 12 : if (poSrcDS == nullptr)
814 0 : return CE_Failure;
815 :
816 12 : VSILFILE *fpJPEG = VSIFOpenL(poSrcDS->GetDescription(), "rb");
817 12 : if (fpJPEG == nullptr)
818 0 : return CE_Failure;
819 :
820 12 : CPLErr eErr = CE_None;
821 :
822 : /* -------------------------------------------------------------------- */
823 : /* Initialization of the decompressor */
824 : /* -------------------------------------------------------------------- */
825 : struct jpeg_error_mgr sJErr;
826 : struct jpeg_decompress_struct sDInfo;
827 12 : memset(&sDInfo, 0, sizeof(sDInfo));
828 : jmp_buf setjmp_buffer;
829 12 : if (setjmp(setjmp_buffer))
830 : {
831 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpJPEG));
832 0 : jpeg_destroy_decompress(&sDInfo);
833 0 : return CE_Failure;
834 : }
835 :
836 12 : sDInfo.err = jpeg_std_error(&sJErr);
837 12 : sJErr.error_exit = GTIFF_ErrorExitJPEG;
838 12 : sDInfo.client_data = &setjmp_buffer;
839 :
840 12 : jpeg_CreateDecompress(&sDInfo, JPEG_LIB_VERSION, sizeof(sDInfo));
841 :
842 : // This is to address bug related in ticket #1795.
843 12 : if (CPLGetConfigOption("JPEGMEM", nullptr) == nullptr)
844 : {
845 : // If the user doesn't provide a value for JPEGMEM, be sure that at
846 : // least 500 MB will be used before creating the temporary file.
847 12 : const long nMinMemory = 500 * 1024 * 1024;
848 12 : sDInfo.mem->max_memory_to_use =
849 12 : std::max(sDInfo.mem->max_memory_to_use, nMinMemory);
850 : }
851 :
852 12 : jpeg_vsiio_src(&sDInfo, fpJPEG);
853 12 : jpeg_read_header(&sDInfo, TRUE);
854 :
855 12 : jvirt_barray_ptr *pSrcCoeffs = jpeg_read_coefficients(&sDInfo);
856 :
857 : /* -------------------------------------------------------------------- */
858 : /* Compute MCU dimensions */
859 : /* -------------------------------------------------------------------- */
860 12 : int iMCU_sample_width = 8;
861 12 : int iMCU_sample_height = 8;
862 12 : if (sDInfo.num_components != 1)
863 : {
864 8 : iMCU_sample_width = sDInfo.max_h_samp_factor * 8;
865 8 : iMCU_sample_height = sDInfo.max_v_samp_factor * 8;
866 : }
867 :
868 : /* -------------------------------------------------------------------- */
869 : /* Get raster and block dimensions */
870 : /* -------------------------------------------------------------------- */
871 12 : int nBlockXSize = 0;
872 12 : int nBlockYSize = 0;
873 :
874 12 : const int nXSize = poDS->GetRasterXSize();
875 12 : const int nYSize = poDS->GetRasterYSize();
876 : // nBands = poDS->GetRasterCount();
877 :
878 : // Don't use the GDAL block dimensions because of the split-band
879 : // mechanism that can expose a pseudo one-line-strip whereas the
880 : // real layout is a single big strip.
881 :
882 12 : TIFF *hTIFF = static_cast<TIFF *>(poDS->GetInternalHandle(nullptr));
883 12 : if (TIFFIsTiled(hTIFF))
884 : {
885 2 : TIFFGetField(hTIFF, TIFFTAG_TILEWIDTH, &(nBlockXSize));
886 2 : TIFFGetField(hTIFF, TIFFTAG_TILELENGTH, &(nBlockYSize));
887 : }
888 : else
889 : {
890 10 : uint32_t nRowsPerStrip = 0;
891 10 : if (!TIFFGetField(hTIFF, TIFFTAG_ROWSPERSTRIP, &(nRowsPerStrip)))
892 : {
893 0 : CPLError(CE_Warning, CPLE_AppDefined,
894 : "RowsPerStrip not defined ... assuming all one strip.");
895 0 : nRowsPerStrip = nYSize; // Dummy value.
896 : }
897 :
898 : // If the rows per strip is larger than the file we will get
899 : // confused. libtiff internally will treat the rowsperstrip as
900 : // the image height and it is best if we do too. (#4468)
901 10 : if (nRowsPerStrip > static_cast<uint32_t>(nYSize))
902 0 : nRowsPerStrip = nYSize;
903 :
904 10 : nBlockXSize = nXSize;
905 10 : nBlockYSize = nRowsPerStrip;
906 : }
907 :
908 12 : const int nXBlocks = (nXSize + nBlockXSize - 1) / nBlockXSize;
909 12 : const int nYBlocks = (nYSize + nBlockYSize - 1) / nBlockYSize;
910 :
911 : /* -------------------------------------------------------------------- */
912 : /* Copy blocks. */
913 : /* -------------------------------------------------------------------- */
914 :
915 12 : bShouldFallbackToNormalCopyIfFail = false;
916 :
917 53 : for (int iY = 0; iY < nYBlocks && eErr == CE_None; iY++)
918 : {
919 86 : for (int iX = 0; iX < nXBlocks && eErr == CE_None; iX++)
920 : {
921 : GTIFF_CopyBlockFromJPEGArgs sArgs;
922 45 : sArgs.hTIFF = hTIFF;
923 45 : sArgs.psDInfo = &sDInfo;
924 45 : sArgs.iX = iX;
925 45 : sArgs.iY = iY;
926 45 : sArgs.nXBlocks = nXBlocks;
927 45 : sArgs.nXSize = nXSize;
928 45 : sArgs.nYSize = nYSize;
929 45 : sArgs.nBlockXSize = nBlockXSize;
930 45 : sArgs.nBlockYSize = nBlockYSize;
931 45 : sArgs.iMCU_sample_width = iMCU_sample_width;
932 45 : sArgs.iMCU_sample_height = iMCU_sample_height;
933 45 : sArgs.pSrcCoeffs = pSrcCoeffs;
934 :
935 45 : eErr = GTIFF_CopyBlockFromJPEG(&sArgs);
936 :
937 45 : if (!pfnProgress((iY * nXBlocks + iX + 1) * 1.0 /
938 45 : (nXBlocks * nYBlocks),
939 : nullptr, pProgressData))
940 0 : eErr = CE_Failure;
941 : }
942 : }
943 :
944 : /* -------------------------------------------------------------------- */
945 : /* Cleanup. */
946 : /* -------------------------------------------------------------------- */
947 :
948 12 : jpeg_finish_decompress(&sDInfo);
949 12 : jpeg_destroy_decompress(&sDInfo);
950 :
951 12 : if (VSIFCloseL(fpJPEG) != 0)
952 0 : eErr = CE_Failure;
953 :
954 12 : return eErr;
955 : }
956 :
957 : #endif // HAVE_LIBJPEG
|