Coverage Report

Created: 2026-02-14 06:52

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
0
    : m_poGDS(poDSIn)
30
0
{
31
0
    poDS = poDSIn;
32
0
    nBand = nBandIn;
33
34
    /* -------------------------------------------------------------------- */
35
    /*      Get the GDAL data type.                                         */
36
    /* -------------------------------------------------------------------- */
37
0
    const uint16_t nBitsPerSample = m_poGDS->m_nBitsPerSample;
38
0
    const uint16_t nSampleFormat = m_poGDS->m_nSampleFormat;
39
40
0
    eDataType = GDT_Unknown;
41
42
0
    if (nBitsPerSample <= 8)
43
0
    {
44
0
        if (nSampleFormat == SAMPLEFORMAT_INT)
45
0
            eDataType = GDT_Int8;
46
0
        else
47
0
            eDataType = GDT_UInt8;
48
0
    }
49
0
    else if (nBitsPerSample <= 16)
50
0
    {
51
0
        if (nBitsPerSample == 16 && nSampleFormat == SAMPLEFORMAT_IEEEFP)
52
0
            eDataType = GDT_Float16;
53
0
        else if (nSampleFormat == SAMPLEFORMAT_INT)
54
0
            eDataType = GDT_Int16;
55
0
        else
56
0
            eDataType = GDT_UInt16;
57
0
    }
58
0
    else if (nBitsPerSample == 32)
59
0
    {
60
0
        if (nSampleFormat == SAMPLEFORMAT_COMPLEXINT)
61
0
            eDataType = GDT_CInt16;
62
0
        else if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
63
0
            eDataType = GDT_CFloat16;
64
0
        else if (nSampleFormat == SAMPLEFORMAT_IEEEFP)
65
0
            eDataType = GDT_Float32;
66
0
        else if (nSampleFormat == SAMPLEFORMAT_INT)
67
0
            eDataType = GDT_Int32;
68
0
        else
69
0
            eDataType = GDT_UInt32;
70
0
    }
71
0
    else if (nBitsPerSample == 64)
72
0
    {
73
0
        if (nSampleFormat == SAMPLEFORMAT_IEEEFP)
74
0
            eDataType = GDT_Float64;
75
0
        else if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
76
0
            eDataType = GDT_CFloat32;
77
0
        else if (nSampleFormat == SAMPLEFORMAT_COMPLEXINT)
78
0
            eDataType = GDT_CInt32;
79
0
        else if (nSampleFormat == SAMPLEFORMAT_INT)
80
0
            eDataType = GDT_Int64;
81
0
        else
82
0
            eDataType = GDT_UInt64;
83
0
    }
84
0
    else if (nBitsPerSample == 128)
85
0
    {
86
0
        if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
87
0
            eDataType = GDT_CFloat64;
88
0
    }
89
90
    /* -------------------------------------------------------------------- */
91
    /*      Try to work out band color interpretation.                      */
92
    /* -------------------------------------------------------------------- */
93
0
    bool bLookForExtraSamples = false;
94
95
0
    if (m_poGDS->m_poColorTable != nullptr && nBand == 1)
96
0
    {
97
0
        m_eBandInterp = GCI_PaletteIndex;
98
0
    }
99
0
    else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
100
0
             (m_poGDS->m_nPhotometric == PHOTOMETRIC_YCBCR &&
101
0
              m_poGDS->m_nCompression == COMPRESSION_JPEG &&
102
0
              CPLTestBool(CPLGetConfigOption("CONVERT_YCBCR_TO_RGB", "YES"))))
103
0
    {
104
0
        if (nBand == 1)
105
0
            m_eBandInterp = GCI_RedBand;
106
0
        else if (nBand == 2)
107
0
            m_eBandInterp = GCI_GreenBand;
108
0
        else if (nBand == 3)
109
0
            m_eBandInterp = GCI_BlueBand;
110
0
        else
111
0
            bLookForExtraSamples = true;
112
0
    }
113
0
    else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_YCBCR)
