Coverage Report

Created: 2026-06-30 08:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/gtiff/gtiffrasterband.cpp
Line
Count
Source
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
GTiffRasterBand::GTiffRasterBand(GTiffDataset *poDSIn, int nBandIn)
29
82.7M
    : m_poGDS(poDSIn)
30
82.7M
{
31
82.7M
    poDS = poDSIn;
32
82.7M
    nBand = nBandIn;
33
34
    /* -------------------------------------------------------------------- */
35
    /*      Get the GDAL data type.                                         */
36
    /* -------------------------------------------------------------------- */
37
82.7M
    const uint16_t nBitsPerSample = m_poGDS->m_nBitsPerSample;
38
82.7M
    const uint16_t nSampleFormat = m_poGDS->m_nSampleFormat;
39
40
82.7M
    eDataType = GDT_Unknown;
41
42
82.7M
    if (nBitsPerSample <= 8)
43
68.9M
    {
44
68.9M
        if (nSampleFormat == SAMPLEFORMAT_INT)
45
6.84M
            eDataType = GDT_Int8;
46
62.1M
        else
47
62.1M
            eDataType = GDT_UInt8;
48
68.9M
    }
49
13.7M
    else if (nBitsPerSample <= 16)
50
5.96M
    {
51
5.96M
        if (nBitsPerSample == 16 && nSampleFormat == SAMPLEFORMAT_IEEEFP)
52
3.13M
            eDataType = GDT_Float16;
53
2.83M
        else if (nSampleFormat == SAMPLEFORMAT_INT)
54
223k
            eDataType = GDT_Int16;
55
2.60M
        else
56
2.60M
            eDataType = GDT_UInt16;
57
5.96M
    }
58
7.79M
    else if (nBitsPerSample == 32)
59
1.99M
    {
60
1.99M
        if (nSampleFormat == SAMPLEFORMAT_COMPLEXINT)
61
281k
            eDataType = GDT_CInt16;
62
1.71M
        else if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
63
14.9k
            eDataType = GDT_CFloat16;
64
1.70M
        else if (nSampleFormat == SAMPLEFORMAT_IEEEFP)
65
349k
            eDataType = GDT_Float32;
66
1.35M
        else if (nSampleFormat == SAMPLEFORMAT_INT)
67
215k
            eDataType = GDT_Int32;
68
1.13M
        else
69
1.13M
            eDataType = GDT_UInt32;
70
1.99M
    }
71
5.79M
    else if (nBitsPerSample == 64)
72
1.67M
    {
73
1.67M
        if (nSampleFormat == SAMPLEFORMAT_IEEEFP)
74
473k
            eDataType = GDT_Float64;
75
1.20M
        else if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
76
164k
            eDataType = GDT_CFloat32;
77
1.04M
        else if (nSampleFormat == SAMPLEFORMAT_COMPLEXINT)
78
278k
            eDataType = GDT_CInt32;
79
762k
        else if (nSampleFormat == SAMPLEFORMAT_INT)
80
84.6k
            eDataType = GDT_Int64;
81
678k
        else
82
678k
            eDataType = GDT_UInt64;
83
1.67M
    }
84
4.12M
    else if (nBitsPerSample == 128)
85
263k
    {
86
263k
        if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
87
118k
            eDataType = GDT_CFloat64;
88
263k
    }
89
90
    /* -------------------------------------------------------------------- */
91
    /*      Try to work out band color interpretation.                      */
92
    /* -------------------------------------------------------------------- */
93
82.7M
    bool bLookForExtraSamples = false;
94
95
82.7M
    if (m_poGDS->m_poColorTable != nullptr && nBand == 1)
96
4.94k
    {
97
4.94k
        m_eBandInterp = GCI_PaletteIndex;
98
4.94k
    }
99
82.7M
    else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
100
80.9M
             (m_poGDS->m_nPhotometric == PHOTOMETRIC_YCBCR &&
101
916k
              m_poGDS->m_nCompression == COMPRESSION_JPEG &&
102
274k
              CPLTestBool(CPLGetConfigOption("CONVERT_YCBCR_TO_RGB", "YES"))))
