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