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 "cpl_vsi_virtual.h"
21 : #include "tifvsi.h"
22 :
23 : /************************************************************************/
24 : /* GTiffRasterBand() */
25 : /************************************************************************/
26 :
27 695103 : GTiffRasterBand::GTiffRasterBand(GTiffDataset *poDSIn, int nBandIn)
28 695103 : : m_poGDS(poDSIn)
29 : {
30 695058 : poDS = poDSIn;
31 695058 : nBand = nBandIn;
32 :
33 : /* -------------------------------------------------------------------- */
34 : /* Get the GDAL data type. */
35 : /* -------------------------------------------------------------------- */
36 695058 : const uint16_t nBitsPerSample = m_poGDS->m_nBitsPerSample;
37 695058 : const uint16_t nSampleFormat = m_poGDS->m_nSampleFormat;
38 :
39 695058 : eDataType = GDT_Unknown;
40 :
41 695058 : if (nBitsPerSample <= 8)
42 : {
43 688423 : if (nSampleFormat == SAMPLEFORMAT_INT)
44 80 : eDataType = GDT_Int8;
45 : else
46 688343 : eDataType = GDT_Byte;
47 : }
48 6635 : else if (nBitsPerSample <= 16)
49 : {
50 2347 : if (nSampleFormat == SAMPLEFORMAT_INT)
51 1162 : eDataType = GDT_Int16;
52 : else
53 1185 : eDataType = GDT_UInt16;
54 : }
55 4288 : else if (nBitsPerSample == 32)
56 : {
57 2866 : if (nSampleFormat == SAMPLEFORMAT_COMPLEXINT)
58 461 : eDataType = GDT_CInt16;
59 2405 : else if (nSampleFormat == SAMPLEFORMAT_IEEEFP)
60 1647 : eDataType = GDT_Float32;
61 758 : else if (nSampleFormat == SAMPLEFORMAT_INT)
62 402 : eDataType = GDT_Int32;
63 : else
64 356 : eDataType = GDT_UInt32;
65 : }
66 1422 : else if (nBitsPerSample == 64)
67 : {
68 1098 : if (nSampleFormat == SAMPLEFORMAT_IEEEFP)
69 561 : eDataType = GDT_Float64;
70 537 : else if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
71 235 : eDataType = GDT_CFloat32;
72 302 : else if (nSampleFormat == SAMPLEFORMAT_COMPLEXINT)
73 214 : eDataType = GDT_CInt32;
74 88 : else if (nSampleFormat == SAMPLEFORMAT_INT)
75 52 : eDataType = GDT_Int64;
76 : else
77 36 : eDataType = GDT_UInt64;
78 : }
79 324 : else if (nBitsPerSample == 128)
80 : {
81 252 : if (nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
82 252 : eDataType = GDT_CFloat64;
83 : }
84 :
85 : /* -------------------------------------------------------------------- */
86 : /* Try to work out band color interpretation. */
87 : /* -------------------------------------------------------------------- */
88 695058 : bool bLookForExtraSamples = false;
89 :
90 695058 : if (m_poGDS->m_poColorTable != nullptr && nBand == 1)
91 : {
92 161 : m_eBandInterp = GCI_PaletteIndex;
93 : }
94 1373920 : else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
95 679001 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_YCBCR &&
96 873 : m_poGDS->m_nCompression == COMPRESSION_JPEG &&
97 834 : CPLTestBool(CPLGetConfigOption("CONVERT_YCBCR_TO_RGB", "YES"))))
98 : {
99 16643 : if (nBand == 1)
100 5218 : m_eBandInterp = GCI_RedBand;
101 11425 : else if (nBand == 2)
102 5221 : m_eBandInterp = GCI_GreenBand;
103 6204 : else if (nBand == 3)
104 5223 : m_eBandInterp = GCI_BlueBand;
105 : else
106 981 : bLookForExtraSamples = true;
107 : }
108 678274 : else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_YCBCR)
109 : {
110 39 : if (nBand == 1)
111 13 : m_eBandInterp = GCI_YCbCr_YBand;
112 26 : else if (nBand == 2)
113 13 : m_eBandInterp = GCI_YCbCr_CbBand;
114 13 : else if (nBand == 3)
115 13 : m_eBandInterp = GCI_YCbCr_CrBand;
116 : else
117 0 : bLookForExtraSamples = true;
118 : }
119 678235 : else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_SEPARATED)
120 : {
121 96 : if (nBand == 1)
122 24 : m_eBandInterp = GCI_CyanBand;
123 72 : else if (nBand == 2)
124 24 : m_eBandInterp = GCI_MagentaBand;
125 48 : else if (nBand == 3)
126 24 : m_eBandInterp = GCI_YellowBand;
127 24 : else if (nBand == 4)
128 24 : m_eBandInterp = GCI_BlackBand;
129 : else
130 0 : bLookForExtraSamples = true;
131 : }
132 678139 : else if (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK && nBand == 1)
133 : {
134 20181 : m_eBandInterp = GCI_GrayIndex;
135 : }
136 : else
137 : {
138 657958 : bLookForExtraSamples = true;
139 : }
140 :
141 695078 : if (bLookForExtraSamples)
142 : {
143 658821 : uint16_t *v = nullptr;
144 658821 : uint16_t count = 0;
145 :
146 658821 : if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v))
147 : {
148 592968 : const int nBaseSamples = m_poGDS->m_nSamplesPerPixel - count;
149 592968 : const int nExpectedBaseSamples =
150 593952 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK) ? 1
151 1968 : : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISWHITE) ? 1
152 990 : : (m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB) ? 3
153 12 : : (m_poGDS->m_nPhotometric == PHOTOMETRIC_YCBCR) ? 3
154 6 : : (m_poGDS->m_nPhotometric == PHOTOMETRIC_SEPARATED) ? 4
155 : : 0;
156 :
157 592968 : if (nExpectedBaseSamples > 0 && nBand == nExpectedBaseSamples + 1 &&
158 : nBaseSamples != nExpectedBaseSamples)
159 : {
160 1 : ReportError(
161 : CE_Warning, CPLE_AppDefined,
162 : "Wrong number of ExtraSamples : %d. %d were expected",
163 1 : count, m_poGDS->m_nSamplesPerPixel - nExpectedBaseSamples);
164 : }
165 :
166 592968 : if (nBand > nBaseSamples && nBand - nBaseSamples - 1 < count &&
167 592963 : (v[nBand - nBaseSamples - 1] == EXTRASAMPLE_ASSOCALPHA ||
168 592954 : v[nBand - nBaseSamples - 1] == EXTRASAMPLE_UNASSALPHA))
169 1036 : m_eBandInterp = GCI_AlphaBand;
170 : else
171 591932 : m_eBandInterp = GCI_Undefined;
172 : }
173 : else
174 : {
175 65853 : m_eBandInterp = GCI_Undefined;
176 : }
177 : }
178 :
179 : /* -------------------------------------------------------------------- */
180 : /* Establish block size for strip or tiles. */
181 : /* -------------------------------------------------------------------- */
182 695078 : nBlockXSize = m_poGDS->m_nBlockXSize;
183 695078 : nBlockYSize = m_poGDS->m_nBlockYSize;
184 695078 : nRasterXSize = m_poGDS->nRasterXSize;
185 695078 : nRasterYSize = m_poGDS->nRasterYSize;
186 695078 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
187 695078 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
188 695078 : }
189 :
190 : /************************************************************************/
191 : /* ~GTiffRasterBand() */
192 : /************************************************************************/
193 :
194 1258222 : GTiffRasterBand::~GTiffRasterBand()
195 : {
196 : // So that any future DropReferenceVirtualMem() will not try to access the
197 : // raster band object, but this would not conform to the advertised
198 : // contract.
199 695122 : if (!m_aSetPSelf.empty())
200 : {
201 0 : ReportError(CE_Warning, CPLE_AppDefined,
202 : "Virtual memory objects still exist at GTiffRasterBand "
203 : "destruction");
204 0 : std::set<GTiffRasterBand **>::iterator oIter = m_aSetPSelf.begin();
205 0 : for (; oIter != m_aSetPSelf.end(); ++oIter)
206 0 : *(*oIter) = nullptr;
207 : }
208 1258211 : }
209 :
210 : /************************************************************************/
211 : /* IRasterIO() */
212 : /************************************************************************/
213 :
214 5326270 : CPLErr GTiffRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
215 : int nXSize, int nYSize, void *pData,
216 : int nBufXSize, int nBufYSize,
217 : GDALDataType eBufType, GSpacing nPixelSpace,
218 : GSpacing nLineSpace,
219 : GDALRasterIOExtraArg *psExtraArg)
220 : {
221 : #if DEBUG_VERBOSE
222 : CPLDebug("GTiff", "RasterIO(%d, %d, %d, %d, %d, %d)", nXOff, nYOff, nXSize,
223 : nYSize, nBufXSize, nBufYSize);
224 : #endif
225 :
226 : // Try to pass the request to the most appropriate overview dataset.
227 5326270 : if (nBufXSize < nXSize && nBufYSize < nYSize)
228 : {
229 161930 : int bTried = FALSE;
230 161930 : if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
231 161575 : ++m_poGDS->m_nJPEGOverviewVisibilityCounter;
232 161930 : const CPLErr eErr = TryOverviewRasterIO(
233 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
234 : eBufType, nPixelSpace, nLineSpace, psExtraArg, &bTried);
235 161930 : if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
236 161575 : --m_poGDS->m_nJPEGOverviewVisibilityCounter;
237 161930 : if (bTried)
238 44 : return eErr;
239 : }
240 :
241 5326230 : if (m_poGDS->m_eVirtualMemIOUsage != GTiffDataset::VirtualMemIOEnum::NO)
242 : {
243 904 : const int nErr = m_poGDS->VirtualMemIO(
244 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
245 452 : eBufType, 1, &nBand, nPixelSpace, nLineSpace, 0, psExtraArg);
246 452 : if (nErr >= 0)
247 363 : return static_cast<CPLErr>(nErr);
248 : }
249 5325870 : if (m_poGDS->m_bDirectIO)
250 : {
251 : int nErr =
252 2098 : DirectIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
253 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
254 2098 : if (nErr >= 0)
255 985 : return static_cast<CPLErr>(nErr);
256 : }
257 :
258 5324880 : bool bCanUseMultiThreadedRead = false;
259 5324470 : if (m_poGDS->m_nDisableMultiThreadedRead == 0 && eRWFlag == GF_Read &&
260 3105440 : m_poGDS->m_poThreadPool != nullptr && nXSize == nBufXSize &&
261 10649400 : nYSize == nBufYSize && m_poGDS->IsMultiThreadedReadCompatible())
262 : {
263 101 : const int nBlockX1 = nXOff / nBlockXSize;
264 101 : const int nBlockY1 = nYOff / nBlockYSize;
265 101 : const int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
266 101 : const int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
267 101 : const int nXBlocks = nBlockX2 - nBlockX1 + 1;
268 101 : const int nYBlocks = nBlockY2 - nBlockY1 + 1;
269 101 : if (nXBlocks > 1 || nYBlocks > 1)
270 : {
271 98 : bCanUseMultiThreadedRead = true;
272 : }
273 : }
274 :
275 : // Cleanup data cached by below CacheMultiRange() call.
276 : struct BufferedDataFreer
277 : {
278 : void *m_pBufferedData = nullptr;
279 : TIFF *m_hTIFF = nullptr;
280 :
281 250 : void Init(void *pBufferedData, TIFF *hTIFF)
282 : {
283 250 : m_pBufferedData = pBufferedData;
284 250 : m_hTIFF = hTIFF;
285 250 : }
286 :
287 5325020 : ~BufferedDataFreer()
288 5325020 : {
289 5325020 : if (m_pBufferedData)
290 : {
291 35 : VSIFree(m_pBufferedData);
292 35 : VSI_TIFFSetCachedRanges(TIFFClientdata(m_hTIFF), 0, nullptr,
293 : nullptr, nullptr);
294 : }
295 5325020 : }
296 : };
297 :
298 : // bufferedDataFreer must be left in this scope !
299 5325080 : BufferedDataFreer bufferedDataFreer;
300 :
301 8113220 : if (m_poGDS->eAccess == GA_ReadOnly && eRWFlag == GF_Read &&
302 2788400 : m_poGDS->HasOptimizedReadMultiRange())
303 : {
304 254 : if (bCanUseMultiThreadedRead &&
305 2 : VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF))->HasPRead())
306 : {
307 : // use the multi-threaded implementation rather than the multi-range
308 : // one
309 : }
310 : else
311 : {
312 250 : bCanUseMultiThreadedRead = false;
313 250 : GTiffRasterBand *poBandForCache = this;
314 250 : if (!m_poGDS->m_bStreamingIn && m_poGDS->m_bBlockOrderRowMajor &&
315 106 : m_poGDS->m_bLeaderSizeAsUInt4 &&
316 106 : m_poGDS->m_bMaskInterleavedWithImagery &&
317 102 : m_poGDS->m_poImageryDS)
318 : {
319 63 : poBandForCache = cpl::down_cast<GTiffRasterBand *>(
320 63 : m_poGDS->m_poImageryDS->GetRasterBand(1));
321 : }
322 250 : bufferedDataFreer.Init(poBandForCache->CacheMultiRange(
323 : nXOff, nYOff, nXSize, nYSize, nBufXSize,
324 : nBufYSize, psExtraArg),
325 250 : poBandForCache->m_poGDS->m_hTIFF);
326 : }
327 : }
328 :
329 5324620 : if (eRWFlag == GF_Read && nXSize == nBufXSize && nYSize == nBufYSize)
330 : {
331 2910020 : const int nBlockX1 = nXOff / nBlockXSize;
332 2910020 : const int nBlockY1 = nYOff / nBlockYSize;
333 2910020 : const int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
334 2910020 : const int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
335 2910020 : const int nXBlocks = nBlockX2 - nBlockX1 + 1;
336 2910020 : const int nYBlocks = nBlockY2 - nBlockY1 + 1;
337 :
338 2910020 : if (bCanUseMultiThreadedRead)
339 : {
340 196 : return m_poGDS->MultiThreadedRead(nXOff, nYOff, nXSize, nYSize,
341 98 : pData, eBufType, 1, &nBand,
342 98 : nPixelSpace, nLineSpace, 0);
343 : }
344 2909930 : else if (m_poGDS->nBands != 1 &&
345 687764 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
346 : {
347 : const GIntBig nRequiredMem =
348 635753 : static_cast<GIntBig>(m_poGDS->nBands) * nXBlocks * nYBlocks *
349 635753 : nBlockXSize * nBlockYSize * GDALGetDataTypeSizeBytes(eDataType);
350 635879 : if (nRequiredMem > GDALGetCacheMax64())
351 : {
352 9060 : if (!m_poGDS->m_bHasWarnedDisableAggressiveBandCaching)
353 : {
354 14 : CPLDebug("GTiff",
355 : "Disable aggressive band caching. "
356 : "Cache not big enough. "
357 : "At least " CPL_FRMT_GIB " bytes necessary",
358 : nRequiredMem);
359 14 : m_poGDS->m_bHasWarnedDisableAggressiveBandCaching = true;
360 : }
361 9060 : m_poGDS->m_bLoadingOtherBands = true;
362 : }
363 2910050 : }
364 : }
365 :
366 : // Write optimization when writing whole blocks, by-passing the block cache.
367 : // We require the block cache to be non instantiated to simplify things
368 : // (otherwise we might need to evict corresponding existing blocks from the
369 : // block cache).
370 4633670 : else if (eRWFlag == GF_Write &&
371 : // Could be extended to "odd bit" case, but more work
372 2219070 : m_poGDS->m_nBitsPerSample == GDALGetDataTypeSize(eDataType) &&
373 2066910 : nXSize == nBufXSize && nYSize == nBufYSize && !HasBlockCache() &&
374 4391 : !m_poGDS->m_bLoadedBlockDirty &&
375 4379 : (m_poGDS->nBands == 1 ||
376 1731 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE) &&
377 3348 : (nXOff % nBlockXSize) == 0 && (nYOff % nBlockYSize) == 0 &&
378 4636840 : (nXOff + nXSize == nRasterXSize || (nXSize % nBlockXSize) == 0) &&
379 3170 : (nYOff + nYSize == nRasterYSize || (nYSize % nBlockYSize) == 0))
380 : {
381 2877 : m_poGDS->Crystalize();
382 :
383 2877 : if (m_poGDS->m_bDebugDontWriteBlocks)
384 0 : return CE_None;
385 :
386 2877 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
387 2877 : if (nXSize == nBlockXSize && nYSize == nBlockYSize &&
388 1510 : eBufType == eDataType && nPixelSpace == nDTSize &&
389 1458 : nLineSpace == nPixelSpace * nBlockXSize)
390 : {
391 : // If writing one single block with the right data type and layout,
392 : // we don't need a temporary buffer
393 : const int nBlockId =
394 1458 : ComputeBlockId(nXOff / nBlockXSize, nYOff / nBlockYSize);
395 1458 : return m_poGDS->WriteEncodedTileOrStrip(
396 1458 : nBlockId, pData, /* bPreserveDataBuffer= */ true);
397 : }
398 :
399 : // Make sure m_poGDS->m_pabyBlockBuf is allocated.
400 : // We could actually use any temporary buffer
401 1419 : if (m_poGDS->LoadBlockBuf(/* nBlockId = */ -1,
402 1419 : /* bReadFromDisk = */ false) != CE_None)
403 : {
404 0 : return CE_Failure;
405 : }
406 :
407 : // Iterate over all blocks defined by
408 : // [nXOff, nXOff+nXSize[ * [nYOff, nYOff+nYSize[
409 : // and write their content as a nBlockXSize x nBlockYSize strile
410 : // in a temporary buffer, before calling WriteEncodedTileOrStrip()
411 : // on it
412 1419 : const int nYBlockStart = nYOff / nBlockYSize;
413 1419 : const int nYBlockEnd = 1 + (nYOff + nYSize - 1) / nBlockYSize;
414 1419 : const int nXBlockStart = nXOff / nBlockXSize;
415 1419 : const int nXBlockEnd = 1 + (nXOff + nXSize - 1) / nBlockXSize;
416 25675 : for (int nYBlock = nYBlockStart; nYBlock < nYBlockEnd; ++nYBlock)
417 : {
418 : const int nValidY =
419 24256 : std::min(nBlockYSize, nRasterYSize - nYBlock * nBlockYSize);
420 62278 : for (int nXBlock = nXBlockStart; nXBlock < nXBlockEnd; ++nXBlock)
421 : {
422 : const int nValidX =
423 38022 : std::min(nBlockXSize, nRasterXSize - nXBlock * nBlockXSize);
424 38021 : if (nValidY < nBlockYSize || nValidX < nBlockXSize)
425 : {
426 : // Make sure padding bytes at the right/bottom of the
427 : // tile are initialized to zero.
428 2203 : memset(m_poGDS->m_pabyBlockBuf, 0,
429 2203 : static_cast<size_t>(nBlockXSize) * nBlockYSize *
430 2203 : nDTSize);
431 : }
432 38021 : const GByte *pabySrcData =
433 : static_cast<const GByte *>(pData) +
434 38021 : static_cast<size_t>(nYBlock - nYBlockStart) * nBlockYSize *
435 38021 : nLineSpace +
436 38021 : static_cast<size_t>(nXBlock - nXBlockStart) * nBlockXSize *
437 38021 : nPixelSpace;
438 1250130 : for (int iY = 0; iY < nValidY; ++iY)
439 : {
440 1212100 : GDALCopyWords64(
441 1212100 : pabySrcData + static_cast<size_t>(iY) * nLineSpace,
442 : eBufType, static_cast<int>(nPixelSpace),
443 1212100 : m_poGDS->m_pabyBlockBuf +
444 1212100 : static_cast<size_t>(iY) * nBlockXSize * nDTSize,
445 : eDataType, nDTSize, nValidX);
446 : }
447 38022 : const int nBlockId = ComputeBlockId(nXBlock, nYBlock);
448 76044 : if (m_poGDS->WriteEncodedTileOrStrip(
449 38022 : nBlockId, m_poGDS->m_pabyBlockBuf,
450 38022 : /* bPreserveDataBuffer= */ false) != CE_None)
451 : {
452 0 : return CE_Failure;
453 : }
454 : }
455 : }
456 1419 : return CE_None;
457 : }
458 :
459 5321770 : if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
460 5319450 : ++m_poGDS->m_nJPEGOverviewVisibilityCounter;
461 5321770 : const CPLErr eErr = GDALPamRasterBand::IRasterIO(
462 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
463 : eBufType, nPixelSpace, nLineSpace, psExtraArg);
464 5322110 : if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
465 5319610 : --m_poGDS->m_nJPEGOverviewVisibilityCounter;
466 :
467 5322110 : m_poGDS->m_bLoadingOtherBands = false;
468 :
469 5322110 : return eErr;
470 : }
471 :
472 : /************************************************************************/
473 : /* ComputeBlockId() */
474 : /************************************************************************/
475 :
476 : /** Computes the TIFF block identifier from the tile coordinate, band
477 : * number and planar configuration.
478 : */
479 3098440 : int GTiffRasterBand::ComputeBlockId(int nBlockXOff, int nBlockYOff) const
480 : {
481 3098440 : const int nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
482 3098440 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
483 : {
484 403202 : return nBlockId + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
485 : }
486 2695240 : return nBlockId;
487 : }
|