103
2.10M
    {
104
2.10M
        if (nBand == 1)
105
11.2k
            m_eBandInterp = GCI_RedBand;
106
2.09M
        else if (nBand == 2)
107
10.1k
            m_eBandInterp = GCI_GreenBand;
108
2.08M
        else if (nBand == 3)
109
10.1k
            m_eBandInterp = GCI_BlueBand;
110
2.07M
        else
111
2.07M
            bLookForExtraSamples = true;
112
2.10M
    }
113
80.6M
    else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_YCBCR)
114
642k
    {
115
642k
        if (nBand == 1)
116
17.0k
            m_eBandInterp = GCI_YCbCr_YBand;
117
625k
        else if (nBand == 2)
118
17.0k
            m_eBandInterp = GCI_YCbCr_CbBand;
119
608k
        else if (nBand == 3)
120
17.0k
            m_eBandInterp = GCI_YCbCr_CrBand;
121
591k
        else
122
591k
            bLookForExtraSamples = true;
123
642k
    }
124
80.0M
    else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_SEPARATED)
125
2.96M
    {
126
2.96M
        if (nBand == 1)
127
3.32k
            m_eBandInterp = GCI_CyanBand;
128
2.96M
        else if (nBand == 2)
129
2.85k
            m_eBandInterp = GCI_MagentaBand;
130
2.96M
        else if (nBand == 3)
131
2.78k
            m_eBandInterp = GCI_YellowBand;
132
2.95M
        else if (nBand == 4)
133
2.71k
            m_eBandInterp = GCI_BlackBand;
134
2.95M
        else
135
2.95M
            bLookForExtraSamples = true;
136
2.96M
    }
137
77.0M
    else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK && nBand == 1)
138
191k
    {
139
191k
        m_eBandInterp = GCI_GrayIndex;
140
191k
    }
141
76.8M
    else
142
76.8M
    {
143
76.8M
        bLookForExtraSamples = true;
144
76.8M
    }
145
146
82.7M
    if (bLookForExtraSamples)
147
82.4M
    {
148
82.4M
        uint16_t *v = nullptr;
149
82.4M
        uint16_t count = 0;
150
151
82.4M
        if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v))
152
3.80M
        {
153
3.80M
            const int nBaseSamples = m_poGDS->m_nSamplesPerPixel - count;
154
3.80M
            const int nExpectedBaseSamples =
155
3.80M
                (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK)   ? 1
156
3.80M
                : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISWHITE) ? 1
157
1.68M
                : (m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB)        ? 3
158
1.43M
                : (m_poGDS->m_nPhotometric == PHOTOMETRIC_YCBCR)      ? 3
159
1.08M
                : (m_poGDS->m_nPhotometric == PHOTOMETRIC_SEPARATED)  ? 4
160
997k
                                                                      : 0;
161
162
3.80M
            if (nExpectedBaseSamples > 0 && nBand == nExpectedBaseSamples + 1 &&
163
3.62k
                nBaseSamples != nExpectedBaseSamples)
164
85
            {
165
85
                ReportError(
166
85
                    CE_Warning, CPLE_AppDefined,
167
85
                    "Wrong number of ExtraSamples : %d. %d were expected",
168
85
                    count, m_poGDS->m_nSamplesPerPixel - nExpectedBaseSamples);
169
85
            }
170
171
3.80M
            if (nBand > nBaseSamples && nBand - nBaseSamples - 1 < count &&
172
3.19M
                (v[nBand - nBaseSamples - 1] == EXTRASAMPLE_ASSOCALPHA ||
173
3.18M
                 v[nBand - nBaseSamples - 1] == EXTRASAMPLE_UNASSALPHA))
