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