114
0
    {
115
0
        if (nBand == 1)
116
0
            m_eBandInterp = GCI_YCbCr_YBand;
117
0
        else if (nBand == 2)
118
0
            m_eBandInterp = GCI_YCbCr_CbBand;
119
0
        else if (nBand == 3)
120
0
            m_eBandInterp = GCI_YCbCr_CrBand;
121
0
        else
122
0
            bLookForExtraSamples = true;
123
0
    }
124
0
    else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_SEPARATED)
125
0
    {
126
0
        if (nBand == 1)
127
0
            m_eBandInterp = GCI_CyanBand;
128
0
        else if (nBand == 2)
129
0
            m_eBandInterp = GCI_MagentaBand;
130
0
        else if (nBand == 3)
131
0
            m_eBandInterp = GCI_YellowBand;
132
0
        else if (nBand == 4)
133
0
            m_eBandInterp = GCI_BlackBand;
134
0
        else
135
0
            bLookForExtraSamples = true;
136
0
    }
137
0
    else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK && nBand == 1)
138
0
    {
139
0
        m_eBandInterp = GCI_GrayIndex;
140
0
    }
141
0
    else
142
0
    {
143
0
        bLookForExtraSamples = true;
144
0
    }
145
146
0
    if (bLookForExtraSamples)
147
0
    {
148
0
        uint16_t *v = nullptr;
149
0
        uint16_t count = 0;
150
151
0
        if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v))
152
0
        {
153
0
            const int nBaseSamples = m_poGDS->m_nSamplesPerPixel - count;
154
0
            const int nExpectedBaseSamples =
155
0
                (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK)   ? 1
156
0
                : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISWHITE) ? 1
157
0
                : (m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB)        ? 3
158
0
                : (m_poGDS->m_nPhotometric == PHOTOMETRIC_YCBCR)      ? 3
159
0
                : (m_poGDS->m_nPhotometric == PHOTOMETRIC_SEPARATED)  ? 4
160
0
                                                                      : 0;
161
162
0
            if (nExpectedBaseSamples > 0 && nBand == nExpectedBaseSamples + 1 &&
163
0
                nBaseSamples != nExpectedBaseSamples)
164
0
            {
165
0
                ReportError(
166
0
                    CE_Warning, CPLE_AppDefined,
167
0
                    "Wrong number of ExtraSamples : %d. %d were expected",
168
0
                    count, m_poGDS->m_nSamplesPerPixel - nExpectedBaseSamples);
169
0
            }
170
171
0
            if (nBand > nBaseSamples && nBand - nBaseSamples - 1 < count &&
172
0
                (v[nBand - nBaseSamples - 1] == EXTRASAMPLE_ASSOCALPHA ||
173
0
                 v[nBand - nBaseSamples - 1] == EXTRASAMPLE_UNASSALPHA))
174
0
            {
175
0
                if (v[nBand - nBaseSamples - 1] == EXTRASAMPLE_ASSOCALPHA)
176
0
                    m_oGTiffMDMD.SetMetadataItem("ALPHA", "PREMULTIPLIED",
177
0
                                                 "IMAGE_STRUCTURE");
178
0
                m_eBandInterp = GCI_AlphaBand;
179
0
            }
180
0
            else
181
0
                m_eBandInterp = GCI_Undefined;
182
0
        }
183
0
        else
184
0
        {
185
0
            m_eBandInterp = GCI_Undefined;
186
0
        }
187
0
    }
188
189
    /* -------------------------------------------------------------------- */
190
    /*      Establish block size for strip or tiles.                        */
191
    /* -------------------------------------------------------------------- */
192
0
    nBlockXSize = m_poGDS->m_nBlockXSize;
193
0
    nBlockYSize = m_poGDS->m_nBlockYSize;
194
0
    nRasterXSize = m_poGDS->nRasterXSize;
195
0
    nRasterYSize = m_poGDS->nRasterYSize;
196
0
    nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
197
0
    nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