174
6.56k
            {
175
6.56k
                if (v[nBand - nBaseSamples - 1] == EXTRASAMPLE_ASSOCALPHA)
176
2.09k
                    m_oGTiffMDMD.SetMetadataItem("ALPHA", "PREMULTIPLIED",
177
2.09k
                                                 GDAL_MDD_IMAGE_STRUCTURE);
178
6.56k
                m_eBandInterp = GCI_AlphaBand;
179
6.56k
            }
180
3.80M
            else
181
3.80M
                m_eBandInterp = GCI_Undefined;
182
3.80M
        }
183
78.6M
        else
184
78.6M
        {
185
78.6M
            m_eBandInterp = GCI_Undefined;
186
78.6M
        }
187
82.4M
    }
188
189
    /* -------------------------------------------------------------------- */
190
    /*      Establish block size for strip or tiles.                        */
191
    /* -------------------------------------------------------------------- */
192
82.7M
    nBlockXSize = m_poGDS->m_nBlockXSize;
193
82.7M
    nBlockYSize = m_poGDS->m_nBlockYSize;
194
82.7M
    nRasterXSize = m_poGDS->nRasterXSize;
195
82.7M
    nRasterYSize = m_poGDS->nRasterYSize;
196
82.7M
    nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
197
82.7M
    nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
198
82.7M
}
199
200
/************************************************************************/
201
/*                          ~GTiffRasterBand()                          */
202
/************************************************************************/
203
204
GTiffRasterBand::~GTiffRasterBand()
205
82.7M
{
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
82.7M
    if (!m_aSetPSelf.empty())
210
0
    {
211
0
        ReportError(CE_Warning, CPLE_AppDefined,
212
0
                    "Virtual memory objects still exist at GTiffRasterBand "
213
0
                    "destruction");
214
0
        std::set<GTiffRasterBand **>::iterator oIter = m_aSetPSelf.begin();
215
0
        for (; oIter != m_aSetPSelf.end(); ++oIter)
216
0
            *(*oIter) = nullptr;
217
0
    }
218
82.7M
}
219
220
/************************************************************************/
221
/*                MayMultiBlockReadingBeMultiThreaded()                 */
222
/************************************************************************/
223
224
bool GTiffRasterBand::MayMultiBlockReadingBeMultiThreaded() const
225
0
{
226
0
    return m_poGDS->m_nDisableMultiThreadedRead == 0 &&
227
0
           m_poGDS->m_poThreadPool != nullptr &&
228
0
           m_poGDS->IsMultiThreadedReadCompatible();
229
0
}
230
231
/************************************************************************/
232
/*                             IRasterIO()                              */
233
/************************************************************************/
234
235
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
1.64M
{
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
1.64M
    if (nBufXSize < nXSize && nBufYSize < nYSize)
249
7.54k
    {
250
7.54k
        int bTried = FALSE;
251
7.54k
        std::unique_ptr<GTiffDataset::JPEGOverviewVisibilitySetter> setter;
252
7.54k
        if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
253
6.47k
        {
254
6.47k
            setter = m_poGDS->MakeJPEGOverviewVisible();
255
6.47k
            CPL_IGNORE_RET_VAL(setter);
256
6.47k
        }
257
7.54k
        const CPLErr eErr = TryOverviewRasterIO(
258
7.54k
            eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
259
7.54k
            eBufType, nPixelSpace, nLineSpace, psExtraArg, &bTried);
260
7.54k
        if (bTried)
261
594
            return eErr;
262
7.54k
    }
263
264
1.64M
    if (m_poGDS->m_eVirtualMemIOUsage != GTiffDataset::VirtualMemIOEnum::NO)
265
0
    {
266
0
        const int nErr = m_poGDS->VirtualMemIO(
267
0
            eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
268
0
            eBufType, 1, &nBand, nPixelSpace, nLineSpace, 0, psExtraArg);
269
0
        if (nErr >= 0)
270
0
            return static_cast<CPLErr>(nErr);
271
0
    }
272
1.64M
    if (m_poGDS->m_bDirectIO)
273
0
    {
274
0
        int nErr =
275
0
            DirectIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
276
0
                     nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
277
0
        if (nErr >= 0)
278
0
            return static_cast<CPLErr>(nErr);
279
0
    }
280
281
1.64M
    bool bCanUseMultiThreadedRead = false;
282
1.64M
    if (m_poGDS->m_nDisableMultiThreadedRead == 0 && eRWFlag == GF_Read &&
283
1.59M
        m_poGDS->m_poThreadPool != nullptr && nXSize == nBufXSize &&
284
0
        nYSize == nBufYSize && m_poGDS->IsMultiThreadedReadCompatible())
285
0
    {
286
0
        const int nBlockX1 = nXOff / nBlockXSize;
287
0
        const int nBlockY1 = nYOff / nBlockYSize;
288
0
        const int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
289
0
        const int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
290
0
        const int nXBlocks = nBlockX2 - nBlockX1 + 1;
291
0
        const int nYBlocks = nBlockY2 - nBlockY1 + 1;
292
0
        if (nXBlocks > 1 || nYBlocks > 1)
293
0
        {
294
0
            bCanUseMultiThreadedRead = true;
295
0
        }
296
0
    }
297
298
    // Cleanup data cached by below CacheMultiRange() call.
299
1.64M
    struct BufferedDataFreer
300
1.64M
    {
301
1.64M
        void *m_pBufferedData = nullptr;
302
1.64M
        TIFF *m_hTIFF = nullptr;
303
304
1.64M
        void Init(void *pBufferedData, TIFF *hTIFF)
305
1.64M
        {
306
0
            m_pBufferedData = pBufferedData;
307
0
            m_hTIFF = hTIFF;
308
0
        }
309
310
1.64M
        ~BufferedDataFreer()
311
1.64M
        {
312
1.64M
            if (m_pBufferedData)
313
0
            {
314
0
                VSIFree(m_pBufferedData);
315
0
                VSI_TIFFSetCachedRanges(TIFFClientdata(m_hTIFF), 0, nullptr,
316
0
                                        nullptr, nullptr);
317
0
            }
318
1.64M
        }
319
1.64M
    };
320
321
    // bufferedDataFreer must be left in this scope !
322
1.64M
    BufferedDataFreer bufferedDataFreer;
323
324
1.64M
    if (m_poGDS->eAccess == GA_ReadOnly && eRWFlag == GF_Read &&
325
1.59M
        m_poGDS->HasOptimizedReadMultiRange())
326
0
    {
327
0
        if (bCanUseMultiThreadedRead &&
328
0
            VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF))->HasPRead())
