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 1032150 : GTiffRasterBand::GTiffRasterBand(GTiffDataset *poDSIn, int nBandIn)
29 1032150 : : m_poGDS(poDSIn)
30 : {
31 1032090 : poDS = poDSIn;
32 1032090 : nBand = nBandIn;
33 :
34 : /* -------------------------------------------------------------------- */
35 : /* Get the GDAL data type. */
36 : /* -------------------------------------------------------------------- */
37 1032090 : const uint16_t nBitsPerSample = m_poGDS->m_nBitsPerSample;
38 1032090 : const uint16_t nSampleFormat = m_poGDS->m_nSampleFormat;
39 :
40 1032090 : eDataType = GDT_Unknown;
41 :
42 1032090 : if (nBitsPerSample <= 8)
43 : {
44 889871 : if (nSampleFormat == SAMPLEFORMAT_INT)
45 310 : eDataType = GDT_Int8;
46 : else
47 889561 : eDataType = GDT_Byte;
48 : }
49 142221 : else if (nBitsPerSample <= 16)
50 : {
51 134423 : if (nBitsPerSample == 16 && nSampleFormat == SAMPLEFORMAT_IEEEFP)
52 248 : eDataType = GDT_Float16;
53 134175 : else if (nSampleFormat == SAMPLEFORMAT_INT)
54 67148 : eDataType = GDT_Int16;
55 : else
56 67027 : eDataType = GDT_UInt16;
57 : }
58 7798 : else if (nBitsPerSample == 32)
59 : {
60 4673 : if (nSampleFormat == SAMPLEFORMAT_COMPLEXINT)
61 683 : eDataType = GDT_CInt16;
62 3990 : else if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
63 224 : eDataType = GDT_CFloat16;
64 3766 : else if (nSampleFormat == SAMPLEFORMAT_IEEEFP)
65 2544 : eDataType = GDT_Float32;
66 1222 : else if (nSampleFormat == SAMPLEFORMAT_INT)
67 645 : eDataType = GDT_Int32;
68 : else
69 577 : eDataType = GDT_UInt32;
70 : }
71 3125 : else if (nBitsPerSample == 64)
72 : {
73 2579 : if (nSampleFormat == SAMPLEFORMAT_IEEEFP)
74 1137 : eDataType = GDT_Float64;
75 1442 : else if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
76 467 : eDataType = GDT_CFloat32;
77 975 : else if (nSampleFormat == SAMPLEFORMAT_COMPLEXINT)
78 436 : eDataType = GDT_CInt32;
79 539 : else if (nSampleFormat == SAMPLEFORMAT_INT)
80 278 : eDataType = GDT_Int64;
81 : else
82 261 : eDataType = GDT_UInt64;
83 : }
84 546 : else if (nBitsPerSample == 128)
85 : {
86 474 : if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
87 474 : eDataType = GDT_CFloat64;
88 : }
89 :
90 : /* -------------------------------------------------------------------- */
91 : /* Try to work out band color interpretation. */
92 : /* -------------------------------------------------------------------- */
93 1032090 : bool bLookForExtraSamples = false;
94 :
95 1032090 : if (m_poGDS->m_poColorTable != nullptr && nBand == 1)
96 : {
97 171 : m_eBandInterp = GCI_PaletteIndex;
98 : }
99 2045950 : else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
100 1014020 : (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 18661 : if (nBand == 1)
105 5875 : m_eBandInterp = GCI_RedBand;
106 12786 : else if (nBand == 2)
107 5883 : m_eBandInterp = GCI_GreenBand;
108 6903 : else if (nBand == 3)
109 5882 : m_eBandInterp = GCI_BlueBand;
110 : else
111 1021 : bLookForExtraSamples = true;
112 : }
113 1013280 : 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 1013240 : 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 1013140 : else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK && nBand == 1)
138 : {
139 26241 : m_eBandInterp = GCI_GrayIndex;
140 : }
141 : else
142 : {
143 986899 : bLookForExtraSamples = true;
144 : }
145 :
146 1032110 : if (bLookForExtraSamples)
147 : {
148 987775 : uint16_t *v = nullptr;
149 987775 : uint16_t count = 0;
150 :
151 987775 : if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v))
152 : {
153 921855 : const int nBaseSamples = m_poGDS->m_nSamplesPerPixel - count;
154 921855 : const int nExpectedBaseSamples =
155 922880 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK) ? 1
156 2050 : : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISWHITE) ? 1
157 1031 : : (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 921855 : 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 921855 : if (nBand > nBaseSamples && nBand - nBaseSamples - 1 < count &&
172 921850 : (v[nBand - nBaseSamples - 1] == EXTRASAMPLE_ASSOCALPHA ||
173 921833 : v[nBand - nBaseSamples - 1] == EXTRASAMPLE_UNASSALPHA))
174 : {
175 1119 : if (v[nBand - nBaseSamples - 1] == EXTRASAMPLE_ASSOCALPHA)
176 17 : m_oGTiffMDMD.SetMetadataItem("ALPHA", "PREMULTIPLIED",
177 : "IMAGE_STRUCTURE");
178 1119 : m_eBandInterp = GCI_AlphaBand;
179 : }
180 : else
181 920736 : 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 1032110 : nBlockXSize = m_poGDS->m_nBlockXSize;
193 1032110 : nBlockYSize = m_poGDS->m_nBlockYSize;
194 1032110 : nRasterXSize = m_poGDS->nRasterXSize;
195 1032110 : nRasterYSize = m_poGDS->nRasterYSize;
196 1032110 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
197 1032110 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
198 1032110 : }
199 :
200 : /************************************************************************/
201 : /* ~GTiffRasterBand() */
202 : /************************************************************************/
203 :
204 1932274 : 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 1032170 : 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 1932264 : }
219 :
220 : /************************************************************************/
221 : /* IRasterIO() */
222 : /************************************************************************/
223 :
224 5817160 : CPLErr GTiffRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
225 : int nXSize, int nYSize, void *pData,
226 : int nBufXSize, int nBufYSize,
227 : GDALDataType eBufType, GSpacing nPixelSpace,
228 : GSpacing nLineSpace,
229 : GDALRasterIOExtraArg *psExtraArg)
230 : {
231 : #if DEBUG_VERBOSE
232 : CPLDebug("GTiff", "RasterIO(%d, %d, %d, %d, %d, %d)", nXOff, nYOff, nXSize,
233 : nYSize, nBufXSize, nBufYSize);
234 : #endif
235 :
236 : // Try to pass the request to the most appropriate overview dataset.
237 5817160 : if (nBufXSize < nXSize && nBufYSize < nYSize)
238 : {
239 362408 : int bTried = FALSE;
240 362408 : if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
241 362040 : ++m_poGDS->m_nJPEGOverviewVisibilityCounter;
242 362408 : const CPLErr eErr = TryOverviewRasterIO(
243 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
244 : eBufType, nPixelSpace, nLineSpace, psExtraArg, &bTried);
245 362408 : if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
246 362040 : --m_poGDS->m_nJPEGOverviewVisibilityCounter;
247 362408 : if (bTried)
248 44 : return eErr;
249 : }
250 :
251 5817120 : if (m_poGDS->m_eVirtualMemIOUsage != GTiffDataset::VirtualMemIOEnum::NO)
252 : {
253 904 : const int nErr = m_poGDS->VirtualMemIO(
254 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
255 452 : eBufType, 1, &nBand, nPixelSpace, nLineSpace, 0, psExtraArg);
256 452 : if (nErr >= 0)
257 363 : return static_cast<CPLErr>(nErr);
258 : }
259 5816760 : if (m_poGDS->m_bDirectIO)
260 : {
261 : int nErr =
262 2522 : DirectIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
263 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
264 2522 : if (nErr >= 0)
265 1409 : return static_cast<CPLErr>(nErr);
266 : }
267 :
268 5815350 : bool bCanUseMultiThreadedRead = false;
269 5815090 : if (m_poGDS->m_nDisableMultiThreadedRead == 0 && eRWFlag == GF_Read &&
270 3356060 : m_poGDS->m_poThreadPool != nullptr && nXSize == nBufXSize &&
271 11630400 : nYSize == nBufYSize && m_poGDS->IsMultiThreadedReadCompatible())
272 : {
273 103 : const int nBlockX1 = nXOff / nBlockXSize;
274 103 : const int nBlockY1 = nYOff / nBlockYSize;
275 103 : const int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
276 103 : const int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
277 103 : const int nXBlocks = nBlockX2 - nBlockX1 + 1;
278 103 : const int nYBlocks = nBlockY2 - nBlockY1 + 1;
279 103 : if (nXBlocks > 1 || nYBlocks > 1)
280 : {
281 100 : bCanUseMultiThreadedRead = true;
282 : }
283 : }
284 :
285 : // Cleanup data cached by below CacheMultiRange() call.
286 : struct BufferedDataFreer
287 : {
288 : void *m_pBufferedData = nullptr;
289 : TIFF *m_hTIFF = nullptr;
290 :
291 254 : void Init(void *pBufferedData, TIFF *hTIFF)
292 : {
293 254 : m_pBufferedData = pBufferedData;
294 254 : m_hTIFF = hTIFF;
295 254 : }
296 :
297 5815330 : ~BufferedDataFreer()
298 5815330 : {
299 5815330 : if (m_pBufferedData)
300 : {
301 34 : VSIFree(m_pBufferedData);
302 34 : VSI_TIFFSetCachedRanges(TIFFClientdata(m_hTIFF), 0, nullptr,
303 : nullptr, nullptr);
304 : }
305 5815330 : }
306 : };
307 :
308 : // bufferedDataFreer must be left in this scope !
309 5815430 : BufferedDataFreer bufferedDataFreer;
310 :
311 8673680 : if (m_poGDS->eAccess == GA_ReadOnly && eRWFlag == GF_Read &&
312 2858360 : m_poGDS->HasOptimizedReadMultiRange())
313 : {
314 262 : if (bCanUseMultiThreadedRead &&
315 4 : VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF))->HasPRead())
316 : {
317 : // use the multi-threaded implementation rather than the multi-range
318 : // one
319 : }
320 : else
321 : {
322 254 : bCanUseMultiThreadedRead = false;
323 254 : GTiffDataset *poDSForCache = m_poGDS;
324 254 : int nBandForCache = nBand;
325 254 : if (!m_poGDS->m_bStreamingIn && m_poGDS->m_bBlockOrderRowMajor &&
326 110 : m_poGDS->m_bLeaderSizeAsUInt4 &&
327 110 : m_poGDS->m_bMaskInterleavedWithImagery &&
328 100 : m_poGDS->m_poImageryDS)
329 : {
330 62 : poDSForCache = m_poGDS->m_poImageryDS;
331 62 : nBandForCache = 1;
332 : }
333 254 : bufferedDataFreer.Init(
334 : poDSForCache->CacheMultiRange(nXOff, nYOff, nXSize, nYSize,
335 : nBufXSize, nBufYSize,
336 : &nBandForCache, 1, psExtraArg),
337 : poDSForCache->m_hTIFF);
338 : }
339 : }
340 :
341 5815320 : if (eRWFlag == GF_Read && nXSize == nBufXSize && nYSize == nBufYSize)
342 : {
343 2960310 : const int nBlockX1 = nXOff / nBlockXSize;
344 2960310 : const int nBlockY1 = nYOff / nBlockYSize;
345 2960310 : const int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
346 2960310 : const int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
347 2960310 : const int nXBlocks = nBlockX2 - nBlockX1 + 1;
348 2960310 : const int nYBlocks = nBlockY2 - nBlockY1 + 1;
349 :
350 2960310 : if (bCanUseMultiThreadedRead)
351 : {
352 200 : return m_poGDS->MultiThreadedRead(nXOff, nYOff, nXSize, nYSize,
353 100 : pData, eBufType, 1, &nBand,
354 100 : nPixelSpace, nLineSpace, 0);
355 : }
356 2960210 : else if (m_poGDS->nBands != 1 &&
357 738291 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
358 : {
359 : const GIntBig nRequiredMem =
360 678777 : static_cast<GIntBig>(m_poGDS->nBands) * nXBlocks * nYBlocks *
361 678777 : nBlockXSize * nBlockYSize * GDALGetDataTypeSizeBytes(eDataType);
362 678846 : if (nRequiredMem > GDALGetCacheMax64())
363 : {
364 9061 : if (!m_poGDS->m_bHasWarnedDisableAggressiveBandCaching)
365 : {
366 15 : CPLDebug("GTiff",
367 : "Disable aggressive band caching. "
368 : "Cache not big enough. "
369 : "At least " CPL_FRMT_GIB " bytes necessary",
370 : nRequiredMem);
371 15 : m_poGDS->m_bHasWarnedDisableAggressiveBandCaching = true;
372 : }
373 9061 : m_poGDS->m_bLoadingOtherBands = true;
374 : }
375 2960260 : }
376 : }
377 :
378 : // Write optimization when writing whole blocks, by-passing the block cache.
379 : // We require the block cache to be non instantiated to simplify things
380 : // (otherwise we might need to evict corresponding existing blocks from the
381 : // block cache).
382 5314030 : else if (eRWFlag == GF_Write &&
383 : // Could be extended to "odd bit" case, but more work
384 2459040 : m_poGDS->m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
385 2306860 : nXSize == nBufXSize && nYSize == nBufYSize && !HasBlockCache() &&
386 49686 : !m_poGDS->m_bLoadedBlockDirty &&
387 49673 : (m_poGDS->nBands == 1 ||
388 4488 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE) &&
389 48584 : !m_poGDS->m_bLeaderSizeAsUInt4 && (nXOff % nBlockXSize) == 0 &&
390 48543 : (nYOff % nBlockYSize) == 0 &&
391 5362420 : (nXOff + nXSize == nRasterXSize || (nXSize % nBlockXSize) == 0) &&
392 48379 : (nYOff + nYSize == nRasterYSize || (nYSize % nBlockYSize) == 0))
393 : {
394 48032 : m_poGDS->Crystalize();
395 :
396 48035 : if (m_poGDS->m_bDebugDontWriteBlocks)
397 0 : return CE_None;
398 :
399 48035 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
400 48039 : if (nXSize == nBlockXSize && nYSize == nBlockYSize &&
401 44017 : eBufType == eDataType && nPixelSpace == nDTSize &&
402 42269 : nLineSpace == nPixelSpace * nBlockXSize)
403 : {
404 : // If writing one single block with the right data type and layout,
405 : // we don't need a temporary buffer
406 : const int nBlockId =
407 42276 : ComputeBlockId(nXOff / nBlockXSize, nYOff / nBlockYSize);
408 42272 : return m_poGDS->WriteEncodedTileOrStrip(
409 42276 : nBlockId, pData, /* bPreserveDataBuffer= */ true);
410 : }
411 :
412 : // Make sure m_poGDS->m_pabyBlockBuf is allocated.
413 : // We could actually use any temporary buffer
414 5763 : if (m_poGDS->LoadBlockBuf(/* nBlockId = */ -1,
415 5761 : /* bReadFromDisk = */ false) != CE_None)
416 : {
417 0 : return CE_Failure;
418 : }
419 :
420 : // Iterate over all blocks defined by
421 : // [nXOff, nXOff+nXSize[ * [nYOff, nYOff+nYSize[
422 : // and write their content as a nBlockXSize x nBlockYSize strile
423 : // in a temporary buffer, before calling WriteEncodedTileOrStrip()
424 : // on it
425 5761 : const int nYBlockStart = nYOff / nBlockYSize;
426 5761 : const int nYBlockEnd = 1 + (nYOff + nYSize - 1) / nBlockYSize;
427 5761 : const int nXBlockStart = nXOff / nBlockXSize;
428 5761 : const int nXBlockEnd = 1 + (nXOff + nXSize - 1) / nBlockXSize;
429 49756 : for (int nYBlock = nYBlockStart; nYBlock < nYBlockEnd; ++nYBlock)
430 : {
431 : const int nValidY =
432 43995 : std::min(nBlockYSize, nRasterYSize - nYBlock * nBlockYSize);
433 103968 : for (int nXBlock = nXBlockStart; nXBlock < nXBlockEnd; ++nXBlock)
434 : {
435 : const int nValidX =
436 59973 : std::min(nBlockXSize, nRasterXSize - nXBlock * nBlockXSize);
437 59958 : if (nValidY < nBlockYSize || nValidX < nBlockXSize)
438 : {
439 : // Make sure padding bytes at the right/bottom of the
440 : // tile are initialized to zero.
441 2977 : memset(m_poGDS->m_pabyBlockBuf, 0,
442 2977 : static_cast<size_t>(nBlockXSize) * nBlockYSize *
443 2977 : nDTSize);
444 : }
445 59958 : const GByte *pabySrcData =
446 : static_cast<const GByte *>(pData) +
447 59958 : static_cast<size_t>(nYBlock - nYBlockStart) * nBlockYSize *
448 59958 : nLineSpace +
449 59958 : static_cast<size_t>(nXBlock - nXBlockStart) * nBlockXSize *
450 59958 : nPixelSpace;
451 3811830 : for (int iY = 0; iY < nValidY; ++iY)
452 : {
453 3751850 : GDALCopyWords64(
454 3751850 : pabySrcData + static_cast<size_t>(iY) * nLineSpace,
455 : eBufType, static_cast<int>(nPixelSpace),
456 3751850 : m_poGDS->m_pabyBlockBuf +
457 3751850 : static_cast<size_t>(iY) * nBlockXSize * nDTSize,
458 : eDataType, nDTSize, nValidX);
459 : }
460 59975 : const int nBlockId = ComputeBlockId(nXBlock, nYBlock);
461 119942 : if (m_poGDS->WriteEncodedTileOrStrip(
462 59969 : nBlockId, m_poGDS->m_pabyBlockBuf,
463 59973 : /* bPreserveDataBuffer= */ false) != CE_None)
464 : {
465 0 : return CE_Failure;
466 : }
467 : }
468 : }
469 5761 : return CE_None;
470 : }
471 :
472 5767230 : if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
473 5764790 : ++m_poGDS->m_nJPEGOverviewVisibilityCounter;
474 5767230 : const CPLErr eErr = GDALPamRasterBand::IRasterIO(
475 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
476 : eBufType, nPixelSpace, nLineSpace, psExtraArg);
477 5767290 : if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
478 5764750 : --m_poGDS->m_nJPEGOverviewVisibilityCounter;
479 :
480 5767290 : m_poGDS->m_bLoadingOtherBands = false;
481 :
482 5767290 : return eErr;
483 : }
484 :
485 : /************************************************************************/
486 : /* ComputeBlockId() */
487 : /************************************************************************/
488 :
489 : /** Computes the TIFF block identifier from the tile coordinate, band
490 : * number and planar configuration.
491 : */
492 3296760 : int GTiffRasterBand::ComputeBlockId(int nBlockXOff, int nBlockYOff) const
493 : {
494 3296760 : const int nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
495 3296760 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
496 : {
497 663981 : return nBlockId + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
498 : }
499 2632780 : return nBlockId;
500 : }
|