198
0
}
199
200
/************************************************************************/
201
/*                          ~GTiffRasterBand()                          */
202
/************************************************************************/
203
204
GTiffRasterBand::~GTiffRasterBand()
205
0
{
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
0
    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
0
}
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
0
{
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
0
    if (nBufXSize < nXSize && nBufYSize < nYSize)
249
0
    {
250
0
        int bTried = FALSE;
251
0
        std::unique_ptr<GTiffDataset::JPEGOverviewVisibilitySetter> setter;
252
0
        if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
253
0
        {
254
0
            setter = m_poGDS->MakeJPEGOverviewVisible();
255
0
            CPL_IGNORE_RET_VAL(setter);
256
0
        }
257
0
        const CPLErr eErr = TryOverviewRasterIO(
258
0
            eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
259
0
            eBufType, nPixelSpace, nLineSpace, psExtraArg, &bTried);
260
0
        if (bTried)
261
0
            return eErr;
262
0
    }
263
264
0
    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
0
    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
0
    bool bCanUseMultiThreadedRead = false;
282
0
    if (m_poGDS->m_nDisableMultiThreadedRead == 0 && eRWFlag == GF_Read &&
283
0
        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
0
    struct BufferedDataFreer
300
0
    {
301
0
        void *m_pBufferedData = nullptr;
302
0
        TIFF *m_hTIFF = nullptr;
303
304
0
        void Init(void *pBufferedData, TIFF *hTIFF)
305
0
        {
306
0
            m_pBufferedData = pBufferedData;
307
0
            m_hTIFF = hTIFF;
308
0
        }
309
310
0
        ~BufferedDataFreer()
311
0
        {
312
0
            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
0
        }
319
0
    };
320
321
    // bufferedDataFreer must be left in this scope !
322
0
    BufferedDataFreer bufferedDataFreer;
323
324
0
    if (m_poGDS->eAccess == GA_ReadOnly && eRWFlag == GF_Read &&
325
0
        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
0
    if (eRWFlag == GF_Read && nXSize == nBufXSize && nYSize == nBufYSize)
355
0
    {
356
0
        const int nBlockX1 = nXOff / nBlockXSize;
357
0
        const int nBlockY1 = nYOff / nBlockYSize;
358
0
        const int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
359
0
        const int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
360
0
        const int nXBlocks = nBlockX2 - nBlockX1 + 1;
361
0
        const int nYBlocks = nBlockY2 - nBlockY1 + 1;
362
363
0
        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
0
        else if (m_poGDS->nBands != 1 &&
370
0
                 m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
371
0
        {
372
0
            const GIntBig nRequiredMem =
373
0
                static_cast<GIntBig>(m_poGDS->nBands) * nXBlocks * nYBlocks *
374
0
                nBlockXSize * nBlockYSize * GDALGetDataTypeSizeBytes(eDataType);
375
0
            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
0
        }
389
0
    }
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
0
    else if (eRWFlag == GF_Write &&
396
             // Could be extended to "odd bit" case, but more work
397
0
             m_poGDS->m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
398
0
             nXSize == nBufXSize && nYSize == nBufYSize && !HasBlockCache() &&
399
0
             !m_poGDS->m_bLoadedBlockDirty &&
400
0
             (m_poGDS->nBands == 1 ||
401
0
              m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE) &&
402
0
             !m_poGDS->m_bLeaderSizeAsUInt4 && (nXOff % nBlockXSize) == 0 &&
403
0
             (nYOff % nBlockYSize) == 0 &&
404
0
             (nXOff + nXSize == nRasterXSize || (nXSize % nBlockXSize) == 0) &&
405
0
             (nYOff + nYSize == nRasterYSize || (nYSize % nBlockYSize) == 0))
406
0
    {
407
0
        m_poGDS->Crystalize();
408
409
0
        if (m_poGDS->m_bDebugDontWriteBlocks)
410
0
            return CE_None;
411
412
0
        const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
413
0
        if (nXSize == nBlockXSize && nYSize == nBlockYSize &&
414
0
            eBufType == eDataType && nPixelSpace == nDTSize &&
415
0
            nLineSpace == nPixelSpace * nBlockXSize)
416
0
        {
417
            // If writing one single block with the right data type and layout,
418
            // we don't need a temporary buffer
419
0
            const int nBlockId =
420
0
                ComputeBlockId(nXOff / nBlockXSize, nYOff / nBlockYSize);
421
0
            return m_poGDS->WriteEncodedTileOrStrip(
422
0
                nBlockId, pData, /* bPreserveDataBuffer= */ true);
423
0
        }
424
425
        // Make sure m_poGDS->m_pabyBlockBuf is allocated.
426
        // We could actually use any temporary buffer
427
0
        if (m_poGDS->LoadBlockBuf(/* nBlockId = */ -1,
428
0
                                  /* 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
0
        const int nYBlockStart = nYOff / nBlockYSize;
439
0
        const int nYBlockEnd = 1 + (nYOff + nYSize - 1) / nBlockYSize;
440
0
        const int nXBlockStart = nXOff / nBlockXSize;
441
0
        const int nXBlockEnd = 1 + (nXOff + nXSize - 1) / nBlockXSize;
442
0
        for (int nYBlock = nYBlockStart; nYBlock < nYBlockEnd; ++nYBlock)
443
0
        {
444
0
            const int nValidY =
445
0
                std::min(nBlockYSize, nRasterYSize - nYBlock * nBlockYSize);
446
0
            for (int nXBlock = nXBlockStart; nXBlock < nXBlockEnd; ++nXBlock)
447
0
            {
448
0
                const int nValidX =
449
0
                    std::min(nBlockXSize, nRasterXSize - nXBlock * nBlockXSize);
450
0
                if (nValidY < nBlockYSize || nValidX < nBlockXSize)
451
0
                {
452
                    // Make sure padding bytes at the right/bottom of the
453
                    // tile are initialized to zero.
454
0
                    memset(m_poGDS->m_pabyBlockBuf, 0,
455
0
                           static_cast<size_t>(nBlockXSize) * nBlockYSize *
456
0
                               nDTSize);
457
0
                }
458
0
                const GByte *pabySrcData =
459
0
                    static_cast<const GByte *>(pData) +
460
0
                    static_cast<size_t>(nYBlock - nYBlockStart) * nBlockYSize *
461
0
                        nLineSpace +
462
0
                    static_cast<size_t>(nXBlock - nXBlockStart) * nBlockXSize *
463
0
                        nPixelSpace;
464
0
                for (int iY = 0; iY < nValidY; ++iY)
465
0
                {
466
0
                    GDALCopyWords64(
467
0
                        pabySrcData + static_cast<size_t>(iY) * nLineSpace,
468
0
                        eBufType, static_cast<int>(nPixelSpace),
469
0
                        m_poGDS->m_pabyBlockBuf +
470
0
                            static_cast<size_t>(iY) * nBlockXSize * nDTSize,
471
0
                        eDataType, nDTSize, nValidX);
472
0
                }
473
0
                const int nBlockId = ComputeBlockId(nXBlock, nYBlock);
474
0
                if (m_poGDS->WriteEncodedTileOrStrip(
475
0
                        nBlockId, m_poGDS->m_pabyBlockBuf,
476
0
                        /* bPreserveDataBuffer= */ false) != CE_None)
477
0
                {
478
0
                    return CE_Failure;
479
0
                }
480
0
            }
481
0
        }
482
0
        return CE_None;
483
0
    }
484
485
0
    std::unique_ptr<GTiffDataset::JPEGOverviewVisibilitySetter> setter;
486
0
    if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
487
0
    {
488
0
        setter = m_poGDS->MakeJPEGOverviewVisible();
489
0
        CPL_IGNORE_RET_VAL(setter);
490
0
    }
491
0
    const CPLErr eErr = GDALPamRasterBand::IRasterIO(
492
0
        eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
493
0
        eBufType, nPixelSpace, nLineSpace, psExtraArg);
494
495
0
    m_poGDS->m_bLoadingOtherBands = false;
496
497
0
    return eErr;
498
0
}
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
0
{
509
0
    const int nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
510
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
511
0
    {
512
0
        return nBlockId + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
513
0
    }
514
0
    return nBlockId;
515
0
}