329
0
        {
330
            // use the multi-threaded implementation rather than the multi-range
331
            // one
332
0
        }
333
0
        else
334
0
        {
335
0
            bCanUseMultiThreadedRead = false;
336
0
            GTiffDataset *poDSForCache = m_poGDS;
337
0
            int nBandForCache = nBand;
338
0
            if (!m_poGDS->m_bStreamingIn && m_poGDS->m_bBlockOrderRowMajor &&
339
0
                m_poGDS->m_bLeaderSizeAsUInt4 &&
340
0
                m_poGDS->m_bMaskInterleavedWithImagery &&
341
0
                m_poGDS->m_poImageryDS)
342
0
            {
343
0
                poDSForCache = m_poGDS->m_poImageryDS;
344
0
                nBandForCache = 1;
345
0
            }
346
0
            bufferedDataFreer.Init(
347
0
                poDSForCache->CacheMultiRange(nXOff, nYOff, nXSize, nYSize,
348
0
                                              nBufXSize, nBufYSize,
349
0
                                              &nBandForCache, 1, psExtraArg),
350
0
                poDSForCache->m_hTIFF);
351
0
        }
352
0
    }
353
354
1.64M
    if (eRWFlag == GF_Read && nXSize == nBufXSize && nYSize == nBufYSize)
