LCOV - code coverage report
Current view: directory - frmts/gtiff - gt_jpeg_copy.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 245 216 88.2 %
Date: 2012-04-28 Functions: 7 6 85.7 %

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

Generated by: LCOV version 1.7