LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 240 251 95.6 %
Date: 2026-01-14 10:48:08 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GeoTIFF Driver
       4             :  * Purpose:  General methods of GTiffRasterBand
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1998, 2002, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys dot com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "gtiffrasterband.h"
      15             : #include "gtiffdataset.h"
      16             : 
      17             : #include <algorithm>
      18             : #include <set>
      19             : 
      20             : #include "gdal_priv.h"
      21             : #include "cpl_vsi_virtual.h"
      22             : #include "tifvsi.h"
      23             : 
      24             : /************************************************************************/
      25             : /*                           GTiffRasterBand()                          */
      26             : /************************************************************************/
      27             : 
      28     1032900 : GTiffRasterBand::GTiffRasterBand(GTiffDataset *poDSIn, int nBandIn)
      29     1032900 :     : m_poGDS(poDSIn)
      30             : {
      31     1032900 :     poDS = poDSIn;
      32     1032900 :     nBand = nBandIn;
      33             : 
      34             :     /* -------------------------------------------------------------------- */
      35             :     /*      Get the GDAL data type.                                         */
      36             :     /* -------------------------------------------------------------------- */
      37     1032900 :     const uint16_t nBitsPerSample = m_poGDS->m_nBitsPerSample;
      38     1032900 :     const uint16_t nSampleFormat = m_poGDS->m_nSampleFormat;
      39             : 
      40     1032900 :     eDataType = GDT_Unknown;
      41             : 
      42     1032900 :     if (nBitsPerSample <= 8)
      43             :     {
      44      890401 :         if (nSampleFormat == SAMPLEFORMAT_INT)
      45         322 :             eDataType = GDT_Int8;
      46             :         else
      47      890079 :             eDataType = GDT_UInt8;
      48             :     }
      49      142494 :     else if (nBitsPerSample <= 16)
      50             :     {
      51      134470 :         if (nBitsPerSample == 16 && nSampleFormat == SAMPLEFORMAT_IEEEFP)
      52         248 :             eDataType = GDT_Float16;
      53      134222 :         else if (nSampleFormat == SAMPLEFORMAT_INT)
      54       67182 :             eDataType = GDT_Int16;
      55             :         else
      56       67040 :             eDataType = GDT_UInt16;
      57             :     }
      58        8024 :     else if (nBitsPerSample == 32)
      59             :     {
      60        4785 :         if (nSampleFormat == SAMPLEFORMAT_COMPLEXINT)
      61         695 :             eDataType = GDT_CInt16;
      62        4090 :         else if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
      63         224 :             eDataType = GDT_CFloat16;
      64        3866 :         else if (nSampleFormat == SAMPLEFORMAT_IEEEFP)
      65        2620 :             eDataType = GDT_Float32;
      66        1246 :         else if (nSampleFormat == SAMPLEFORMAT_INT)
      67         657 :             eDataType = GDT_Int32;
      68             :         else
      69         589 :             eDataType = GDT_UInt32;
      70             :     }
      71        3239 :     else if (nBitsPerSample == 64)
      72             :     {
      73        2681 :         if (nSampleFormat == SAMPLEFORMAT_IEEEFP)
      74        1191 :             eDataType = GDT_Float64;
      75        1490 :         else if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
      76         479 :             eDataType = GDT_CFloat32;
      77        1011 :         else if (nSampleFormat == SAMPLEFORMAT_COMPLEXINT)
      78         448 :             eDataType = GDT_CInt32;
      79         563 :         else if (nSampleFormat == SAMPLEFORMAT_INT)
      80         290 :             eDataType = GDT_Int64;
      81             :         else
      82         273 :             eDataType = GDT_UInt64;
      83             :     }
      84         558 :     else if (nBitsPerSample == 128)
      85             :     {
      86         486 :         if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
      87         486 :             eDataType = GDT_CFloat64;
      88             :     }
      89             : 
      90             :     /* -------------------------------------------------------------------- */
      91             :     /*      Try to work out band color interpretation.                      */
      92             :     /* -------------------------------------------------------------------- */
      93     1032900 :     bool bLookForExtraSamples = false;
      94             : 
      95     1032900 :     if (m_poGDS->m_poColorTable != nullptr && nBand == 1)
      96             :     {
      97         171 :         m_eBandInterp = GCI_PaletteIndex;
      98             :     }
      99     2047440 :     else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
     100     1014720 :              (m_poGDS->m_nPhotometric == PHOTOMETRIC_YCBCR &&
     101         858 :               m_poGDS->m_nCompression == COMPRESSION_JPEG &&
     102         819 :               CPLTestBool(CPLGetConfigOption("CONVERT_YCBCR_TO_RGB", "YES"))))
     103             :     {
     104       18824 :         if (nBand == 1)
     105        5933 :             m_eBandInterp = GCI_RedBand;
     106       12891 :         else if (nBand == 2)
     107        5933 :             m_eBandInterp = GCI_GreenBand;
     108        6958 :         else if (nBand == 3)
     109        5933 :             m_eBandInterp = GCI_BlueBand;
     110             :         else
     111        1025 :             bLookForExtraSamples = true;
     112             :     }
     113     1013900 :     else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_YCBCR)
     114             :     {
     115          39 :         if (nBand == 1)
     116          13 :             m_eBandInterp = GCI_YCbCr_YBand;
     117          26 :         else if (nBand == 2)
     118          13 :             m_eBandInterp = GCI_YCbCr_CbBand;
     119          13 :         else if (nBand == 3)
     120          13 :             m_eBandInterp = GCI_YCbCr_CrBand;
     121             :         else
     122           0 :             bLookForExtraSamples = true;
     123             :     }
     124     1013860 :     else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_SEPARATED)
     125             :     {
     126          96 :         if (nBand == 1)
     127          24 :             m_eBandInterp = GCI_CyanBand;
     128          72 :         else if (nBand == 2)
     129          24 :             m_eBandInterp = GCI_MagentaBand;
     130          48 :         else if (nBand == 3)
     131          24 :             m_eBandInterp = GCI_YellowBand;
     132          24 :         else if (nBand == 4)
     133          24 :             m_eBandInterp = GCI_BlackBand;
     134             :         else
     135           0 :             bLookForExtraSamples = true;
     136             :     }
     137     1013760 :     else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK && nBand == 1)
     138             :     {
     139       26861 :         m_eBandInterp = GCI_GrayIndex;
     140             :     }
     141             :     else
     142             :     {
     143      986904 :         bLookForExtraSamples = true;
     144             :     }
     145             : 
     146     1032900 :     if (bLookForExtraSamples)
     147             :     {
     148      987929 :         uint16_t *v = nullptr;
     149      987929 :         uint16_t count = 0;
     150             : 
     151      987929 :         if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v))
     152             :         {
     153      922009 :             const int nBaseSamples = m_poGDS->m_nSamplesPerPixel - count;
     154      922009 :             const int nExpectedBaseSamples =
     155      923037 :                 (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK)   ? 1
     156        2056 :                 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISWHITE) ? 1
     157        1034 :                 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB)        ? 3
     158          12 :                 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_YCBCR)      ? 3
     159           6 :                 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_SEPARATED)  ? 4
     160             :                                                                       : 0;
     161             : 
     162      922009 :             if (nExpectedBaseSamples > 0 && nBand == nExpectedBaseSamples + 1 &&
     163             :                 nBaseSamples != nExpectedBaseSamples)
     164             :             {
     165           1 :                 ReportError(
     166             :                     CE_Warning, CPLE_AppDefined,
     167             :                     "Wrong number of ExtraSamples : %d. %d were expected",
     168           1 :                     count, m_poGDS->m_nSamplesPerPixel - nExpectedBaseSamples);
     169             :             }
     170             : 
     171      922009 :             if (nBand > nBaseSamples && nBand - nBaseSamples - 1 < count &&
     172      922004 :                 (v[nBand - nBaseSamples - 1] == EXTRASAMPLE_ASSOCALPHA ||
     173      921987 :                  v[nBand - nBaseSamples - 1] == EXTRASAMPLE_UNASSALPHA))
     174             :             {
     175        1122 :                 if (v[nBand - nBaseSamples - 1] == EXTRASAMPLE_ASSOCALPHA)
     176          17 :                     m_oGTiffMDMD.SetMetadataItem("ALPHA", "PREMULTIPLIED",
     177             :                                                  "IMAGE_STRUCTURE");
     178        1122 :                 m_eBandInterp = GCI_AlphaBand;
     179             :             }
     180             :             else
     181      920887 :                 m_eBandInterp = GCI_Undefined;
     182             :         }
     183             :         else
     184             :         {
     185       65920 :             m_eBandInterp = GCI_Undefined;
     186             :         }
     187             :     }
     188             : 
     189             :     /* -------------------------------------------------------------------- */
     190             :     /*      Establish block size for strip or tiles.                        */
     191             :     /* -------------------------------------------------------------------- */
     192     1032900 :     nBlockXSize = m_poGDS->m_nBlockXSize;
     193     1032900 :     nBlockYSize = m_poGDS->m_nBlockYSize;
     194     1032900 :     nRasterXSize = m_poGDS->nRasterXSize;
     195     1032900 :     nRasterYSize = m_poGDS->nRasterYSize;
     196     1032900 :     nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
     197     1032900 :     nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
     198     1032900 : }
     199             : 
     200             : /************************************************************************/
     201             : /*                          ~GTiffRasterBand()                          */
     202             : /************************************************************************/
     203             : 
     204     1933717 : GTiffRasterBand::~GTiffRasterBand()
     205             : {
     206             :     // So that any future DropReferenceVirtualMem() will not try to access the
     207             :     // raster band object, but this would not conform to the advertised
     208             :     // contract.
     209     1032890 :     if (!m_aSetPSelf.empty())
     210             :     {
     211           0 :         ReportError(CE_Warning, CPLE_AppDefined,
     212             :                     "Virtual memory objects still exist at GTiffRasterBand "
     213             :                     "destruction");
     214           0 :         std::set<GTiffRasterBand **>::iterator oIter = m_aSetPSelf.begin();
     215           0 :         for (; oIter != m_aSetPSelf.end(); ++oIter)
     216           0 :             *(*oIter) = nullptr;
     217             :     }
     218     1933717 : }
     219             : 
     220             : /************************************************************************/
     221             : /*                            IRasterIO()                               */
     222             : /************************************************************************/
     223             : 
     224     5818660 : CPLErr GTiffRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     225             :                                   int nXSize, int nYSize, void *pData,
     226             :                                   int nBufXSize, int nBufYSize,
     227             :                                   GDALDataType eBufType, GSpacing nPixelSpace,
     228             :                                   GSpacing nLineSpace,
     229             :                                   GDALRasterIOExtraArg *psExtraArg)
     230             : {
     231             : #if DEBUG_VERBOSE
     232             :     CPLDebug("GTiff", "RasterIO(%d, %d, %d, %d, %d, %d)", nXOff, nYOff, nXSize,
     233             :              nYSize, nBufXSize, nBufYSize);
     234             : #endif
     235             : 
     236             :     // Try to pass the request to the most appropriate overview dataset.
     237     5818660 :     if (nBufXSize < nXSize && nBufYSize < nYSize)
     238             :     {
     239      362408 :         int bTried = FALSE;
     240           0 :         std::unique_ptr<GTiffDataset::JPEGOverviewVisibilitySetter> setter;
     241      362408 :         if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
     242             :         {
     243      362040 :             setter = m_poGDS->MakeJPEGOverviewVisible();
     244      362040 :             CPL_IGNORE_RET_VAL(setter);
     245             :         }
     246      362408 :         const CPLErr eErr = TryOverviewRasterIO(
     247             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     248             :             eBufType, nPixelSpace, nLineSpace, psExtraArg, &bTried);
     249      362408 :         if (bTried)
     250          44 :             return eErr;
     251             :     }
     252             : 
     253     5818610 :     if (m_poGDS->m_eVirtualMemIOUsage != GTiffDataset::VirtualMemIOEnum::NO)
     254             :     {
     255         904 :         const int nErr = m_poGDS->VirtualMemIO(
     256             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     257         452 :             eBufType, 1, &nBand, nPixelSpace, nLineSpace, 0, psExtraArg);
     258         452 :         if (nErr >= 0)
     259         363 :             return static_cast<CPLErr>(nErr);
     260             :     }
     261     5818250 :     if (m_poGDS->m_bDirectIO)
     262             :     {
     263             :         int nErr =
     264        2522 :             DirectIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     265             :                      nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
     266        2522 :         if (nErr >= 0)
     267        1409 :             return static_cast<CPLErr>(nErr);
     268             :     }
     269             : 
     270     5816840 :     bool bCanUseMultiThreadedRead = false;
     271     5816570 :     if (m_poGDS->m_nDisableMultiThreadedRead == 0 && eRWFlag == GF_Read &&
     272     3357290 :         m_poGDS->m_poThreadPool != nullptr && nXSize == nBufXSize &&
     273    11633400 :         nYSize == nBufYSize && m_poGDS->IsMultiThreadedReadCompatible())
     274             :     {
     275         104 :         const int nBlockX1 = nXOff / nBlockXSize;
     276         104 :         const int nBlockY1 = nYOff / nBlockYSize;
     277         104 :         const int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
     278         104 :         const int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
     279         104 :         const int nXBlocks = nBlockX2 - nBlockX1 + 1;
     280         104 :         const int nYBlocks = nBlockY2 - nBlockY1 + 1;
     281         104 :         if (nXBlocks > 1 || nYBlocks > 1)
     282             :         {
     283         101 :             bCanUseMultiThreadedRead = true;
     284             :         }
     285             :     }
     286             : 
     287             :     // Cleanup data cached by below CacheMultiRange() call.
     288             :     struct BufferedDataFreer
     289             :     {
     290             :         void *m_pBufferedData = nullptr;
     291             :         TIFF *m_hTIFF = nullptr;
     292             : 
     293         254 :         void Init(void *pBufferedData, TIFF *hTIFF)
     294             :         {
     295         254 :             m_pBufferedData = pBufferedData;
     296         254 :             m_hTIFF = hTIFF;
     297         254 :         }
     298             : 
     299     5816840 :         ~BufferedDataFreer()
     300     5816840 :         {
     301     5816840 :             if (m_pBufferedData)
     302             :             {
     303          34 :                 VSIFree(m_pBufferedData);
     304          34 :                 VSI_TIFFSetCachedRanges(TIFFClientdata(m_hTIFF), 0, nullptr,
     305             :                                         nullptr, nullptr);
     306             :             }
     307     5816840 :         }
     308             :     };
     309             : 
     310             :     // bufferedDataFreer must be left in this scope !
     311     5816840 :     BufferedDataFreer bufferedDataFreer;
     312             : 
     313     8676310 :     if (m_poGDS->eAccess == GA_ReadOnly && eRWFlag == GF_Read &&
     314     2859470 :         m_poGDS->HasOptimizedReadMultiRange())
     315             :     {
     316         262 :         if (bCanUseMultiThreadedRead &&
     317           4 :             VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF))->HasPRead())
     318             :         {
     319             :             // use the multi-threaded implementation rather than the multi-range
     320             :             // one
     321             :         }
     322             :         else
     323             :         {
     324         254 :             bCanUseMultiThreadedRead = false;
     325         254 :             GTiffDataset *poDSForCache = m_poGDS;
     326         254 :             int nBandForCache = nBand;
     327         254 :             if (!m_poGDS->m_bStreamingIn && m_poGDS->m_bBlockOrderRowMajor &&
     328         110 :                 m_poGDS->m_bLeaderSizeAsUInt4 &&
     329         110 :                 m_poGDS->m_bMaskInterleavedWithImagery &&
     330         100 :                 m_poGDS->m_poImageryDS)
     331             :             {
     332          62 :                 poDSForCache = m_poGDS->m_poImageryDS;
     333          62 :                 nBandForCache = 1;
     334             :             }
     335         254 :             bufferedDataFreer.Init(
     336             :                 poDSForCache->CacheMultiRange(nXOff, nYOff, nXSize, nYSize,
     337             :                                               nBufXSize, nBufYSize,
     338             :                                               &nBandForCache, 1, psExtraArg),
     339             :                 poDSForCache->m_hTIFF);
     340             :         }
     341             :     }
     342             : 
     343     5816840 :     if (eRWFlag == GF_Read && nXSize == nBufXSize && nYSize == nBufYSize)
     344             :     {
     345     2961560 :         const int nBlockX1 = nXOff / nBlockXSize;
     346     2961560 :         const int nBlockY1 = nYOff / nBlockYSize;
     347     2961560 :         const int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
     348     2961560 :         const int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
     349     2961560 :         const int nXBlocks = nBlockX2 - nBlockX1 + 1;
     350     2961560 :         const int nYBlocks = nBlockY2 - nBlockY1 + 1;
     351             : 
     352     2961560 :         if (bCanUseMultiThreadedRead)
     353             :         {
     354         202 :             return m_poGDS->MultiThreadedRead(nXOff, nYOff, nXSize, nYSize,
     355         101 :                                               pData, eBufType, 1, &nBand,
     356         101 :                                               nPixelSpace, nLineSpace, 0);
     357             :         }
     358     2961460 :         else if (m_poGDS->nBands != 1 &&
     359      738962 :                  m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     360             :         {
     361             :             const GIntBig nRequiredMem =
     362      679172 :                 static_cast<GIntBig>(m_poGDS->nBands) * nXBlocks * nYBlocks *
     363      679172 :                 nBlockXSize * nBlockYSize * GDALGetDataTypeSizeBytes(eDataType);
     364      679172 :             if (nRequiredMem > GDALGetCacheMax64())
     365             :             {
     366        9061 :                 if (!m_poGDS->m_bHasWarnedDisableAggressiveBandCaching)
     367             :                 {
     368          15 :                     CPLDebug("GTiff",
     369             :                              "Disable aggressive band caching. "
     370             :                              "Cache not big enough. "
     371             :                              "At least " CPL_FRMT_GIB " bytes necessary",
     372             :                              nRequiredMem);
     373          15 :                     m_poGDS->m_bHasWarnedDisableAggressiveBandCaching = true;
     374             :                 }
     375        9061 :                 m_poGDS->m_bLoadingOtherBands = true;
     376             :             }
     377     2961460 :         }
     378             :     }
     379             : 
     380             :     // Write optimization when writing whole blocks, by-passing the block cache.
     381             :     // We require the block cache to be non instantiated to simplify things
     382             :     // (otherwise we might need to evict corresponding existing blocks from the
     383             :     // block cache).
     384     5314560 :     else if (eRWFlag == GF_Write &&
     385             :              // Could be extended to "odd bit" case, but more work
     386     2459270 :              m_poGDS->m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
     387     2307110 :              nXSize == nBufXSize && nYSize == nBufYSize && !HasBlockCache() &&
     388       49778 :              !m_poGDS->m_bLoadedBlockDirty &&
     389       49766 :              (m_poGDS->nBands == 1 ||
     390        4519 :               m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE) &&
     391       48657 :              !m_poGDS->m_bLeaderSizeAsUInt4 && (nXOff % nBlockXSize) == 0 &&
     392       48612 :              (nYOff % nBlockYSize) == 0 &&
     393     5363000 :              (nXOff + nXSize == nRasterXSize || (nXSize % nBlockXSize) == 0) &&
     394       48441 :              (nYOff + nYSize == nRasterYSize || (nYSize % nBlockYSize) == 0))
     395             :     {
     396       48104 :         m_poGDS->Crystalize();
     397             : 
     398       48104 :         if (m_poGDS->m_bDebugDontWriteBlocks)
     399           0 :             return CE_None;
     400             : 
     401       48104 :         const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
     402       48104 :         if (nXSize == nBlockXSize && nYSize == nBlockYSize &&
     403       44055 :             eBufType == eDataType && nPixelSpace == nDTSize &&
     404       42314 :             nLineSpace == nPixelSpace * nBlockXSize)
     405             :         {
     406             :             // If writing one single block with the right data type and layout,
     407             :             // we don't need a temporary buffer
     408             :             const int nBlockId =
     409       42314 :                 ComputeBlockId(nXOff / nBlockXSize, nYOff / nBlockYSize);
     410       42314 :             return m_poGDS->WriteEncodedTileOrStrip(
     411       42314 :                 nBlockId, pData, /* bPreserveDataBuffer= */ true);
     412             :         }
     413             : 
     414             :         // Make sure m_poGDS->m_pabyBlockBuf is allocated.
     415             :         // We could actually use any temporary buffer
     416        5790 :         if (m_poGDS->LoadBlockBuf(/* nBlockId = */ -1,
     417        5790 :                                   /* bReadFromDisk = */ false) != CE_None)
     418             :         {
     419           0 :             return CE_Failure;
     420             :         }
     421             : 
     422             :         // Iterate over all blocks defined by
     423             :         // [nXOff, nXOff+nXSize[ * [nYOff, nYOff+nYSize[
     424             :         // and write their content as a nBlockXSize x nBlockYSize strile
     425             :         // in a temporary buffer, before calling WriteEncodedTileOrStrip()
     426             :         // on it
     427        5790 :         const int nYBlockStart = nYOff / nBlockYSize;
     428        5790 :         const int nYBlockEnd = 1 + (nYOff + nYSize - 1) / nBlockYSize;
     429        5790 :         const int nXBlockStart = nXOff / nBlockXSize;
     430        5790 :         const int nXBlockEnd = 1 + (nXOff + nXSize - 1) / nBlockXSize;
     431       52254 :         for (int nYBlock = nYBlockStart; nYBlock < nYBlockEnd; ++nYBlock)
     432             :         {
     433             :             const int nValidY =
     434       46464 :                 std::min(nBlockYSize, nRasterYSize - nYBlock * nBlockYSize);
     435      108971 :             for (int nXBlock = nXBlockStart; nXBlock < nXBlockEnd; ++nXBlock)
     436             :             {
     437             :                 const int nValidX =
     438       62507 :                     std::min(nBlockXSize, nRasterXSize - nXBlock * nBlockXSize);
     439       62507 :                 if (nValidY < nBlockYSize || nValidX < nBlockXSize)
     440             :                 {
     441             :                     // Make sure padding bytes at the right/bottom of the
     442             :                     // tile are initialized to zero.
     443        3010 :                     memset(m_poGDS->m_pabyBlockBuf, 0,
     444        3010 :                            static_cast<size_t>(nBlockXSize) * nBlockYSize *
     445        3010 :                                nDTSize);
     446             :                 }
     447       62507 :                 const GByte *pabySrcData =
     448             :                     static_cast<const GByte *>(pData) +
     449       62507 :                     static_cast<size_t>(nYBlock - nYBlockStart) * nBlockYSize *
     450       62507 :                         nLineSpace +
     451       62507 :                     static_cast<size_t>(nXBlock - nXBlockStart) * nBlockXSize *
     452       62507 :                         nPixelSpace;
     453     3838930 :                 for (int iY = 0; iY < nValidY; ++iY)
     454             :                 {
     455     3776420 :                     GDALCopyWords64(
     456     3776420 :                         pabySrcData + static_cast<size_t>(iY) * nLineSpace,
     457             :                         eBufType, static_cast<int>(nPixelSpace),
     458     3776420 :                         m_poGDS->m_pabyBlockBuf +
     459     3776420 :                             static_cast<size_t>(iY) * nBlockXSize * nDTSize,
     460             :                         eDataType, nDTSize, nValidX);
     461             :                 }
     462       62507 :                 const int nBlockId = ComputeBlockId(nXBlock, nYBlock);
     463      125014 :                 if (m_poGDS->WriteEncodedTileOrStrip(
     464       62507 :                         nBlockId, m_poGDS->m_pabyBlockBuf,
     465       62507 :                         /* bPreserveDataBuffer= */ false) != CE_None)
     466             :                 {
     467           0 :                     return CE_Failure;
     468             :                 }
     469             :             }
     470             :         }
     471        5790 :         return CE_None;
     472             :     }
     473             : 
     474           0 :     std::unique_ptr<GTiffDataset::JPEGOverviewVisibilitySetter> setter;
     475     5768640 :     if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
     476             :     {
     477     5766140 :         setter = m_poGDS->MakeJPEGOverviewVisible();
     478     5766140 :         CPL_IGNORE_RET_VAL(setter);
     479             :     }
     480     5768640 :     const CPLErr eErr = GDALPamRasterBand::IRasterIO(
     481             :         eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     482             :         eBufType, nPixelSpace, nLineSpace, psExtraArg);
     483             : 
     484     5768640 :     m_poGDS->m_bLoadingOtherBands = false;
     485             : 
     486     5768640 :     return eErr;
     487             : }
     488             : 
     489             : /************************************************************************/
     490             : /*                        ComputeBlockId()                              */
     491             : /************************************************************************/
     492             : 
     493             : /** Computes the TIFF block identifier from the tile coordinate, band
     494             :  * number and planar configuration.
     495             :  */
     496     3307140 : int GTiffRasterBand::ComputeBlockId(int nBlockXOff, int nBlockYOff) const
     497             : {
     498     3307140 :     const int nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
     499     3307140 :     if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
     500             :     {
     501      665008 :         return nBlockId + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
     502             :     }
     503     2642130 :     return nBlockId;
     504             : }

Generated by: LCOV version 1.14