355
1.58M
    {
356
1.58M
        const int nBlockX1 = nXOff / nBlockXSize;
357
1.58M
        const int nBlockY1 = nYOff / nBlockYSize;
358
1.58M
        const int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
359
1.58M
        const int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
360
1.58M
        const int nXBlocks = nBlockX2 - nBlockX1 + 1;
361
1.58M
        const int nYBlocks = nBlockY2 - nBlockY1 + 1;
362
363
1.58M
        if (bCanUseMultiThreadedRead)
364
0
        {
365
0
            return m_poGDS->MultiThreadedRead(nXOff, nYOff, nXSize, nYSize,
366
0
                                              pData, eBufType, 1, &nBand,
367
0
                                              nPixelSpace, nLineSpace, 0);
368
0
        }
369
1.58M
        else if (m_poGDS->nBands != 1 &&
370
1.03M
                 m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
371
921k
        {
372
921k
            const GIntBig nRequiredMem =
373
921k
                static_cast<GIntBig>(m_poGDS->nBands) * nXBlocks * nYBlocks *
374
921k
                nBlockXSize * nBlockYSize * GDALGetDataTypeSizeBytes(eDataType);
375
921k
            if (nRequiredMem > GDALGetCacheMax64())
376
0
            {
377
0
                if (!m_poGDS->m_bHasWarnedDisableAggressiveBandCaching)
378
0
                {
379
0
                    CPLDebug("GTiff",
380
0
                             "Disable aggressive band caching. "
381
0
                             "Cache not big enough. "
382
0
                             "At least " CPL_FRMT_GIB " bytes necessary",
383
0
                             nRequiredMem);
384
0
                    m_poGDS->m_bHasWarnedDisableAggressiveBandCaching = true;
385
0
                }
386
0
                m_poGDS->m_bLoadingOtherBands = true;
387
0
            }
388
921k
        }
389
1.58M
    }
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
58.6k
    else if (eRWFlag == GF_Write &&
396
             // Could be extended to "odd bit" case, but more work
397
46.2k
             m_poGDS->m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
398
22.2k
             nXSize == nBufXSize && nYSize == nBufYSize && !HasBlockCache() &&
399
3.56k
             !m_poGDS->m_bLoadedBlockDirty &&
400
3.56k
             (m_poGDS->nBands == 1 ||
401
3.33k
              m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE) &&
402
3.56k
             !m_poGDS->m_bLeaderSizeAsUInt4 && (nXOff % nBlockXSize) == 0 &&
403
3.56k
             (nYOff % nBlockYSize) == 0 &&
404
3.56k
             (nXOff + nXSize == nRasterXSize || (nXSize % nBlockXSize) == 0) &&
405
3.56k
             (nYOff + nYSize == nRasterYSize || (nYSize % nBlockYSize) == 0))
406
3.46k
    {
407
3.46k
        m_poGDS->Crystalize();
408
409
3.46k
        if (m_poGDS->m_bDebugDontWriteBlocks)
410
0
            return CE_None;
411
412
3.46k
        const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
413
3.46k
        if (nXSize == nBlockXSize && nYSize == nBlockYSize &&
414
3.41k
            eBufType == eDataType && nPixelSpace == nDTSize &&
415
3.41k
            nLineSpace == nPixelSpace * nBlockXSize)
416
3.41k
        {
417
            // If writing one single block with the right data type and layout,
418
            // we don't need a temporary buffer
419
3.41k
            const int nBlockId =
420
3.41k
                ComputeBlockId(nXOff / nBlockXSize, nYOff / nBlockYSize);
421
3.41k
            return m_poGDS->WriteEncodedTileOrStrip(
422
3.41k
                nBlockId, pData, /* bPreserveDataBuffer= */ true);
423
3.41k
        }
424
425
        // Make sure m_poGDS->m_pabyBlockBuf is allocated.
426
        // We could actually use any temporary buffer
427
47
        if (m_poGDS->LoadBlockBuf(/* nBlockId = */ -1,
428
47
                                  /* bReadFromDisk = */ false) != CE_None)
429
0
        {
430
0
            return CE_Failure;
431
0
        }
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
47
        const int nYBlockStart = nYOff / nBlockYSize;
439
47
        const int nYBlockEnd = 1 + (nYOff + nYSize - 1) / nBlockYSize;
440
47
        const int nXBlockStart = nXOff / nBlockXSize;
441
47
        const int nXBlockEnd = 1 + (nXOff + nXSize - 1) / nBlockXSize;
442
223
        for (int nYBlock = nYBlockStart; nYBlock < nYBlockEnd; ++nYBlock)
443
176
        {
444
176
            const int nValidY =
445
176
                std::min(nBlockYSize, nRasterYSize - nYBlock * nBlockYSize);
446
422
            for (int nXBlock = nXBlockStart; nXBlock < nXBlockEnd; ++nXBlock)
447
246
            {
448
246
                const int nValidX =
449
246
                    std::min(nBlockXSize, nRasterXSize - nXBlock * nBlockXSize);
450
246
                if (nValidY < nBlockYSize || nValidX < nBlockXSize)
451
96
                {
452
                    // Make sure padding bytes at the right/bottom of the
453
                    // tile are initialized to zero.
454
96
                    memset(m_poGDS->m_pabyBlockBuf, 0,
455
96
                           static_cast<size_t>(nBlockXSize) * nBlockYSize *
456
96
                               nDTSize);
457
96
                }
458
246
                const GByte *pabySrcData =
459
246
                    static_cast<const GByte *>(pData) +
460
246
                    static_cast<size_t>(nYBlock - nYBlockStart) * nBlockYSize *
461
246
                        nLineSpace +
462
246
                    static_cast<size_t>(nXBlock - nXBlockStart) * nBlockXSize *
463
246
                        nPixelSpace;
464
34.2k
                for (int iY = 0; iY < nValidY; ++iY)
465
34.0k
                {
466
34.0k
                    GDALCopyWords64(
467
34.0k
                        pabySrcData + static_cast<size_t>(iY) * nLineSpace,
468
34.0k
                        eBufType, static_cast<int>(nPixelSpace),
469
34.0k
                        m_poGDS->m_pabyBlockBuf +
470
34.0k
                            static_cast<size_t>(iY) * nBlockXSize * nDTSize,
471
34.0k
                        eDataType, nDTSize, nValidX);
472
34.0k
                }
473
246
                const int nBlockId = ComputeBlockId(nXBlock, nYBlock);
474
246
                if (m_poGDS->WriteEncodedTileOrStrip(
475
246
                        nBlockId, m_poGDS->m_pabyBlockBuf,
476
246
                        /* bPreserveDataBuffer= */ false) != CE_None)
477
0
                {
478
0
                    return CE_Failure;
479
0
                }
480
246
            }
481
176
        }
482
47
        return CE_None;
483
47
    }
484
485
1.63M
    std::unique_ptr<GTiffDataset::JPEGOverviewVisibilitySetter> setter;
486
1.63M
    if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
487
1.63M
    {
488
1.63M
        setter = m_poGDS->MakeJPEGOverviewVisible();
489
1.63M
        CPL_IGNORE_RET_VAL(setter);
490
1.63M
    }
491
1.63M
    const CPLErr eErr = GDALPamRasterBand::IRasterIO(
492
1.63M
        eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
493
1.63M
        eBufType, nPixelSpace, nLineSpace, psExtraArg);
494
495
1.63M
    m_poGDS->m_bLoadingOtherBands = false;
496
497
1.63M
    return eErr;
498
1.64M
}
499
500
/************************************************************************/
501
/*                           ComputeBlockId()                           */
502
/************************************************************************/
503
504
/** Computes the TIFF block identifier from the tile coordinate, band
505
 * number and planar configuration.
506
 */
507
int GTiffRasterBand::ComputeBlockId(int nBlockXOff, int nBlockYOff) const
508
1.82M
{
509
1.82M
    const int nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
510
1.82M
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
511
330k
    {
512
330k
        return nBlockId + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
513
330k
    }
514
1.49M
    return nBlockId;
515
1.82M
}