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 : }
|