LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 244 255 95.7 %
Date: 2026-02-12 23:49:34 Functions: 8 8 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     1033180 : GTiffRasterBand::GTiffRasterBand(GTiffDataset *poDSIn, int nBandIn)
      29     1033180 :     : m_poGDS(poDSIn)
      30             : {
      31     1033180 :     poDS = poDSIn;
      32     1033180 :     nBand = nBandIn;
      33             : 
      34             :     /* -------------------------------------------------------------------- */
      35             :     /*      Get the GDAL data type.                                         */
      36             :     /* -------------------------------------------------------------------- */
      37     1033180 :     const uint16_t nBitsPerSample = m_poGDS->m_nBitsPerSample;
      38     1033180 :     const uint16_t nSampleFormat = m_poGDS->m_nSampleFormat;
      39             : 
      40     1033180 :     eDataType = GDT_Unknown;
      41             : 
      42     1033180 :     if (nBitsPerSample <= 8)
      43             :     {
      44      890574 :         if (nSampleFormat == SAMPLEFORMAT_INT)
      45         324 :             eDataType = GDT_Int8;
      46             :         else
      47      890250 :             eDataType = GDT_UInt8;
      48             :     }
      49      142609 :     else if (nBitsPerSample <= 16)
      50             :     {
      51      134483 :         if (nBitsPerSample == 16 && nSampleFormat == SAMPLEFORMAT_IEEEFP)
      52         254 :             eDataType = GDT_Float16;
      53      134229 :         else if (nSampleFormat == SAMPLEFORMAT_INT)
      54       67179 :             eDataType = GDT_Int16;
      55             :         else
      56       67050 :             eDataType = GDT_UInt16;
      57             :     }
      58        8126 :     else if (nBitsPerSample == 32)
      59             :     {
      60        4399 :         if (nSampleFormat == SAMPLEFORMAT_COMPLEXINT)
      61         695 :             eDataType = GDT_CInt16;
      62        3704 :         else if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
      63         224 :             eDataType = GDT_CFloat16;
      64        3480 :         else if (nSampleFormat == SAMPLEFORMAT_IEEEFP)
      65        2230 :             eDataType = GDT_Float32;
      66        1250 :         else if (nSampleFormat == SAMPLEFORMAT_INT)
      67         659 :             eDataType = GDT_Int32;
      68             :         else
      69         591 :             eDataType = GDT_UInt32;
      70             :     }
      71        3727 :     else if (nBitsPerSample == 64)
      72             :     {
      73        3169 :         if (nSampleFormat == SAMPLEFORMAT_IEEEFP)
      74        1673 :             eDataType = GDT_Float64;
      75        1496 :         else if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
      76         481 :             eDataType = GDT_CFloat32;
      77        1015 :         else if (nSampleFormat == SAMPLEFORMAT_COMPLEXINT)
      78         448 :             eDataType = GDT_CInt32;
      79         567 :         else if (nSampleFormat == SAMPLEFORMAT_INT)
      80         292 :             eDataType = GDT_Int64;
      81             :         else
      82         275 :             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     1033180 :     bool bLookForExtraSamples = false;
      94             : 
      95     1033180 :     if (m_poGDS->m_poColorTable != nullptr && nBand == 1)
      96             :     {
      97         175 :         m_eBandInterp = GCI_PaletteIndex;
      98             :     }
      99     2048000 :     else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
     100     1014990 :              (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       18840 :         if (nBand == 1)
     105        5938 :             m_eBandInterp = GCI_RedBand;
     106       12902 :         else if (nBand == 2)
     107        5938 :             m_eBandInterp = GCI_GreenBand;
     108        6964 :         else if (nBand == 3)
     109        5938 :             m_eBandInterp = GCI_BlueBand;
     110             :         else
     111        1026 :             bLookForExtraSamples = true;
     112             :     }
     113     1014170 :     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     1014130 :     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     1014030 :     else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK && nBand == 1)
     138             :     {
     139       27083 :         m_eBandInterp = GCI_GrayIndex;
     140             :     }
     141             :     else
     142             :     {
     143      986950 :         bLookForExtraSamples = true;
     144             :     }
     145             : 
     146     1033180 :     if (bLookForExtraSamples)
     147             :     {
     148      987976 :         uint16_t *v = nullptr;
     149      987976 :         uint16_t count = 0;
     150             : 
     151      987976 :         if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v))
     152             :         {
     153      922056 :             const int nBaseSamples = m_poGDS->m_nSamplesPerPixel - count;
     154      922056 :             const int nExpectedBaseSamples =
     155      923085 :                 (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK)   ? 1
     156        2058 :                 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISWHITE) ? 1
     157        1035 :                 : (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      922056 :             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      922056 :             if (nBand > nBaseSamples && nBand - nBaseSamples - 1 < count &&
     172      922051 :                 (v[nBand - nBaseSamples - 1] == EXTRASAMPLE_ASSOCALPHA ||
     173      922034 :                  v[nBand - nBaseSamples - 1] == EXTRASAMPLE_UNASSALPHA))
     174             :             {
     175        1123 :                 if (v[nBand - nBaseSamples - 1] == EXTRASAMPLE_ASSOCALPHA)
     176          17 :                     m_oGTiffMDMD.SetMetadataItem("ALPHA", "PREMULTIPLIED",
     177             :                                                  "IMAGE_STRUCTURE");
     178        1123 :                 m_eBandInterp = GCI_AlphaBand;
     179             :             }
     180             :             else
     181      920933 :                 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     1033180 :     nBlockXSize = m_poGDS->m_nBlockXSize;
     193     1033180 :     nBlockYSize = m_poGDS->m_nBlockYSize;
     194     1033180 :     nRasterXSize = m_poGDS->nRasterXSize;
     195     1033180 :     nRasterYSize = m_poGDS->nRasterYSize;
     196     1033180 :     nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
     197     1033180 :     nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
     198     1033180 : }
     199             : 
     200             : /************************************************************************/
     201             : /*                          ~GTiffRasterBand()                          */
     202             : /************************************************************************/
     203             : 
     204     1934295 : 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     1033180 :     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     1934295 : }
     219             : 
     220             : /************************************************************************/
     221             : /*                MayMultiBlockReadingBeMultiThreaded()                 */
     222             : /************************************************************************/
     223             : 
     224          12 : bool GTiffRasterBand::MayMultiBlockReadingBeMultiThreaded() const
     225             : {
     226          24 :     return m_poGDS->m_nDisableMultiThreadedRead == 0 &&
     227          16 :            m_poGDS->m_poThreadPool != nullptr &&
     228          16 :            m_poGDS->IsMultiThreadedReadCompatible();
     229             : }
     230             : 
     231             : /************************************************************************/
     232             : /*                             IRasterIO()                              */
     233             : /************************************************************************/
     234             : 
     235     5823570 : CPLErr GTiffRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     236             :                                   int nXSize, int nYSize, void *pData,
     237             :                                   int nBufXSize, int nBufYSize,
     238             :                                   GDALDataType eBufType, GSpacing nPixelSpace,
     239             :                                   GSpacing nLineSpace,
     240             :                                   GDALRasterIOExtraArg *psExtraArg)
     241             : {
     242             : #if DEBUG_VERBOSE
     243             :     CPLDebug("GTiff", "RasterIO(%d, %d, %d, %d, %d, %d)", nXOff, nYOff, nXSize,
     244             :              nYSize, nBufXSize, nBufYSize);
     245             : #endif
     246             : 
     247             :     // Try to pass the request to the most appropriate overview dataset.
     248     5823570 :     if (nBufXSize < nXSize && nBufYSize < nYSize)
     249             :     {
     250      362409 :         int bTried = FALSE;
     251           0 :         std::unique_ptr<GTiffDataset::JPEGOverviewVisibilitySetter> setter;
     252      362409 :         if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
     253             :         {
     254      362041 :             setter = m_poGDS->MakeJPEGOverviewVisible();
     255      362041 :             CPL_IGNORE_RET_VAL(setter);
     256             :         }
     257      362409 :         const CPLErr eErr = TryOverviewRasterIO(
     258             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     259             :             eBufType, nPixelSpace, nLineSpace, psExtraArg, &bTried);
     260      362409 :         if (bTried)
     261          44 :             return eErr;
     262             :     }
     263             : 
     264     5823520 :     if (m_poGDS->m_eVirtualMemIOUsage != GTiffDataset::VirtualMemIOEnum::NO)
     265             :     {
     266         904 :         const int nErr = m_poGDS->VirtualMemIO(
     267             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     268         452 :             eBufType, 1, &nBand, nPixelSpace, nLineSpace, 0, psExtraArg);
     269         452 :         if (nErr >= 0)
     270         363 :             return static_cast<CPLErr>(nErr);
     271             :     }
     272     5823160 :     if (m_poGDS->m_bDirectIO)
     273             :     {
     274             :         int nErr =
     275        2523 :             DirectIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     276             :                      nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
     277        2523 :         if (nErr >= 0)
     278        1410 :             return static_cast<CPLErr>(nErr);
     279             :     }
     280             : 
     281     5821750 :     bool bCanUseMultiThreadedRead = false;
     282     5821480 :     if (m_poGDS->m_nDisableMultiThreadedRead == 0 && eRWFlag == GF_Read &&
     283     3361460 :         m_poGDS->m_poThreadPool != nullptr && nXSize == nBufXSize &&
     284    11643200 :         nYSize == nBufYSize && m_poGDS->IsMultiThreadedReadCompatible())
     285             :     {
     286         110 :         const int nBlockX1 = nXOff / nBlockXSize;
     287         110 :         const int nBlockY1 = nYOff / nBlockYSize;
     288         110 :         const int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
     289         110 :         const int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
     290         110 :         const int nXBlocks = nBlockX2 - nBlockX1 + 1;
     291         110 :         const int nYBlocks = nBlockY2 - nBlockY1 + 1;
     292         110 :         if (nXBlocks > 1 || nYBlocks > 1)
     293             :         {
     294         107 :             bCanUseMultiThreadedRead = true;
     295             :         }
     296             :     }
     297             : 
     298             :     // Cleanup data cached by below CacheMultiRange() call.
     299             :     struct BufferedDataFreer
     300             :     {
     301             :         void *m_pBufferedData = nullptr;
     302             :         TIFF *m_hTIFF = nullptr;
     303             : 
     304         254 :         void Init(void *pBufferedData, TIFF *hTIFF)
     305             :         {
     306         254 :             m_pBufferedData = pBufferedData;
     307         254 :             m_hTIFF = hTIFF;
     308         254 :         }
     309             : 
     310     5821750 :         ~BufferedDataFreer()
     311     5821750 :         {
     312     5821750 :             if (m_pBufferedData)
     313             :             {
     314          34 :                 VSIFree(m_pBufferedData);
     315          34 :                 VSI_TIFFSetCachedRanges(TIFFClientdata(m_hTIFF), 0, nullptr,
     316             :                                         nullptr, nullptr);
     317             :             }
     318     5821750 :         }
     319             :     };
     320             : 
     321             :     // bufferedDataFreer must be left in this scope !
     322     5821750 :     BufferedDataFreer bufferedDataFreer;
     323             : 
     324     8682870 :     if (m_poGDS->eAccess == GA_ReadOnly && eRWFlag == GF_Read &&
     325     2861120 :         m_poGDS->HasOptimizedReadMultiRange())
     326             :     {
     327         262 :         if (bCanUseMultiThreadedRead &&
     328           4 :             VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF))->HasPRead())
     329             :         {
     330             :             // use the multi-threaded implementation rather than the multi-range
     331             :             // one
     332             :         }
     333             :         else
     334             :         {
     335         254 :             bCanUseMultiThreadedRead = false;
     336         254 :             GTiffDataset *poDSForCache = m_poGDS;
     337         254 :             int nBandForCache = nBand;
     338         254 :             if (!m_poGDS->m_bStreamingIn && m_poGDS->m_bBlockOrderRowMajor &&
     339         110 :                 m_poGDS->m_bLeaderSizeAsUInt4 &&
     340         110 :                 m_poGDS->m_bMaskInterleavedWithImagery &&
     341         100 :                 m_poGDS->m_poImageryDS)
     342             :             {
     343          62 :                 poDSForCache = m_poGDS->m_poImageryDS;
     344          62 :                 nBandForCache = 1;
     345             :             }
     346         254 :             bufferedDataFreer.Init(
     347             :                 poDSForCache->CacheMultiRange(nXOff, nYOff, nXSize, nYSize,
     348             :                                               nBufXSize, nBufYSize,
     349             :                                               &nBandForCache, 1, psExtraArg),
     350             :                 poDSForCache->m_hTIFF);
     351             :         }
     352             :     }
     353             : 
     354     5821750 :     if (eRWFlag == GF_Read && nXSize == nBufXSize && nYSize == nBufYSize)
     355             :     {
     356     2965710 :         const int nBlockX1 = nXOff / nBlockXSize;
     357     2965710 :         const int nBlockY1 = nYOff / nBlockYSize;
     358     2965710 :         const int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
     359     2965710 :         const int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
     360     2965710 :         const int nXBlocks = nBlockX2 - nBlockX1 + 1;
     361     2965710 :         const int nYBlocks = nBlockY2 - nBlockY1 + 1;
     362             : 
     363     2965710 :         if (bCanUseMultiThreadedRead)
     364             :         {
     365         214 :             return m_poGDS->MultiThreadedRead(nXOff, nYOff, nXSize, nYSize,
     366         107 :                                               pData, eBufType, 1, &nBand,
     367         107 :                                               nPixelSpace, nLineSpace, 0);
     368             :         }
     369     2965610 :         else if (m_poGDS->nBands != 1 &&
     370      742209 :                  m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     371             :         {
     372             :             const GIntBig nRequiredMem =
     373      681222 :                 static_cast<GIntBig>(m_poGDS->nBands) * nXBlocks * nYBlocks *
     374      681222 :                 nBlockXSize * nBlockYSize * GDALGetDataTypeSizeBytes(eDataType);
     375      681222 :             if (nRequiredMem > GDALGetCacheMax64())
     376             :             {
     377        9061 :                 if (!m_poGDS->m_bHasWarnedDisableAggressiveBandCaching)
     378             :                 {
     379          15 :                     CPLDebug("GTiff",
     380             :                              "Disable aggressive band caching. "
     381             :                              "Cache not big enough. "
     382             :                              "At least " CPL_FRMT_GIB " bytes necessary",
     383             :                              nRequiredMem);
     384          15 :                     m_poGDS->m_bHasWarnedDisableAggressiveBandCaching = true;
     385             :                 }
     386        9061 :                 m_poGDS->m_bLoadingOtherBands = true;
     387             :             }
     388     2965610 :         }
     389             :     }
     390             : 
     391             :     // Write optimization when writing whole blocks, by-passing the block cache.
     392             :     // We require the block cache to be non instantiated to simplify things
     393             :     // (otherwise we might need to evict corresponding existing blocks from the
     394             :     // block cache).
     395     5316060 :     else if (eRWFlag == GF_Write &&
     396             :              // Could be extended to "odd bit" case, but more work
     397     2460020 :              m_poGDS->m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
     398     2307850 :              nXSize == nBufXSize && nYSize == nBufYSize && !HasBlockCache() &&
     399       49833 :              !m_poGDS->m_bLoadedBlockDirty &&
     400       49821 :              (m_poGDS->nBands == 1 ||
     401        4519 :               m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE) &&
     402       48712 :              !m_poGDS->m_bLeaderSizeAsUInt4 && (nXOff % nBlockXSize) == 0 &&
     403       48667 :              (nYOff % nBlockYSize) == 0 &&
     404     5364560 :              (nXOff + nXSize == nRasterXSize || (nXSize % nBlockXSize) == 0) &&
     405       48494 :              (nYOff + nYSize == nRasterYSize || (nYSize % nBlockYSize) == 0))
     406             :     {
     407       48153 :         m_poGDS->Crystalize();
     408             : 
     409       48153 :         if (m_poGDS->m_bDebugDontWriteBlocks)
     410           0 :             return CE_None;
     411             : 
     412       48153 :         const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
     413       48153 :         if (nXSize == nBlockXSize && nYSize == nBlockYSize &&
     414       44092 :             eBufType == eDataType && nPixelSpace == nDTSize &&
     415       42351 :             nLineSpace == nPixelSpace * nBlockXSize)
     416             :         {
     417             :             // If writing one single block with the right data type and layout,
     418             :             // we don't need a temporary buffer
     419             :             const int nBlockId =
     420       42351 :                 ComputeBlockId(nXOff / nBlockXSize, nYOff / nBlockYSize);
     421       42351 :             return m_poGDS->WriteEncodedTileOrStrip(
     422       42351 :                 nBlockId, pData, /* bPreserveDataBuffer= */ true);
     423             :         }
     424             : 
     425             :         // Make sure m_poGDS->m_pabyBlockBuf is allocated.
     426             :         // We could actually use any temporary buffer
     427        5802 :         if (m_poGDS->LoadBlockBuf(/* nBlockId = */ -1,
     428        5802 :                                   /* bReadFromDisk = */ false) != CE_None)
     429             :         {
     430           0 :             return CE_Failure;
     431             :         }
     432             : 
     433             :         // Iterate over all blocks defined by
     434             :         // [nXOff, nXOff+nXSize[ * [nYOff, nYOff+nYSize[
     435             :         // and write their content as a nBlockXSize x nBlockYSize strile
     436             :         // in a temporary buffer, before calling WriteEncodedTileOrStrip()
     437             :         // on it
     438        5802 :         const int nYBlockStart = nYOff / nBlockYSize;
     439        5802 :         const int nYBlockEnd = 1 + (nYOff + nYSize - 1) / nBlockYSize;
     440        5802 :         const int nXBlockStart = nXOff / nBlockXSize;
     441        5802 :         const int nXBlockEnd = 1 + (nXOff + nXSize - 1) / nBlockXSize;
     442       52293 :         for (int nYBlock = nYBlockStart; nYBlock < nYBlockEnd; ++nYBlock)
     443             :         {
     444             :             const int nValidY =
     445       46491 :                 std::min(nBlockYSize, nRasterYSize - nYBlock * nBlockYSize);
     446      109058 :             for (int nXBlock = nXBlockStart; nXBlock < nXBlockEnd; ++nXBlock)
     447             :             {
     448             :                 const int nValidX =
     449       62567 :                     std::min(nBlockXSize, nRasterXSize - nXBlock * nBlockXSize);
     450       62567 :                 if (nValidY < nBlockYSize || nValidX < nBlockXSize)
     451             :                 {
     452             :                     // Make sure padding bytes at the right/bottom of the
     453             :                     // tile are initialized to zero.
     454        3036 :                     memset(m_poGDS->m_pabyBlockBuf, 0,
     455        3036 :                            static_cast<size_t>(nBlockXSize) * nBlockYSize *
     456        3036 :                                nDTSize);
     457             :                 }
     458       62567 :                 const GByte *pabySrcData =
     459             :                     static_cast<const GByte *>(pData) +
     460       62567 :                     static_cast<size_t>(nYBlock - nYBlockStart) * nBlockYSize *
     461       62567 :                         nLineSpace +
     462       62567 :                     static_cast<size_t>(nXBlock - nXBlockStart) * nBlockXSize *
     463       62567 :                         nPixelSpace;
     464     3847810 :                 for (int iY = 0; iY < nValidY; ++iY)
     465             :                 {
     466     3785240 :                     GDALCopyWords64(
     467     3785240 :                         pabySrcData + static_cast<size_t>(iY) * nLineSpace,
     468             :                         eBufType, static_cast<int>(nPixelSpace),
     469     3785240 :                         m_poGDS->m_pabyBlockBuf +
     470     3785240 :                             static_cast<size_t>(iY) * nBlockXSize * nDTSize,
     471             :                         eDataType, nDTSize, nValidX);
     472             :                 }
     473       62567 :                 const int nBlockId = ComputeBlockId(nXBlock, nYBlock);
     474      125134 :                 if (m_poGDS->WriteEncodedTileOrStrip(
     475       62567 :                         nBlockId, m_poGDS->m_pabyBlockBuf,
     476       62567 :                         /* bPreserveDataBuffer= */ false) != CE_None)
     477             :                 {
     478           0 :                     return CE_Failure;
     479             :                 }
     480             :             }
     481             :         }
     482        5802 :         return CE_None;
     483             :     }
     484             : 
     485           0 :     std::unique_ptr<GTiffDataset::JPEGOverviewVisibilitySetter> setter;
     486     5773490 :     if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
     487             :     {
     488     5770990 :         setter = m_poGDS->MakeJPEGOverviewVisible();
     489     5770990 :         CPL_IGNORE_RET_VAL(setter);
     490             :     }
     491     5773490 :     const CPLErr eErr = GDALPamRasterBand::IRasterIO(
     492             :         eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     493             :         eBufType, nPixelSpace, nLineSpace, psExtraArg);
     494             : 
     495     5773490 :     m_poGDS->m_bLoadingOtherBands = false;
     496             : 
     497     5773490 :     return eErr;
     498             : }
     499             : 
     500             : /************************************************************************/
     501             : /*                           ComputeBlockId()                           */
     502             : /************************************************************************/
     503             : 
     504             : /** Computes the TIFF block identifier from the tile coordinate, band
     505             :  * number and planar configuration.
     506             :  */
     507     3307600 : int GTiffRasterBand::ComputeBlockId(int nBlockXOff, int nBlockYOff) const
     508             : {
     509     3307600 :     const int nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
     510     3307600 :     if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
     511             :     {
     512      665035 :         return nBlockId + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
     513             :     }
     514     2642560 :     return nBlockId;
     515             : }

Generated by: LCOV version 1.14