Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Base class for format specific band class implementation. This
5 : * base class provides default implementation for many methods.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1998, Frank Warmerdam
10 : * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "cpl_port.h"
16 : #include "gdal_priv.h"
17 :
18 : #include <climits>
19 : #include <cmath>
20 : #include <cstdarg>
21 : #include <cstddef>
22 : #include <cstdio>
23 : #include <cstdlib>
24 : #include <cstring>
25 : #include <algorithm>
26 : #include <limits>
27 : #include <memory>
28 : #include <new>
29 : #include <type_traits>
30 :
31 : #include "cpl_conv.h"
32 : #include "cpl_error.h"
33 : #include "cpl_float.h"
34 : #include "cpl_progress.h"
35 : #include "cpl_string.h"
36 : #include "cpl_virtualmem.h"
37 : #include "cpl_vsi.h"
38 : #include "gdal.h"
39 : #include "gdal_rat.h"
40 : #include "gdal_priv_templates.hpp"
41 : #include "gdal_interpolateatpoint.h"
42 : #include "gdal_minmax_element.hpp"
43 :
44 : /************************************************************************/
45 : /* GDALRasterBand() */
46 : /************************************************************************/
47 :
48 : /*! Constructor. Applications should never create GDALRasterBands directly. */
49 :
50 1065430 : GDALRasterBand::GDALRasterBand()
51 : : GDALRasterBand(
52 1065430 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
53 : {
54 1065310 : }
55 :
56 : /** Constructor. Applications should never create GDALRasterBands directly.
57 : * @param bForceCachedIOIn Whether cached IO should be forced.
58 : */
59 1202120 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
60 1202120 : : bForceCachedIO(bForceCachedIOIn)
61 :
62 : {
63 1201970 : }
64 :
65 : /************************************************************************/
66 : /* ~GDALRasterBand() */
67 : /************************************************************************/
68 :
69 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
70 : instead destroy the GDALDataset. */
71 :
72 1202100 : GDALRasterBand::~GDALRasterBand()
73 :
74 : {
75 1202110 : if (poDS && poDS->IsMarkedSuppressOnClose())
76 : {
77 448 : if (poBandBlockCache)
78 384 : poBandBlockCache->DisableDirtyBlockWriting();
79 : }
80 1202110 : GDALRasterBand::FlushCache(true);
81 :
82 1202100 : delete poBandBlockCache;
83 :
84 1202100 : if (static_cast<GIntBig>(nBlockReads) >
85 1202100 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
86 214 : nBand == 1 && poDS != nullptr)
87 : {
88 302 : CPLDebug(
89 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
90 151 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
91 151 : poDS->GetDescription());
92 : }
93 :
94 1202100 : InvalidateMaskBand();
95 1202100 : nBand = -nBand;
96 :
97 1202100 : delete m_poPointsCache;
98 1202100 : }
99 :
100 : /************************************************************************/
101 : /* RasterIO() */
102 : /************************************************************************/
103 :
104 : /**
105 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
106 : * int nXOff, int nYOff, int nXSize, int nYSize,
107 : * void * pData, int nBufXSize, int nBufYSize,
108 : * GDALDataType eBufType,
109 : * GSpacing nPixelSpace,
110 : * GSpacing nLineSpace,
111 : * GDALRasterIOExtraArg* psExtraArg )
112 : * \brief Read/write a region of image data for this band.
113 : *
114 : * This method allows reading a region of a GDALRasterBand into a buffer,
115 : * or writing data from a buffer into a region of a GDALRasterBand. It
116 : * automatically takes care of data type translation if the data type
117 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
118 : * The method also takes care of image decimation / replication if the
119 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
120 : * region being accessed (nXSize x nYSize).
121 : *
122 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
123 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
124 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
125 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
126 : * Or use nLineSpace and a possibly shifted pData value.
127 : *
128 : * The nPixelSpace and nLineSpace parameters allow reading into or
129 : * writing from unusually organized buffers. This is primarily used
130 : * for buffers containing more than one bands raster data in interleaved
131 : * format.
132 : *
133 : * Some formats may efficiently implement decimation into a buffer by
134 : * reading from lower resolution overview images. The logic of the default
135 : * implementation in the base class GDALRasterBand is the following one. It
136 : * computes a target_downscaling_factor from the window of interest and buffer
137 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
138 : * It then walks through overviews and will select the first one whose
139 : * downscaling factor is greater than target_downscaling_factor / 1.2.
140 : *
141 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
142 : * The relationship between target_downscaling_factor and the select overview
143 : * level is the following one:
144 : *
145 : * target_downscaling_factor | selected_overview
146 : * ------------------------- | -----------------
147 : * ]0, 2 / 1.2] | full resolution band
148 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
149 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
150 : * ]8 / 1.2, infinity[ | 8x downsampled band
151 : *
152 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
153 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
154 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
155 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
156 : * this oversampling threshold defaults to 1. Consequently if there are overviews
157 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
158 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
159 : *
160 : * For highest performance full resolution data access, read and write
161 : * on "block boundaries" as returned by GetBlockSize(), or use the
162 : * ReadBlock() and WriteBlock() methods.
163 : *
164 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
165 : * functions.
166 : *
167 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
168 : * write a region of data.
169 : *
170 : * @param nXOff The pixel offset to the top left corner of the region
171 : * of the band to be accessed. This would be zero to start from the left side.
172 : *
173 : * @param nYOff The line offset to the top left corner of the region
174 : * of the band to be accessed. This would be zero to start from the top.
175 : *
176 : * @param nXSize The width of the region of the band to be accessed in pixels.
177 : *
178 : * @param nYSize The height of the region of the band to be accessed in lines.
179 : *
180 : * @param pData The buffer into which the data should be read, or from which
181 : * it should be written. This buffer must contain at least nBufXSize *
182 : * nBufYSize words of type eBufType. It is organized in left to right,
183 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
184 : * and nLineSpace parameters.
185 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
186 : * temporarily modified during the execution of this method (and eventually
187 : * restored back to its original content), so it is not safe to use a buffer
188 : * stored in a read-only section of the calling program.
189 : *
190 : * @param nBufXSize the width of the buffer image into which the desired region
191 : * is to be read, or from which it is to be written.
192 : *
193 : * @param nBufYSize the height of the buffer image into which the desired region
194 : * is to be read, or from which it is to be written.
195 : *
196 : * @param eBufType the type of the pixel values in the pData data buffer. The
197 : * pixel values will automatically be translated to/from the GDALRasterBand
198 : * data type as needed. Most driver implementations will use GDALCopyWords64()
199 : * to perform data type translation.
200 : *
201 : * @param nPixelSpace The byte offset from the start of one pixel value in
202 : * pData to the start of the next pixel value within a scanline. If defaulted
203 : * (0) the size of the datatype eBufType is used.
204 : *
205 : * @param nLineSpace The byte offset from the start of one scanline in
206 : * pData to the start of the next. If defaulted (0) the size of the datatype
207 : * eBufType * nBufXSize is used.
208 : *
209 : * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
210 : * structure with additional arguments to specify resampling and progress
211 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
212 : * configuration option can also be defined to override the default resampling
213 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
214 : *
215 : * @return CE_Failure if the access fails, otherwise CE_None.
216 : */
217 :
218 : /**
219 : * \brief Read/write a region of image data for this band.
220 : *
221 : * This method allows reading a region of a GDALRasterBand into a buffer,
222 : * or writing data from a buffer into a region of a GDALRasterBand. It
223 : * automatically takes care of data type translation if the data type
224 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
225 : * The method also takes care of image decimation / replication if the
226 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
227 : * region being accessed (nXSize x nYSize).
228 : *
229 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
230 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
231 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
232 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
233 : * Or use nLineSpace and a possibly shifted pData value.
234 : *
235 : * The nPixelSpace and nLineSpace parameters allow reading into or
236 : * writing from unusually organized buffers. This is primarily used
237 : * for buffers containing more than one bands raster data in interleaved
238 : * format.
239 : *
240 : * Some formats may efficiently implement decimation into a buffer by
241 : * reading from lower resolution overview images. The logic of the default
242 : * implementation in the base class GDALRasterBand is the following one. It
243 : * computes a target_downscaling_factor from the window of interest and buffer
244 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
245 : * It then walks through overviews and will select the first one whose
246 : * downscaling factor is greater than target_downscaling_factor / 1.2.
247 : *
248 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
249 : * The relationship between target_downscaling_factor and the select overview
250 : * level is the following one:
251 : *
252 : * target_downscaling_factor | selected_overview
253 : * ------------------------- | -----------------
254 : * ]0, 2 / 1.2] | full resolution band
255 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
256 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
257 : * ]8 / 1.2, infinity[ | 8x downsampled band
258 : *
259 : * For highest performance full resolution data access, read and write
260 : * on "block boundaries" as returned by GetBlockSize(), or use the
261 : * ReadBlock() and WriteBlock() methods.
262 : *
263 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
264 : * functions.
265 : *
266 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
267 : * more convenient to use for most common use cases.
268 : *
269 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
270 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
271 : * instance of this dataset) concurrently from several threads.
272 : *
273 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
274 : * write a region of data.
275 : *
276 : * @param nXOff The pixel offset to the top left corner of the region
277 : * of the band to be accessed. This would be zero to start from the left side.
278 : *
279 : * @param nYOff The line offset to the top left corner of the region
280 : * of the band to be accessed. This would be zero to start from the top.
281 : *
282 : * @param nXSize The width of the region of the band to be accessed in pixels.
283 : *
284 : * @param nYSize The height of the region of the band to be accessed in lines.
285 : *
286 : * @param[in,out] pData The buffer into which the data should be read, or from
287 : * which it should be written. This buffer must contain at least nBufXSize *
288 : * nBufYSize words of type eBufType. It is organized in left to right,
289 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
290 : * and nLineSpace parameters.
291 : *
292 : * @param nBufXSize the width of the buffer image into which the desired region
293 : * is to be read, or from which it is to be written.
294 : *
295 : * @param nBufYSize the height of the buffer image into which the desired region
296 : * is to be read, or from which it is to be written.
297 : *
298 : * @param eBufType the type of the pixel values in the pData data buffer. The
299 : * pixel values will automatically be translated to/from the GDALRasterBand
300 : * data type as needed.
301 : *
302 : * @param nPixelSpace The byte offset from the start of one pixel value in
303 : * pData to the start of the next pixel value within a scanline. If defaulted
304 : * (0) the size of the datatype eBufType is used.
305 : *
306 : * @param nLineSpace The byte offset from the start of one scanline in
307 : * pData to the start of the next. If defaulted (0) the size of the datatype
308 : * eBufType * nBufXSize is used.
309 : *
310 : * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
311 : * structure with additional arguments to specify resampling and progress
312 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
313 : * configuration option can also be defined to override the default resampling
314 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
315 : *
316 : * @return CE_Failure if the access fails, otherwise CE_None.
317 : *
318 : * @see GDALRasterBand::ReadRaster()
319 : */
320 :
321 3853230 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
322 : int nXSize, int nYSize, void *pData,
323 : int nBufXSize, int nBufYSize,
324 : GDALDataType eBufType, GSpacing nPixelSpace,
325 : GSpacing nLineSpace,
326 : GDALRasterIOExtraArg *psExtraArg)
327 :
328 : {
329 : GDALRasterIOExtraArg sExtraArg;
330 3853230 : if (psExtraArg == nullptr)
331 : {
332 3757360 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
333 3757360 : psExtraArg = &sExtraArg;
334 : }
335 95866 : else if (CPL_UNLIKELY(psExtraArg->nVersion !=
336 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
337 : {
338 0 : ReportError(CE_Failure, CPLE_AppDefined,
339 : "Unhandled version of GDALRasterIOExtraArg");
340 0 : return CE_Failure;
341 : }
342 :
343 3853230 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
344 : nBufYSize);
345 :
346 3855520 : if (CPL_UNLIKELY(nullptr == pData))
347 : {
348 0 : ReportError(CE_Failure, CPLE_AppDefined,
349 : "The buffer into which the data should be read is null");
350 0 : return CE_Failure;
351 : }
352 :
353 : /* -------------------------------------------------------------------- */
354 : /* Some size values are "noop". Lets just return to avoid */
355 : /* stressing lower level functions. */
356 : /* -------------------------------------------------------------------- */
357 3855520 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
358 : nBufYSize < 1))
359 : {
360 2 : CPLDebug("GDAL",
361 : "RasterIO() skipped for odd window or buffer size.\n"
362 : " Window = (%d,%d)x%dx%d\n"
363 : " Buffer = %dx%d\n",
364 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
365 :
366 2 : return CE_None;
367 : }
368 :
369 3855520 : if (eRWFlag == GF_Write)
370 : {
371 248928 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
372 : {
373 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
374 : "An error occurred while writing a dirty block "
375 : "from GDALRasterBand::RasterIO");
376 0 : CPLErr eErr = eFlushBlockErr;
377 0 : eFlushBlockErr = CE_None;
378 0 : return eErr;
379 : }
380 248928 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
381 : {
382 7 : return CE_Failure;
383 : }
384 : }
385 :
386 : /* -------------------------------------------------------------------- */
387 : /* If pixel and line spacing are defaulted assign reasonable */
388 : /* value assuming a packed buffer. */
389 : /* -------------------------------------------------------------------- */
390 3855380 : if (nPixelSpace == 0)
391 : {
392 3761980 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
393 : }
394 :
395 3847400 : if (nLineSpace == 0)
396 : {
397 3745230 : nLineSpace = nPixelSpace * nBufXSize;
398 : }
399 :
400 : /* -------------------------------------------------------------------- */
401 : /* Do some validation of parameters. */
402 : /* -------------------------------------------------------------------- */
403 3847400 : if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
404 : nXOff + nXSize > nRasterXSize || nYOff < 0 ||
405 : nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
406 : {
407 14 : ReportError(CE_Failure, CPLE_IllegalArg,
408 : "Access window out of range in RasterIO(). Requested\n"
409 : "(%d,%d) of size %dx%d on raster of %dx%d.",
410 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
411 14 : return CE_Failure;
412 : }
413 :
414 3847390 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
415 : {
416 0 : ReportError(
417 : CE_Failure, CPLE_IllegalArg,
418 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
419 : eRWFlag);
420 0 : return CE_Failure;
421 : }
422 3847390 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
423 : {
424 2 : ReportError(CE_Failure, CPLE_IllegalArg,
425 : "Illegal GDT_Unknown/GDT_TypeCount argument");
426 2 : return CE_Failure;
427 : }
428 :
429 : /* -------------------------------------------------------------------- */
430 : /* Call the format specific function. */
431 : /* -------------------------------------------------------------------- */
432 :
433 3847390 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
434 :
435 : CPLErr eErr;
436 3834740 : if (bForceCachedIO)
437 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
438 : pData, nBufXSize, nBufYSize, eBufType,
439 : nPixelSpace, nLineSpace, psExtraArg);
440 : else
441 : eErr =
442 3858200 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
443 3834720 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
444 :
445 3858220 : if (bCallLeaveReadWrite)
446 224029 : LeaveReadWrite();
447 :
448 3827500 : return eErr;
449 : }
450 :
451 : /************************************************************************/
452 : /* GDALRasterIO() */
453 : /************************************************************************/
454 :
455 : /**
456 : * \brief Read/write a region of image data for this band.
457 : *
458 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
459 : * resolution, progress callback, etc. are needed)
460 : *
461 : * @see GDALRasterBand::RasterIO()
462 : */
463 :
464 3542540 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
465 : int nXOff, int nYOff, int nXSize, int nYSize,
466 : void *pData, int nBufXSize, int nBufYSize,
467 : GDALDataType eBufType, int nPixelSpace,
468 : int nLineSpace)
469 :
470 : {
471 3542540 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
472 :
473 3542540 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
474 :
475 3542990 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
476 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
477 3531770 : nLineSpace, nullptr));
478 : }
479 :
480 : /************************************************************************/
481 : /* GDALRasterIOEx() */
482 : /************************************************************************/
483 :
484 : /**
485 : * \brief Read/write a region of image data for this band.
486 : *
487 : * @see GDALRasterBand::RasterIO()
488 : * @since GDAL 2.0
489 : */
490 :
491 35259 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
492 : int nXOff, int nYOff, int nXSize, int nYSize,
493 : void *pData, int nBufXSize, int nBufYSize,
494 : GDALDataType eBufType, GSpacing nPixelSpace,
495 : GSpacing nLineSpace,
496 : GDALRasterIOExtraArg *psExtraArg)
497 :
498 : {
499 35259 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
500 :
501 35259 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
502 :
503 35259 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
504 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
505 35258 : nLineSpace, psExtraArg));
506 : }
507 :
508 : /************************************************************************/
509 : /* GetGDTFromCppType() */
510 : /************************************************************************/
511 :
512 : namespace
513 : {
514 : template <class T> struct GetGDTFromCppType;
515 :
516 : #define DEFINE_GetGDTFromCppType(T, eDT) \
517 : template <> struct GetGDTFromCppType<T> \
518 : { \
519 : static constexpr GDALDataType GDT = eDT; \
520 : }
521 :
522 : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
523 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
524 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
525 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
526 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
527 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
528 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
529 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
530 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
531 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
532 : // Not allowed by C++ standard
533 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
534 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
535 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
536 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
537 : } // namespace
538 :
539 : /************************************************************************/
540 : /* ReadRaster() */
541 : /************************************************************************/
542 :
543 : // clang-format off
544 : /** Read a region of image data for this band.
545 : *
546 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
547 : * for common use cases, like reading a whole band.
548 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
549 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
550 : * float, double, std::complex<float|double>.
551 : *
552 : * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
553 : * and can allocate memory automatically.
554 : *
555 : * To read a whole band (assuming it fits into memory), as an array of double:
556 : *
557 : \code{.cpp}
558 : double* myArray = static_cast<double*>(
559 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
560 : // TODO: check here that myArray != nullptr
561 : const size_t nArrayEltCount =
562 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
563 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
564 : {
565 : // do something
566 : }
567 : VSIFree(myArray)
568 : \endcode
569 : *
570 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
571 : *
572 : \code{.cpp}
573 : double* myArray = static_cast<double*>(
574 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
575 : // TODO: check here that myArray != nullptr
576 : const size_t nArrayEltCount = 128 * 128;
577 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
578 : {
579 : // do something
580 : }
581 : VSIFree(myArray)
582 : \endcode
583 : *
584 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
585 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
586 : * instance of this dataset) concurrently from several threads.
587 : *
588 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
589 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
590 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
591 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
592 : * Or use nLineSpace and a possibly shifted pData value.
593 : *
594 : * @param[out] pData The buffer into which the data should be written.
595 : * This buffer must contain at least nBufXSize *
596 : * nBufYSize words of type T. It is organized in left to right,
597 : * top to bottom pixel order, and fully packed.
598 : * The type of the buffer does not need to be the one of GetDataType(). The
599 : * method will perform data type translation (with potential rounding, clamping)
600 : * if needed.
601 : *
602 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
603 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
604 : * return in error if it is not. If set to zero, then pData is trusted to be
605 : * large enough.
606 : *
607 : * @param dfXOff The pixel offset to the top left corner of the region
608 : * of the band to be accessed. This would be zero to start from the left side.
609 : * Defaults to 0.
610 : *
611 : * @param dfYOff The line offset to the top left corner of the region
612 : * of the band to be accessed. This would be zero to start from the top.
613 : * Defaults to 0.
614 : *
615 : * @param dfXSize The width of the region of the band to be accessed in pixels.
616 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
617 : * dfXSize is set to the band width.
618 : *
619 : * @param dfYSize The height of the region of the band to be accessed in lines.
620 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
621 : * dfYSize is set to the band height.
622 : *
623 : * @param nBufXSize the width of the buffer image into which the desired region
624 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
625 : * then nBufXSize is initialized with dfXSize.
626 : *
627 : * @param nBufYSize the height of the buffer image into which the desired region
628 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
629 : * then nBufYSize is initialized with dfYSize.
630 : *
631 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
632 : *
633 : * @param pfnProgress Progress function. May be nullptr.
634 : *
635 : * @param pProgressData User data of pfnProgress. May be nullptr.
636 : *
637 : * @return CE_Failure if the access fails, otherwise CE_None.
638 : *
639 : * @see GDALRasterBand::RasterIO()
640 : * @since GDAL 3.10
641 : */
642 : // clang-format on
643 :
644 : template <class T>
645 19 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
646 : double dfXOff, double dfYOff, double dfXSize,
647 : double dfYSize, size_t nBufXSize,
648 : size_t nBufYSize,
649 : GDALRIOResampleAlg eResampleAlg,
650 : GDALProgressFunc pfnProgress,
651 : void *pProgressData) const
652 : {
653 19 : if (((nBufXSize | nBufYSize) >> 31) != 0)
654 : {
655 2 : return CE_Failure;
656 : }
657 :
658 17 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
659 : {
660 15 : dfXSize = nRasterXSize;
661 15 : dfYSize = nRasterYSize;
662 : }
663 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
664 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
665 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
666 2 : dfYOff + dfYSize > INT_MAX)
667 : {
668 0 : return CE_Failure;
669 : }
670 :
671 : GDALRasterIOExtraArg sExtraArg;
672 17 : sExtraArg.nVersion = 1;
673 17 : sExtraArg.eResampleAlg = eResampleAlg;
674 17 : sExtraArg.pfnProgress = pfnProgress;
675 17 : sExtraArg.pProgressData = pProgressData;
676 17 : sExtraArg.bFloatingPointWindowValidity = true;
677 17 : sExtraArg.dfXOff = dfXOff;
678 17 : sExtraArg.dfYOff = dfYOff;
679 17 : sExtraArg.dfXSize = dfXSize;
680 17 : sExtraArg.dfYSize = dfYSize;
681 17 : const int nXOff = static_cast<int>(dfXOff);
682 17 : const int nYOff = static_cast<int>(dfYOff);
683 17 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
684 17 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
685 17 : if (nBufXSize == 0 && nBufYSize == 0)
686 : {
687 16 : if (static_cast<int>(dfXSize) == dfXSize &&
688 16 : static_cast<int>(dfYSize) == dfYSize)
689 : {
690 16 : nBufXSize = static_cast<int>(dfXSize);
691 16 : nBufYSize = static_cast<int>(dfYSize);
692 : }
693 : else
694 : {
695 0 : CPLError(CE_Failure, CPLE_AppDefined,
696 : "nBufXSize and nBufYSize must be provided if dfXSize or "
697 : "dfYSize is not an integer value");
698 0 : return CE_Failure;
699 : }
700 : }
701 17 : if (nBufXSize == 0 || nBufYSize == 0)
702 : {
703 0 : CPLDebug("GDAL",
704 : "RasterIO() skipped for odd window or buffer size.\n"
705 : " Window = (%d,%d)x%dx%d\n"
706 : " Buffer = %dx%d\n",
707 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
708 : static_cast<int>(nBufYSize));
709 :
710 0 : return CE_None;
711 : }
712 :
713 17 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
714 : {
715 1 : CPLError(CE_Failure, CPLE_AppDefined,
716 : "Provided array is not large enough");
717 1 : return CE_Failure;
718 : }
719 :
720 16 : constexpr GSpacing nPixelSpace = sizeof(T);
721 16 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
722 16 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
723 :
724 16 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
725 :
726 : const bool bCallLeaveReadWrite =
727 16 : CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
728 : CPLErr eErr;
729 : // coverity[identical_branches]
730 16 : if (bForceCachedIO)
731 0 : eErr = pThis->GDALRasterBand::IRasterIO(
732 : GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
733 : static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
734 : nPixelSpace, nLineSpace, &sExtraArg);
735 : else
736 16 : eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
737 : static_cast<int>(nBufXSize),
738 : static_cast<int>(nBufYSize), eBufType,
739 : nPixelSpace, nLineSpace, &sExtraArg);
740 :
741 16 : if (bCallLeaveReadWrite)
742 0 : pThis->LeaveReadWrite();
743 :
744 16 : return eErr;
745 : }
746 :
747 : //! @cond Doxygen_Suppress
748 :
749 : #define INSTANTIATE_READ_RASTER(T) \
750 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
751 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
752 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
753 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
754 : void *pProgressData) const;
755 :
756 : INSTANTIATE_READ_RASTER(uint8_t)
757 : INSTANTIATE_READ_RASTER(int8_t)
758 : INSTANTIATE_READ_RASTER(uint16_t)
759 : INSTANTIATE_READ_RASTER(int16_t)
760 : INSTANTIATE_READ_RASTER(uint32_t)
761 : INSTANTIATE_READ_RASTER(int32_t)
762 : INSTANTIATE_READ_RASTER(uint64_t)
763 : INSTANTIATE_READ_RASTER(int64_t)
764 : INSTANTIATE_READ_RASTER(float)
765 : INSTANTIATE_READ_RASTER(double)
766 : // Not allowed by C++ standard
767 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
768 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
769 : INSTANTIATE_READ_RASTER(std::complex<float>)
770 : INSTANTIATE_READ_RASTER(std::complex<double>)
771 :
772 : //! @endcond
773 :
774 : /************************************************************************/
775 : /* ReadRaster() */
776 : /************************************************************************/
777 :
778 : /** Read a region of image data for this band.
779 : *
780 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
781 : * for common use cases, like reading a whole band.
782 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
783 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
784 : * float, double, std::complex<float|double>.
785 : *
786 : * To read a whole band (assuming it fits into memory), as a vector of double:
787 : *
788 : \code
789 : std::vector<double> myArray;
790 : if (poBand->ReadRaster(myArray) == CE_None)
791 : {
792 : // do something
793 : }
794 : \endcode
795 : *
796 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
797 : *
798 : \code{.cpp}
799 : std::vector<double> myArray;
800 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
801 : {
802 : // do something
803 : }
804 : \endcode
805 : *
806 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
807 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
808 : * instance of this dataset) concurrently from several threads.
809 : *
810 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
811 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
812 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
813 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
814 : * Or use nLineSpace and a possibly shifted pData value.
815 : *
816 : * @param[out] vData The vector into which the data should be written.
817 : * The vector will be resized, if needed, to contain at least nBufXSize *
818 : * nBufYSize values. The values in the vector are organized in left to right,
819 : * top to bottom pixel order, and fully packed.
820 : * The type of the vector does not need to be the one of GetDataType(). The
821 : * method will perform data type translation (with potential rounding, clamping)
822 : * if needed.
823 : *
824 : * @param dfXOff The pixel offset to the top left corner of the region
825 : * of the band to be accessed. This would be zero to start from the left side.
826 : * Defaults to 0.
827 : *
828 : * @param dfYOff The line offset to the top left corner of the region
829 : * of the band to be accessed. This would be zero to start from the top.
830 : * Defaults to 0.
831 : *
832 : * @param dfXSize The width of the region of the band to be accessed in pixels.
833 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
834 : * dfXSize is set to the band width.
835 : *
836 : * @param dfYSize The height of the region of the band to be accessed in lines.
837 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
838 : * dfYSize is set to the band height.
839 : *
840 : * @param nBufXSize the width of the buffer image into which the desired region
841 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
842 : * then nBufXSize is initialized with dfXSize.
843 : *
844 : * @param nBufYSize the height of the buffer image into which the desired region
845 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
846 : * then nBufYSize is initialized with dfYSize.
847 : *
848 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
849 : *
850 : * @param pfnProgress Progress function. May be nullptr.
851 : *
852 : * @param pProgressData User data of pfnProgress. May be nullptr.
853 : *
854 : * @return CE_Failure if the access fails, otherwise CE_None.
855 : *
856 : * @see GDALRasterBand::RasterIO()
857 : * @since GDAL 3.10
858 : */
859 : template <class T>
860 21 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
861 : double dfYOff, double dfXSize, double dfYSize,
862 : size_t nBufXSize, size_t nBufYSize,
863 : GDALRIOResampleAlg eResampleAlg,
864 : GDALProgressFunc pfnProgress,
865 : void *pProgressData) const
866 : {
867 21 : if (((nBufXSize | nBufYSize) >> 31) != 0)
868 : {
869 2 : return CE_Failure;
870 : }
871 :
872 19 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
873 : {
874 12 : dfXSize = nRasterXSize;
875 12 : dfYSize = nRasterYSize;
876 : }
877 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
878 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
879 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
880 7 : dfYOff + dfYSize > INT_MAX)
881 : {
882 0 : return CE_Failure;
883 : }
884 :
885 : GDALRasterIOExtraArg sExtraArg;
886 19 : sExtraArg.nVersion = 1;
887 19 : sExtraArg.eResampleAlg = eResampleAlg;
888 19 : sExtraArg.pfnProgress = pfnProgress;
889 19 : sExtraArg.pProgressData = pProgressData;
890 19 : sExtraArg.bFloatingPointWindowValidity = true;
891 19 : sExtraArg.dfXOff = dfXOff;
892 19 : sExtraArg.dfYOff = dfYOff;
893 19 : sExtraArg.dfXSize = dfXSize;
894 19 : sExtraArg.dfYSize = dfYSize;
895 19 : const int nXOff = static_cast<int>(dfXOff);
896 19 : const int nYOff = static_cast<int>(dfYOff);
897 19 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
898 19 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
899 19 : if (nBufXSize == 0 && nBufYSize == 0)
900 : {
901 15 : if (static_cast<int>(dfXSize) == dfXSize &&
902 14 : static_cast<int>(dfYSize) == dfYSize)
903 : {
904 14 : nBufXSize = static_cast<int>(dfXSize);
905 14 : nBufYSize = static_cast<int>(dfYSize);
906 : }
907 : else
908 : {
909 1 : CPLError(CE_Failure, CPLE_AppDefined,
910 : "nBufXSize and nBufYSize must be provided if "
911 : "dfXSize or dfYSize is not an integer value");
912 1 : return CE_Failure;
913 : }
914 : }
915 18 : if (nBufXSize == 0 || nBufYSize == 0)
916 : {
917 0 : CPLDebug("GDAL",
918 : "RasterIO() skipped for odd window or buffer size.\n"
919 : " Window = (%d,%d)x%dx%d\n"
920 : " Buffer = %dx%d\n",
921 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
922 : static_cast<int>(nBufYSize));
923 :
924 0 : return CE_None;
925 : }
926 :
927 : if constexpr (SIZEOF_VOIDP < 8)
928 : {
929 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
930 : {
931 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
932 : return CE_Failure;
933 : }
934 : }
935 :
936 18 : if (vData.size() < nBufXSize * nBufYSize)
937 : {
938 : try
939 : {
940 16 : vData.resize(nBufXSize * nBufYSize);
941 : }
942 1 : catch (const std::exception &)
943 : {
944 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
945 1 : return CE_Failure;
946 : }
947 : }
948 :
949 17 : constexpr GSpacing nPixelSpace = sizeof(T);
950 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
951 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
952 :
953 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
954 :
955 : const bool bCallLeaveReadWrite =
956 17 : CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
957 :
958 : CPLErr eErr;
959 : // coverity[identical_branches]
960 17 : if (bForceCachedIO)
961 0 : eErr = pThis->GDALRasterBand::IRasterIO(
962 : GF_Read, nXOff, nYOff, nXSize, nYSize, vData.data(),
963 : static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
964 : nPixelSpace, nLineSpace, &sExtraArg);
965 : else
966 17 : eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
967 : vData.data(), static_cast<int>(nBufXSize),
968 : static_cast<int>(nBufYSize), eBufType,
969 : nPixelSpace, nLineSpace, &sExtraArg);
970 :
971 17 : if (bCallLeaveReadWrite)
972 0 : pThis->LeaveReadWrite();
973 :
974 17 : return eErr;
975 : }
976 :
977 : //! @cond Doxygen_Suppress
978 :
979 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
980 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
981 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
982 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
983 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
984 : void *pProgressData) const;
985 :
986 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
987 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
988 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
989 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
990 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
991 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
992 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
993 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
994 : INSTANTIATE_READ_RASTER_VECTOR(float)
995 : INSTANTIATE_READ_RASTER_VECTOR(double)
996 : // Not allowed by C++ standard
997 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
998 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
999 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
1000 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
1001 :
1002 : //! @endcond
1003 :
1004 : /************************************************************************/
1005 : /* ReadBlock() */
1006 : /************************************************************************/
1007 :
1008 : /**
1009 : * \brief Read a block of image data efficiently.
1010 : *
1011 : * This method accesses a "natural" block from the raster band without
1012 : * resampling, or data type conversion. For a more generalized, but
1013 : * potentially less efficient access use RasterIO().
1014 : *
1015 : * This method is the same as the C GDALReadBlock() function.
1016 : *
1017 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1018 : * block oriented data without an extra copy into an application buffer.
1019 : *
1020 : * The following code would efficiently compute a histogram of eight bit
1021 : * raster data. Note that the final block may be partial ... data beyond
1022 : * the edge of the underlying raster band in these edge blocks is of an
1023 : * undetermined value.
1024 : *
1025 : \code{.cpp}
1026 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1027 :
1028 : {
1029 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1030 :
1031 : CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1032 :
1033 : int nXBlockSize, nYBlockSize;
1034 :
1035 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1036 : int nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
1037 : int nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
1038 :
1039 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1040 :
1041 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1042 : {
1043 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1044 : {
1045 : int nXValid, nYValid;
1046 :
1047 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1048 :
1049 : // Compute the portion of the block that is valid
1050 : // for partial edge blocks.
1051 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1052 :
1053 : // Collect the histogram counts.
1054 : for( int iY = 0; iY < nYValid; iY++ )
1055 : {
1056 : for( int iX = 0; iX < nXValid; iX++ )
1057 : {
1058 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1059 : }
1060 : }
1061 : }
1062 : }
1063 : }
1064 : \endcode
1065 : *
1066 : * @param nXBlockOff the horizontal block offset, with zero indicating
1067 : * the left most block, 1 the next block and so forth.
1068 : *
1069 : * @param nYBlockOff the vertical block offset, with zero indicating
1070 : * the top most block, 1 the next block and so forth.
1071 : *
1072 : * @param pImage the buffer into which the data will be read. The buffer
1073 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1074 : * of type GetRasterDataType().
1075 : *
1076 : * @return CE_None on success or CE_Failure on an error.
1077 : */
1078 :
1079 644 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1080 :
1081 : {
1082 : /* -------------------------------------------------------------------- */
1083 : /* Validate arguments. */
1084 : /* -------------------------------------------------------------------- */
1085 644 : CPLAssert(pImage != nullptr);
1086 :
1087 644 : if (!InitBlockInfo())
1088 0 : return CE_Failure;
1089 :
1090 644 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1091 : {
1092 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1093 : "Illegal nXBlockOff value (%d) in "
1094 : "GDALRasterBand::ReadBlock()\n",
1095 : nXBlockOff);
1096 :
1097 0 : return (CE_Failure);
1098 : }
1099 :
1100 644 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1101 : {
1102 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1103 : "Illegal nYBlockOff value (%d) in "
1104 : "GDALRasterBand::ReadBlock()\n",
1105 : nYBlockOff);
1106 :
1107 0 : return (CE_Failure);
1108 : }
1109 :
1110 : /* -------------------------------------------------------------------- */
1111 : /* Invoke underlying implementation method. */
1112 : /* -------------------------------------------------------------------- */
1113 :
1114 644 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1115 644 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1116 644 : if (bCallLeaveReadWrite)
1117 4 : LeaveReadWrite();
1118 644 : return eErr;
1119 : }
1120 :
1121 : /************************************************************************/
1122 : /* GDALReadBlock() */
1123 : /************************************************************************/
1124 :
1125 : /**
1126 : * \brief Read a block of image data efficiently.
1127 : *
1128 : * @see GDALRasterBand::ReadBlock()
1129 : */
1130 :
1131 67 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1132 : void *pData)
1133 :
1134 : {
1135 67 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1136 :
1137 67 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1138 67 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1139 : }
1140 :
1141 : /************************************************************************/
1142 : /* IReadBlock() */
1143 : /************************************************************************/
1144 :
1145 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1146 : * ) \brief Read a block of data.
1147 : *
1148 : * Default internal implementation ... to be overridden by
1149 : * subclasses that support reading.
1150 : * @param nBlockXOff Block X Offset
1151 : * @param nBlockYOff Block Y Offset
1152 : * @param pData Pixel buffer into which to place read data.
1153 : * @return CE_None on success or CE_Failure on an error.
1154 : */
1155 :
1156 : /************************************************************************/
1157 : /* IWriteBlock() */
1158 : /************************************************************************/
1159 :
1160 : /**
1161 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1162 : * Write a block of data.
1163 : *
1164 : * Default internal implementation ... to be overridden by
1165 : * subclasses that support writing.
1166 : * @param nBlockXOff Block X Offset
1167 : * @param nBlockYOff Block Y Offset
1168 : * @param pData Pixel buffer to write
1169 : * @return CE_None on success or CE_Failure on an error.
1170 : */
1171 :
1172 : /**/
1173 : /**/
1174 :
1175 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1176 : void * /*pData*/)
1177 :
1178 : {
1179 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1180 0 : ReportError(CE_Failure, CPLE_NotSupported,
1181 : "WriteBlock() not supported for this dataset.");
1182 :
1183 0 : return (CE_Failure);
1184 : }
1185 :
1186 : /************************************************************************/
1187 : /* WriteBlock() */
1188 : /************************************************************************/
1189 :
1190 : /**
1191 : * \brief Write a block of image data efficiently.
1192 : *
1193 : * This method accesses a "natural" block from the raster band without
1194 : * resampling, or data type conversion. For a more generalized, but
1195 : * potentially less efficient access use RasterIO().
1196 : *
1197 : * This method is the same as the C GDALWriteBlock() function.
1198 : *
1199 : * See ReadBlock() for an example of block oriented data access.
1200 : *
1201 : * @param nXBlockOff the horizontal block offset, with zero indicating
1202 : * the left most block, 1 the next block and so forth.
1203 : *
1204 : * @param nYBlockOff the vertical block offset, with zero indicating
1205 : * the left most block, 1 the next block and so forth.
1206 : *
1207 : * @param pImage the buffer from which the data will be written. The buffer
1208 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1209 : * of type GetRasterDataType(). Note that the content of the buffer might be
1210 : * temporarily modified during the execution of this method (and eventually
1211 : * restored back to its original content), so it is not safe to use a buffer
1212 : * stored in a read-only section of the calling program.
1213 : *
1214 : * @return CE_None on success or CE_Failure on an error.
1215 : */
1216 :
1217 4888 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1218 :
1219 : {
1220 : /* -------------------------------------------------------------------- */
1221 : /* Validate arguments. */
1222 : /* -------------------------------------------------------------------- */
1223 4888 : CPLAssert(pImage != nullptr);
1224 :
1225 4888 : if (!InitBlockInfo())
1226 0 : return CE_Failure;
1227 :
1228 4888 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1229 : {
1230 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1231 : "Illegal nXBlockOff value (%d) in "
1232 : "GDALRasterBand::WriteBlock()\n",
1233 : nXBlockOff);
1234 :
1235 0 : return (CE_Failure);
1236 : }
1237 :
1238 4888 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1239 : {
1240 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1241 : "Illegal nYBlockOff value (%d) in "
1242 : "GDALRasterBand::WriteBlock()\n",
1243 : nYBlockOff);
1244 :
1245 0 : return (CE_Failure);
1246 : }
1247 :
1248 4888 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1249 : {
1250 0 : return CE_Failure;
1251 : }
1252 :
1253 4888 : if (eFlushBlockErr != CE_None)
1254 : {
1255 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1256 : "An error occurred while writing a dirty block "
1257 : "from GDALRasterBand::WriteBlock");
1258 0 : CPLErr eErr = eFlushBlockErr;
1259 0 : eFlushBlockErr = CE_None;
1260 0 : return eErr;
1261 : }
1262 :
1263 : /* -------------------------------------------------------------------- */
1264 : /* Invoke underlying implementation method. */
1265 : /* -------------------------------------------------------------------- */
1266 :
1267 4888 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1268 4888 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1269 4888 : if (bCallLeaveReadWrite)
1270 4888 : LeaveReadWrite();
1271 :
1272 4888 : return eErr;
1273 : }
1274 :
1275 : /************************************************************************/
1276 : /* GDALWriteBlock() */
1277 : /************************************************************************/
1278 :
1279 : /**
1280 : * \brief Write a block of image data efficiently.
1281 : *
1282 : * @see GDALRasterBand::WriteBlock()
1283 : */
1284 :
1285 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1286 : void *pData)
1287 :
1288 : {
1289 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1290 :
1291 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1292 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1293 : }
1294 :
1295 : /************************************************************************/
1296 : /* EmitErrorMessageIfWriteNotSupported() */
1297 : /************************************************************************/
1298 :
1299 : /**
1300 : * Emit an error message if a write operation to this band is not supported.
1301 : *
1302 : * The base implementation will emit an error message if the access mode is
1303 : * read-only. Derived classes may implement it to provide a custom message.
1304 : *
1305 : * @param pszCaller Calling function.
1306 : * @return true if an error message has been emitted.
1307 : */
1308 423255 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1309 : const char *pszCaller) const
1310 : {
1311 423255 : if (eAccess == GA_ReadOnly)
1312 : {
1313 4 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1314 : "%s: attempt to write to dataset opened in read-only mode.",
1315 : pszCaller);
1316 :
1317 4 : return true;
1318 : }
1319 423251 : return false;
1320 : }
1321 :
1322 : /************************************************************************/
1323 : /* GetActualBlockSize() */
1324 : /************************************************************************/
1325 : /**
1326 : * \brief Fetch the actual block size for a given block offset.
1327 : *
1328 : * Handles partial blocks at the edges of the raster and returns the true
1329 : * number of pixels
1330 : *
1331 : * @param nXBlockOff the horizontal block offset for which to calculate the
1332 : * number of valid pixels, with zero indicating the left most block, 1 the next
1333 : * block and so forth.
1334 : *
1335 : * @param nYBlockOff the vertical block offset, with zero indicating
1336 : * the top most block, 1 the next block and so forth.
1337 : *
1338 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1339 : * the x direction will be stored
1340 : *
1341 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1342 : * the y direction will be stored
1343 : *
1344 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1345 : *
1346 : * @since GDAL 2.2
1347 : */
1348 49178 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1349 : int *pnXValid, int *pnYValid) const
1350 : {
1351 98355 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1352 98353 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1353 98350 : nYBlockOff < 0 || nBlockYSize == 0 ||
1354 49175 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1355 : {
1356 4 : return CE_Failure;
1357 : }
1358 :
1359 49174 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1360 49174 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1361 :
1362 49174 : *pnXValid = nBlockXSize;
1363 49174 : *pnYValid = nBlockYSize;
1364 :
1365 49174 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1366 : {
1367 47790 : *pnXValid = nRasterXSize - nXPixelOff;
1368 : }
1369 :
1370 49174 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1371 : {
1372 3262 : *pnYValid = nRasterYSize - nYPixelOff;
1373 : }
1374 :
1375 49174 : return CE_None;
1376 : }
1377 :
1378 : /************************************************************************/
1379 : /* GDALGetActualBlockSize() */
1380 : /************************************************************************/
1381 :
1382 : /**
1383 : * \brief Retrieve the actual block size for a given block offset.
1384 : *
1385 : * @see GDALRasterBand::GetActualBlockSize()
1386 : */
1387 :
1388 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1389 : int nYBlockOff, int *pnXValid,
1390 : int *pnYValid)
1391 :
1392 : {
1393 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1394 :
1395 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1396 : return (
1397 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1398 : }
1399 :
1400 : /************************************************************************/
1401 : /* GetSuggestedBlockAccessPattern() */
1402 : /************************************************************************/
1403 :
1404 : /**
1405 : * \brief Return the suggested/most efficient access pattern to blocks
1406 : * (for read operations).
1407 : *
1408 : * While all GDAL drivers have to expose a block size, not all can guarantee
1409 : * efficient random access (GSBAP_RANDOM) to any block.
1410 : * Some drivers for example decompress sequentially a compressed stream from
1411 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1412 : * case best performance will be achieved while reading blocks in that order.
1413 : * (accessing blocks in random access in such rasters typically causes the
1414 : * decoding to be re-initialized from the start if accessing blocks in
1415 : * a non-sequential order)
1416 : *
1417 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1418 : * returned by drivers that expose a somewhat artificial block size, because
1419 : * they can extract any part of a raster, but in a rather inefficient way.
1420 : *
1421 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1422 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1423 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1424 : * most efficient strategy is to read as many pixels as possible in the less
1425 : * RasterIO() operations.
1426 : *
1427 : * The return of this method is for example used to determine the swath size
1428 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1429 : *
1430 : * @since GDAL 3.6
1431 : */
1432 :
1433 : GDALSuggestedBlockAccessPattern
1434 2226 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1435 : {
1436 2226 : return GSBAP_UNKNOWN;
1437 : }
1438 :
1439 : /************************************************************************/
1440 : /* GetRasterDataType() */
1441 : /************************************************************************/
1442 :
1443 : /**
1444 : * \brief Fetch the pixel data type for this band.
1445 : *
1446 : * This method is the same as the C function GDALGetRasterDataType().
1447 : *
1448 : * @return the data type of pixels for this band.
1449 : */
1450 :
1451 7585560 : GDALDataType GDALRasterBand::GetRasterDataType() const
1452 :
1453 : {
1454 7585560 : return eDataType;
1455 : }
1456 :
1457 : /************************************************************************/
1458 : /* GDALGetRasterDataType() */
1459 : /************************************************************************/
1460 :
1461 : /**
1462 : * \brief Fetch the pixel data type for this band.
1463 : *
1464 : * @see GDALRasterBand::GetRasterDataType()
1465 : */
1466 :
1467 900270 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1468 :
1469 : {
1470 900270 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1471 :
1472 900270 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1473 900270 : return poBand->GetRasterDataType();
1474 : }
1475 :
1476 : /************************************************************************/
1477 : /* GetBlockSize() */
1478 : /************************************************************************/
1479 :
1480 : /**
1481 : * \brief Fetch the "natural" block size of this band.
1482 : *
1483 : * GDAL contains a concept of the natural block size of rasters so that
1484 : * applications can organized data access efficiently for some file formats.
1485 : * The natural block size is the block size that is most efficient for
1486 : * accessing the format. For many formats this is simple a whole scanline
1487 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1488 : *
1489 : * However, for tiled images this will typically be the tile size.
1490 : *
1491 : * Note that the X and Y block sizes don't have to divide the image size
1492 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1493 : * See ReadBlock() for an example of code dealing with these issues.
1494 : *
1495 : * This method is the same as the C function GDALGetBlockSize().
1496 : *
1497 : * @param pnXSize integer to put the X block size into or NULL.
1498 : *
1499 : * @param pnYSize integer to put the Y block size into or NULL.
1500 : */
1501 :
1502 5009020 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1503 :
1504 : {
1505 5009020 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1506 : {
1507 29271 : ReportError(CE_Failure, CPLE_AppDefined,
1508 29271 : "Invalid block dimension : %d * %d", nBlockXSize,
1509 29271 : nBlockYSize);
1510 0 : if (pnXSize != nullptr)
1511 0 : *pnXSize = 0;
1512 0 : if (pnYSize != nullptr)
1513 0 : *pnYSize = 0;
1514 : }
1515 : else
1516 : {
1517 4979750 : if (pnXSize != nullptr)
1518 4971730 : *pnXSize = nBlockXSize;
1519 4979750 : if (pnYSize != nullptr)
1520 4959760 : *pnYSize = nBlockYSize;
1521 : }
1522 4979750 : }
1523 :
1524 : /************************************************************************/
1525 : /* GDALGetBlockSize() */
1526 : /************************************************************************/
1527 :
1528 : /**
1529 : * \brief Fetch the "natural" block size of this band.
1530 : *
1531 : * @see GDALRasterBand::GetBlockSize()
1532 : */
1533 :
1534 40763 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1535 : int *pnYSize)
1536 :
1537 : {
1538 40763 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1539 :
1540 40763 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1541 40763 : poBand->GetBlockSize(pnXSize, pnYSize);
1542 : }
1543 :
1544 : /************************************************************************/
1545 : /* InitBlockInfo() */
1546 : /************************************************************************/
1547 :
1548 : //! @cond Doxygen_Suppress
1549 3325960 : int GDALRasterBand::InitBlockInfo()
1550 :
1551 : {
1552 3325960 : if (poBandBlockCache != nullptr)
1553 3291870 : return poBandBlockCache->IsInitOK();
1554 :
1555 : /* Do some validation of raster and block dimensions in case the driver */
1556 : /* would have neglected to do it itself */
1557 34090 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1558 : {
1559 2 : ReportError(CE_Failure, CPLE_AppDefined,
1560 : "Invalid block dimension : %d * %d", nBlockXSize,
1561 : nBlockYSize);
1562 0 : return FALSE;
1563 : }
1564 :
1565 34088 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1566 : {
1567 1 : ReportError(CE_Failure, CPLE_AppDefined,
1568 : "Invalid raster dimension : %d * %d", nRasterXSize,
1569 : nRasterYSize);
1570 0 : return FALSE;
1571 : }
1572 :
1573 34087 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1574 34086 : if (nDataTypeSize == 0)
1575 : {
1576 0 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1577 0 : return FALSE;
1578 : }
1579 :
1580 : #if SIZEOF_VOIDP == 4
1581 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1582 : {
1583 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1584 : * multiplication in other cases */
1585 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1586 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1587 : {
1588 : ReportError(CE_Failure, CPLE_NotSupported,
1589 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1590 : nBlockYSize);
1591 : return FALSE;
1592 : }
1593 : }
1594 : #endif
1595 :
1596 34087 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1597 34087 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1598 :
1599 : const char *pszBlockStrategy =
1600 34087 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1601 34089 : bool bUseArray = true;
1602 34089 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1603 : {
1604 34049 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1605 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1606 : {
1607 34030 : GUIntBig nBlockCount =
1608 34030 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1609 34030 : if (poDS != nullptr)
1610 33841 : nBlockCount *= poDS->GetRasterCount();
1611 34030 : bUseArray = (nBlockCount < 1024 * 1024);
1612 : }
1613 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1614 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1615 : {
1616 0 : bUseArray = false;
1617 34049 : }
1618 : }
1619 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1620 40 : bUseArray = false;
1621 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1622 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1623 : pszBlockStrategy);
1624 :
1625 34089 : if (bUseArray)
1626 34019 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1627 : else
1628 : {
1629 70 : if (nBand == 1)
1630 25 : CPLDebug("GDAL", "Use hashset band block cache");
1631 70 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1632 : }
1633 34088 : if (poBandBlockCache == nullptr)
1634 0 : return FALSE;
1635 34088 : return poBandBlockCache->Init();
1636 : }
1637 :
1638 : //! @endcond
1639 :
1640 : /************************************************************************/
1641 : /* FlushCache() */
1642 : /************************************************************************/
1643 :
1644 : /**
1645 : * \brief Flush raster data cache.
1646 : *
1647 : * This call will recover memory used to cache data blocks for this raster
1648 : * band, and ensure that new requests are referred to the underlying driver.
1649 : *
1650 : * This method is the same as the C function GDALFlushRasterCache().
1651 : *
1652 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1653 : * @return CE_None on success.
1654 : */
1655 :
1656 3924490 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1657 :
1658 : {
1659 3969780 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1660 45298 : poBandBlockCache)
1661 2205 : poBandBlockCache->DisableDirtyBlockWriting();
1662 :
1663 3927950 : CPLErr eGlobalErr = eFlushBlockErr;
1664 :
1665 3927950 : if (eFlushBlockErr != CE_None)
1666 : {
1667 0 : ReportError(
1668 : eFlushBlockErr, CPLE_AppDefined,
1669 : "An error occurred while writing a dirty block from FlushCache");
1670 0 : eFlushBlockErr = CE_None;
1671 : }
1672 :
1673 3927950 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1674 3763350 : return eGlobalErr;
1675 :
1676 164601 : return poBandBlockCache->FlushCache();
1677 : }
1678 :
1679 : /************************************************************************/
1680 : /* GDALFlushRasterCache() */
1681 : /************************************************************************/
1682 :
1683 : /**
1684 : * \brief Flush raster data cache.
1685 : *
1686 : * @see GDALRasterBand::FlushCache()
1687 : */
1688 :
1689 130 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1690 :
1691 : {
1692 130 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1693 :
1694 130 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1695 : }
1696 :
1697 : /************************************************************************/
1698 : /* DropCache() */
1699 : /************************************************************************/
1700 :
1701 : /**
1702 : * \brief Drop raster data cache : data in cache will be lost.
1703 : *
1704 : * This call will recover memory used to cache data blocks for this raster
1705 : * band, and ensure that new requests are referred to the underlying driver.
1706 : *
1707 : * This method is the same as the C function GDALDropRasterCache().
1708 : *
1709 : * @return CE_None on success.
1710 : * @since 3.9
1711 : */
1712 :
1713 1 : CPLErr GDALRasterBand::DropCache()
1714 :
1715 : {
1716 1 : CPLErr result = CE_None;
1717 :
1718 1 : if (poBandBlockCache)
1719 1 : poBandBlockCache->DisableDirtyBlockWriting();
1720 :
1721 1 : CPLErr eGlobalErr = eFlushBlockErr;
1722 :
1723 1 : if (eFlushBlockErr != CE_None)
1724 : {
1725 0 : ReportError(
1726 : eFlushBlockErr, CPLE_AppDefined,
1727 : "An error occurred while writing a dirty block from DropCache");
1728 0 : eFlushBlockErr = CE_None;
1729 : }
1730 :
1731 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1732 0 : result = eGlobalErr;
1733 : else
1734 1 : result = poBandBlockCache->FlushCache();
1735 :
1736 1 : if (poBandBlockCache)
1737 1 : poBandBlockCache->EnableDirtyBlockWriting();
1738 :
1739 1 : return result;
1740 : }
1741 :
1742 : /************************************************************************/
1743 : /* GDALDropRasterCache() */
1744 : /************************************************************************/
1745 :
1746 : /**
1747 : * \brief Drop raster data cache.
1748 : *
1749 : * @see GDALRasterBand::DropCache()
1750 : * @since 3.9
1751 : */
1752 :
1753 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1754 :
1755 : {
1756 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1757 :
1758 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1759 : }
1760 :
1761 : /************************************************************************/
1762 : /* UnreferenceBlock() */
1763 : /* */
1764 : /* Unreference the block from our array of blocks */
1765 : /* This method should only be called by */
1766 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1767 : /* the block cache mutex) */
1768 : /************************************************************************/
1769 :
1770 29632 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1771 : {
1772 : #ifdef notdef
1773 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1774 : {
1775 : if (poBandBlockCache == nullptr)
1776 : printf("poBandBlockCache == NULL\n"); /*ok*/
1777 : else
1778 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1779 : printf("caller = %s\n", pszCaller); /*ok*/
1780 : printf("GDALRasterBand: %p\n", this); /*ok*/
1781 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1782 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1783 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1784 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1785 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1786 : poBlock->DumpBlock();
1787 : if (GetDataset() != nullptr)
1788 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1789 : GDALRasterBlock::Verify();
1790 : abort();
1791 : }
1792 : #endif
1793 29632 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1794 29632 : return poBandBlockCache->UnreferenceBlock(poBlock);
1795 : }
1796 :
1797 : /************************************************************************/
1798 : /* AddBlockToFreeList() */
1799 : /* */
1800 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1801 : /* finished with a block about to be free'd, they pass it to that */
1802 : /* method. */
1803 : /************************************************************************/
1804 :
1805 : //! @cond Doxygen_Suppress
1806 29630 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1807 : {
1808 29630 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1809 29631 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1810 : }
1811 :
1812 : //! @endcond
1813 :
1814 : /************************************************************************/
1815 : /* FlushBlock() */
1816 : /************************************************************************/
1817 :
1818 : /** Flush a block out of the block cache.
1819 : * @param nXBlockOff block x offset
1820 : * @param nYBlockOff blocky offset
1821 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1822 : * @return CE_None in case of success, an error code otherwise.
1823 : */
1824 2294 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1825 : int bWriteDirtyBlock)
1826 :
1827 : {
1828 2294 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1829 0 : return (CE_Failure);
1830 :
1831 : /* -------------------------------------------------------------------- */
1832 : /* Validate the request */
1833 : /* -------------------------------------------------------------------- */
1834 2294 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1835 : {
1836 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1837 : "Illegal nBlockXOff value (%d) in "
1838 : "GDALRasterBand::FlushBlock()\n",
1839 : nXBlockOff);
1840 :
1841 0 : return (CE_Failure);
1842 : }
1843 :
1844 2294 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1845 : {
1846 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1847 : "Illegal nBlockYOff value (%d) in "
1848 : "GDALRasterBand::FlushBlock()\n",
1849 : nYBlockOff);
1850 :
1851 0 : return (CE_Failure);
1852 : }
1853 :
1854 2294 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1855 2294 : bWriteDirtyBlock);
1856 : }
1857 :
1858 : /************************************************************************/
1859 : /* TryGetLockedBlockRef() */
1860 : /************************************************************************/
1861 :
1862 : /**
1863 : * \brief Try fetching block ref.
1864 : *
1865 : * This method will returned the requested block (locked) if it is already
1866 : * in the block cache for the layer. If not, nullptr is returned.
1867 : *
1868 : * If a non-NULL value is returned, then a lock for the block will have been
1869 : * acquired on behalf of the caller. It is absolutely imperative that the
1870 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1871 : * severe problems may result.
1872 : *
1873 : * @param nXBlockOff the horizontal block offset, with zero indicating
1874 : * the left most block, 1 the next block and so forth.
1875 : *
1876 : * @param nYBlockOff the vertical block offset, with zero indicating
1877 : * the top most block, 1 the next block and so forth.
1878 : *
1879 : * @return NULL if block not available, or locked block pointer.
1880 : */
1881 :
1882 9983200 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1883 : int nYBlockOff)
1884 :
1885 : {
1886 9983200 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1887 66420 : return nullptr;
1888 :
1889 : /* -------------------------------------------------------------------- */
1890 : /* Validate the request */
1891 : /* -------------------------------------------------------------------- */
1892 9916800 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1893 : {
1894 605 : ReportError(CE_Failure, CPLE_IllegalArg,
1895 : "Illegal nBlockXOff value (%d) in "
1896 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1897 : nXBlockOff);
1898 :
1899 0 : return (nullptr);
1900 : }
1901 :
1902 9916200 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1903 : {
1904 163 : ReportError(CE_Failure, CPLE_IllegalArg,
1905 : "Illegal nBlockYOff value (%d) in "
1906 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1907 : nYBlockOff);
1908 :
1909 0 : return (nullptr);
1910 : }
1911 :
1912 9916030 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1913 : }
1914 :
1915 : /************************************************************************/
1916 : /* GetLockedBlockRef() */
1917 : /************************************************************************/
1918 :
1919 : /**
1920 : * \brief Fetch a pointer to an internally cached raster block.
1921 : *
1922 : * This method will returned the requested block (locked) if it is already
1923 : * in the block cache for the layer. If not, the block will be read from
1924 : * the driver, and placed in the layer block cached, then returned. If an
1925 : * error occurs reading the block from the driver, a NULL value will be
1926 : * returned.
1927 : *
1928 : * If a non-NULL value is returned, then a lock for the block will have been
1929 : * acquired on behalf of the caller. It is absolutely imperative that the
1930 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1931 : * severe problems may result.
1932 : *
1933 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1934 : * enable caching.
1935 : *
1936 : * @param nXBlockOff the horizontal block offset, with zero indicating
1937 : * the left most block, 1 the next block and so forth.
1938 : *
1939 : * @param nYBlockOff the vertical block offset, with zero indicating
1940 : * the top most block, 1 the next block and so forth.
1941 : *
1942 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1943 : * but not actually read from the source. This is useful when it will just
1944 : * be completely set and written back.
1945 : *
1946 : * @return pointer to the block object, or NULL on failure.
1947 : */
1948 :
1949 9781590 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1950 : int nYBlockOff,
1951 : int bJustInitialize)
1952 :
1953 : {
1954 : /* -------------------------------------------------------------------- */
1955 : /* Try and fetch from cache. */
1956 : /* -------------------------------------------------------------------- */
1957 9781590 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1958 :
1959 : /* -------------------------------------------------------------------- */
1960 : /* If we didn't find it in our memory cache, instantiate a */
1961 : /* block (potentially load from disk) and "adopt" it into the */
1962 : /* cache. */
1963 : /* -------------------------------------------------------------------- */
1964 9782430 : if (poBlock == nullptr)
1965 : {
1966 3149080 : if (!InitBlockInfo())
1967 0 : return (nullptr);
1968 :
1969 : /* --------------------------------------------------------------------
1970 : */
1971 : /* Validate the request */
1972 : /* --------------------------------------------------------------------
1973 : */
1974 3149070 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1975 : {
1976 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1977 : "Illegal nBlockXOff value (%d) in "
1978 : "GDALRasterBand::GetLockedBlockRef()\n",
1979 : nXBlockOff);
1980 :
1981 0 : return (nullptr);
1982 : }
1983 :
1984 3149080 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1985 : {
1986 10 : ReportError(CE_Failure, CPLE_IllegalArg,
1987 : "Illegal nBlockYOff value (%d) in "
1988 : "GDALRasterBand::GetLockedBlockRef()\n",
1989 : nYBlockOff);
1990 :
1991 0 : return (nullptr);
1992 : }
1993 :
1994 3149060 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1995 3149070 : if (poBlock == nullptr)
1996 0 : return nullptr;
1997 :
1998 3149070 : poBlock->AddLock();
1999 :
2000 : /* We need to temporarily drop the read-write lock in the following */
2001 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
2002 : */
2003 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
2004 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
2005 : */
2006 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
2007 : */
2008 : /* called and attempt at taking the lock on T2 (already taken).
2009 : * Similarly */
2010 : /* for T2 with D1, hence a deadlock situation (#6163) */
2011 : /* But this may open the door to other problems... */
2012 3149080 : if (poDS)
2013 3148350 : poDS->TemporarilyDropReadWriteLock();
2014 : /* allocate data space */
2015 3149080 : CPLErr eErr = poBlock->Internalize();
2016 3149080 : if (poDS)
2017 3148350 : poDS->ReacquireReadWriteLock();
2018 3149080 : if (eErr != CE_None)
2019 : {
2020 0 : poBlock->DropLock();
2021 0 : delete poBlock;
2022 0 : return nullptr;
2023 : }
2024 :
2025 3149080 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2026 : {
2027 0 : poBlock->DropLock();
2028 0 : delete poBlock;
2029 0 : return nullptr;
2030 : }
2031 :
2032 3149080 : if (!bJustInitialize)
2033 : {
2034 2797780 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2035 2797780 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2036 2797780 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2037 2797780 : if (bCallLeaveReadWrite)
2038 129168 : LeaveReadWrite();
2039 2797770 : if (eErr != CE_None)
2040 : {
2041 1144 : poBlock->DropLock();
2042 1144 : FlushBlock(nXBlockOff, nYBlockOff);
2043 1144 : ReportError(CE_Failure, CPLE_AppDefined,
2044 : "IReadBlock failed at X offset %d, Y offset %d%s",
2045 : nXBlockOff, nYBlockOff,
2046 1144 : (nErrorCounter != CPLGetErrorCounter())
2047 1142 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2048 : : "");
2049 1144 : return nullptr;
2050 : }
2051 :
2052 2796630 : nBlockReads++;
2053 2796630 : if (static_cast<GIntBig>(nBlockReads) ==
2054 2796630 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2055 214 : 1 &&
2056 214 : nBand == 1 && poDS != nullptr)
2057 : {
2058 151 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2059 151 : poDS->GetDescription());
2060 : }
2061 : }
2062 : }
2063 :
2064 9781280 : return poBlock;
2065 : }
2066 :
2067 : /************************************************************************/
2068 : /* Fill() */
2069 : /************************************************************************/
2070 :
2071 : /**
2072 : * \brief Fill this band with a constant value.
2073 : *
2074 : * GDAL makes no guarantees
2075 : * about what values pixels in newly created files are set to, so this
2076 : * method can be used to clear a band to a specified "default" value.
2077 : * The fill value is passed in as a double but this will be converted
2078 : * to the underlying type before writing to the file. An optional
2079 : * second argument allows the imaginary component of a complex
2080 : * constant value to be specified.
2081 : *
2082 : * This method is the same as the C function GDALFillRaster().
2083 : *
2084 : * @param dfRealValue Real component of fill value
2085 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2086 : *
2087 : * @return CE_Failure if the write fails, otherwise CE_None
2088 : */
2089 169321 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2090 : {
2091 :
2092 : // General approach is to construct a source block of the file's
2093 : // native type containing the appropriate value and then copy this
2094 : // to each block in the image via the RasterBlock cache. Using
2095 : // the cache means we avoid file I/O if it is not necessary, at the
2096 : // expense of some extra memcpy's (since we write to the
2097 : // RasterBlock cache, which is then at some point written to the
2098 : // underlying file, rather than simply directly to the underlying
2099 : // file.)
2100 :
2101 : // Check we can write to the file.
2102 169321 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2103 : {
2104 6 : return CE_Failure;
2105 : }
2106 :
2107 : // Make sure block parameters are set.
2108 169315 : if (!InitBlockInfo())
2109 0 : return CE_Failure;
2110 :
2111 : // Allocate the source block.
2112 169315 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2113 169315 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2114 169315 : auto blockByteSize = blockSize * elementSize;
2115 : unsigned char *srcBlock =
2116 169315 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2117 169315 : if (srcBlock == nullptr)
2118 : {
2119 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2120 : "GDALRasterBand::Fill(): Out of memory "
2121 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2122 : static_cast<GUIntBig>(blockByteSize));
2123 0 : return CE_Failure;
2124 : }
2125 :
2126 : // Initialize the source block.
2127 169315 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2128 169315 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2129 : elementSize, blockSize);
2130 :
2131 169315 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2132 :
2133 : // Write block to block cache
2134 647150 : for (int j = 0; j < nBlocksPerColumn; ++j)
2135 : {
2136 1250000 : for (int i = 0; i < nBlocksPerRow; ++i)
2137 : {
2138 772168 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2139 772168 : if (destBlock == nullptr)
2140 : {
2141 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2142 : "GDALRasterBand::Fill(): Error "
2143 : "while retrieving cache block.");
2144 0 : VSIFree(srcBlock);
2145 0 : return CE_Failure;
2146 : }
2147 772168 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2148 772168 : destBlock->MarkDirty();
2149 772168 : destBlock->DropLock();
2150 : }
2151 : }
2152 :
2153 169315 : if (bCallLeaveReadWrite)
2154 168766 : LeaveReadWrite();
2155 :
2156 : // Free up the source block
2157 169315 : VSIFree(srcBlock);
2158 :
2159 169315 : return CE_None;
2160 : }
2161 :
2162 : /************************************************************************/
2163 : /* GDALFillRaster() */
2164 : /************************************************************************/
2165 :
2166 : /**
2167 : * \brief Fill this band with a constant value.
2168 : *
2169 : * @see GDALRasterBand::Fill()
2170 : */
2171 169263 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2172 : double dfImaginaryValue)
2173 : {
2174 169263 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2175 :
2176 169263 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2177 169263 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2178 : }
2179 :
2180 : /************************************************************************/
2181 : /* GetAccess() */
2182 : /************************************************************************/
2183 :
2184 : /**
2185 : * \brief Find out if we have update permission for this band.
2186 : *
2187 : * This method is the same as the C function GDALGetRasterAccess().
2188 : *
2189 : * @return Either GA_Update or GA_ReadOnly.
2190 : */
2191 :
2192 2541 : GDALAccess GDALRasterBand::GetAccess()
2193 :
2194 : {
2195 2541 : return eAccess;
2196 : }
2197 :
2198 : /************************************************************************/
2199 : /* GDALGetRasterAccess() */
2200 : /************************************************************************/
2201 :
2202 : /**
2203 : * \brief Find out if we have update permission for this band.
2204 : *
2205 : * @see GDALRasterBand::GetAccess()
2206 : */
2207 :
2208 1893 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2209 :
2210 : {
2211 1893 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2212 :
2213 1893 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2214 1893 : return poBand->GetAccess();
2215 : }
2216 :
2217 : /************************************************************************/
2218 : /* GetCategoryNames() */
2219 : /************************************************************************/
2220 :
2221 : /**
2222 : * \brief Fetch the list of category names for this raster.
2223 : *
2224 : * The return list is a "StringList" in the sense of the CPL functions.
2225 : * That is a NULL terminated array of strings. Raster values without
2226 : * associated names will have an empty string in the returned list. The
2227 : * first entry in the list is for raster values of zero, and so on.
2228 : *
2229 : * The returned stringlist should not be altered or freed by the application.
2230 : * It may change on the next GDAL call, so please copy it if it is needed
2231 : * for any period of time.
2232 : *
2233 : * This method is the same as the C function GDALGetRasterCategoryNames().
2234 : *
2235 : * @return list of names, or NULL if none.
2236 : */
2237 :
2238 277 : char **GDALRasterBand::GetCategoryNames()
2239 :
2240 : {
2241 277 : return nullptr;
2242 : }
2243 :
2244 : /************************************************************************/
2245 : /* GDALGetRasterCategoryNames() */
2246 : /************************************************************************/
2247 :
2248 : /**
2249 : * \brief Fetch the list of category names for this raster.
2250 : *
2251 : * @see GDALRasterBand::GetCategoryNames()
2252 : */
2253 :
2254 181 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2255 :
2256 : {
2257 181 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2258 :
2259 181 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2260 181 : return poBand->GetCategoryNames();
2261 : }
2262 :
2263 : /************************************************************************/
2264 : /* SetCategoryNames() */
2265 : /************************************************************************/
2266 :
2267 : /**
2268 : * \fn GDALRasterBand::SetCategoryNames(char**)
2269 : * \brief Set the category names for this band.
2270 : *
2271 : * See the GetCategoryNames() method for more on the interpretation of
2272 : * category names.
2273 : *
2274 : * This method is the same as the C function GDALSetRasterCategoryNames().
2275 : *
2276 : * @param papszNames the NULL terminated StringList of category names. May
2277 : * be NULL to just clear the existing list.
2278 : *
2279 : * @return CE_None on success of CE_Failure on failure. If unsupported
2280 : * by the driver CE_Failure is returned, but no error message is reported.
2281 : */
2282 :
2283 : /**/
2284 : /**/
2285 :
2286 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2287 : {
2288 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2289 0 : ReportError(CE_Failure, CPLE_NotSupported,
2290 : "SetCategoryNames() not supported for this dataset.");
2291 :
2292 0 : return CE_Failure;
2293 : }
2294 :
2295 : /************************************************************************/
2296 : /* GDALSetCategoryNames() */
2297 : /************************************************************************/
2298 :
2299 : /**
2300 : * \brief Set the category names for this band.
2301 : *
2302 : * @see GDALRasterBand::SetCategoryNames()
2303 : */
2304 :
2305 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2306 : CSLConstList papszNames)
2307 :
2308 : {
2309 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2310 :
2311 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2312 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2313 : }
2314 :
2315 : /************************************************************************/
2316 : /* GetNoDataValue() */
2317 : /************************************************************************/
2318 :
2319 : /**
2320 : * \brief Fetch the no data value for this band.
2321 : *
2322 : * If there is no out of data value, an out of range value will generally
2323 : * be returned. The no data value for a band is generally a special marker
2324 : * value used to mark pixels that are not valid data. Such pixels should
2325 : * generally not be displayed, nor contribute to analysis operations.
2326 : *
2327 : * The no data value returned is 'raw', meaning that it has no offset and
2328 : * scale applied.
2329 : *
2330 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2331 : * lossy if the nodata value cannot exactly been represented by a double.
2332 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2333 : *
2334 : * This method is the same as the C function GDALGetRasterNoDataValue().
2335 : *
2336 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2337 : * is actually associated with this layer. May be NULL (default).
2338 : *
2339 : * @return the nodata value for this band.
2340 : */
2341 :
2342 31430 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2343 :
2344 : {
2345 31430 : if (pbSuccess != nullptr)
2346 31430 : *pbSuccess = FALSE;
2347 :
2348 31430 : return -1e10;
2349 : }
2350 :
2351 : /************************************************************************/
2352 : /* GDALGetRasterNoDataValue() */
2353 : /************************************************************************/
2354 :
2355 : /**
2356 : * \brief Fetch the no data value for this band.
2357 : *
2358 : * @see GDALRasterBand::GetNoDataValue()
2359 : */
2360 :
2361 414066 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2362 : int *pbSuccess)
2363 :
2364 : {
2365 414066 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2366 :
2367 414066 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2368 414066 : return poBand->GetNoDataValue(pbSuccess);
2369 : }
2370 :
2371 : /************************************************************************/
2372 : /* GetNoDataValueAsInt64() */
2373 : /************************************************************************/
2374 :
2375 : /**
2376 : * \brief Fetch the no data value for this band.
2377 : *
2378 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2379 : *
2380 : * If there is no out of data value, an out of range value will generally
2381 : * be returned. The no data value for a band is generally a special marker
2382 : * value used to mark pixels that are not valid data. Such pixels should
2383 : * generally not be displayed, nor contribute to analysis operations.
2384 : *
2385 : * The no data value returned is 'raw', meaning that it has no offset and
2386 : * scale applied.
2387 : *
2388 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2389 : *
2390 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2391 : * is actually associated with this layer. May be NULL (default).
2392 : *
2393 : * @return the nodata value for this band.
2394 : *
2395 : * @since GDAL 3.5
2396 : */
2397 :
2398 4 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2399 :
2400 : {
2401 4 : if (pbSuccess != nullptr)
2402 4 : *pbSuccess = FALSE;
2403 :
2404 4 : return std::numeric_limits<int64_t>::min();
2405 : }
2406 :
2407 : /************************************************************************/
2408 : /* GDALGetRasterNoDataValueAsInt64() */
2409 : /************************************************************************/
2410 :
2411 : /**
2412 : * \brief Fetch the no data value for this band.
2413 : *
2414 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2415 : *
2416 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2417 : *
2418 : * @since GDAL 3.5
2419 : */
2420 :
2421 27 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2422 : int *pbSuccess)
2423 :
2424 : {
2425 27 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2426 : std::numeric_limits<int64_t>::min());
2427 :
2428 27 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2429 27 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2430 : }
2431 :
2432 : /************************************************************************/
2433 : /* GetNoDataValueAsUInt64() */
2434 : /************************************************************************/
2435 :
2436 : /**
2437 : * \brief Fetch the no data value for this band.
2438 : *
2439 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2440 : *
2441 : * If there is no out of data value, an out of range value will generally
2442 : * be returned. The no data value for a band is generally a special marker
2443 : * value used to mark pixels that are not valid data. Such pixels should
2444 : * generally not be displayed, nor contribute to analysis operations.
2445 : *
2446 : * The no data value returned is 'raw', meaning that it has no offset and
2447 : * scale applied.
2448 : *
2449 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2450 : *
2451 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2452 : * is actually associated with this layer. May be NULL (default).
2453 : *
2454 : * @return the nodata value for this band.
2455 : *
2456 : * @since GDAL 3.5
2457 : */
2458 :
2459 3 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2460 :
2461 : {
2462 3 : if (pbSuccess != nullptr)
2463 3 : *pbSuccess = FALSE;
2464 :
2465 3 : return std::numeric_limits<uint64_t>::max();
2466 : }
2467 :
2468 : /************************************************************************/
2469 : /* GDALGetRasterNoDataValueAsUInt64() */
2470 : /************************************************************************/
2471 :
2472 : /**
2473 : * \brief Fetch the no data value for this band.
2474 : *
2475 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2476 : *
2477 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2478 : *
2479 : * @since GDAL 3.5
2480 : */
2481 :
2482 18 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2483 : int *pbSuccess)
2484 :
2485 : {
2486 18 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2487 : std::numeric_limits<uint64_t>::max());
2488 :
2489 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2490 18 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2491 : }
2492 :
2493 : /************************************************************************/
2494 : /* SetNoDataValueAsString() */
2495 : /************************************************************************/
2496 :
2497 : /**
2498 : * \brief Set the no data value for this band.
2499 : *
2500 : * Depending on drivers, changing the no data value may or may not have an
2501 : * effect on the pixel values of a raster that has just been created. It is
2502 : * thus advised to explicitly called Fill() if the intent is to initialize
2503 : * the raster to the nodata value.
2504 : * In any case, changing an existing no data value, when one already exists and
2505 : * the dataset exists or has been initialized, has no effect on the pixel whose
2506 : * value matched the previous nodata value.
2507 : *
2508 : * To clear the nodata value, use DeleteNoDataValue().
2509 : *
2510 : * @param pszNoData the value to set.
2511 : * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2512 : * If the value cannot be exactly represented on the output data
2513 : * type, *pbCannotBeExactlyRepresented will be set to true.
2514 : *
2515 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2516 : * by the driver, CE_Failure is returned but no error message will have
2517 : * been emitted.
2518 : *
2519 : * @since 3.11
2520 : */
2521 :
2522 : CPLErr
2523 113 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2524 : bool *pbCannotBeExactlyRepresented)
2525 : {
2526 113 : if (pbCannotBeExactlyRepresented)
2527 113 : *pbCannotBeExactlyRepresented = false;
2528 113 : if (eDataType == GDT_Int64)
2529 : {
2530 8 : if (strchr(pszNoData, '.') ||
2531 3 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2532 : {
2533 2 : char *endptr = nullptr;
2534 2 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2535 4 : if (endptr == pszNoData + strlen(pszNoData) &&
2536 2 : GDALIsValueExactAs<int64_t>(dfVal))
2537 : {
2538 0 : return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2539 : }
2540 : }
2541 : else
2542 : {
2543 : try
2544 : {
2545 7 : const auto val = std::stoll(pszNoData);
2546 1 : return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2547 : }
2548 2 : catch (const std::exception &)
2549 : {
2550 : }
2551 : }
2552 : }
2553 108 : else if (eDataType == GDT_UInt64)
2554 : {
2555 2 : if (strchr(pszNoData, '.') ||
2556 1 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2557 : {
2558 0 : char *endptr = nullptr;
2559 0 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2560 0 : if (endptr == pszNoData + strlen(pszNoData) &&
2561 0 : GDALIsValueExactAs<uint64_t>(dfVal))
2562 : {
2563 0 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2564 : }
2565 : }
2566 : else
2567 : {
2568 : try
2569 : {
2570 1 : const auto val = std::stoull(pszNoData);
2571 1 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2572 : }
2573 0 : catch (const std::exception &)
2574 : {
2575 : }
2576 : }
2577 : }
2578 107 : else if (eDataType == GDT_Float32)
2579 : {
2580 10 : char *endptr = nullptr;
2581 10 : const float fVal = CPLStrtof(pszNoData, &endptr);
2582 10 : if (endptr == pszNoData + strlen(pszNoData))
2583 : {
2584 10 : return SetNoDataValue(fVal);
2585 : }
2586 : }
2587 : else
2588 : {
2589 97 : char *endptr = nullptr;
2590 97 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2591 194 : if (endptr == pszNoData + strlen(pszNoData) &&
2592 97 : GDALIsValueExactAs(dfVal, eDataType))
2593 : {
2594 96 : return SetNoDataValue(dfVal);
2595 : }
2596 : }
2597 5 : if (pbCannotBeExactlyRepresented)
2598 5 : *pbCannotBeExactlyRepresented = true;
2599 5 : return CE_Failure;
2600 : }
2601 :
2602 : /************************************************************************/
2603 : /* SetNoDataValue() */
2604 : /************************************************************************/
2605 :
2606 : /**
2607 : * \fn GDALRasterBand::SetNoDataValue(double)
2608 : * \brief Set the no data value for this band.
2609 : *
2610 : * Depending on drivers, changing the no data value may or may not have an
2611 : * effect on the pixel values of a raster that has just been created. It is
2612 : * thus advised to explicitly called Fill() if the intent is to initialize
2613 : * the raster to the nodata value.
2614 : * In any case, changing an existing no data value, when one already exists and
2615 : * the dataset exists or has been initialized, has no effect on the pixel whose
2616 : * value matched the previous nodata value.
2617 : *
2618 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2619 : * be represented by a double, use SetNoDataValueAsInt64() or
2620 : * SetNoDataValueAsUInt64() instead.
2621 : *
2622 : * To clear the nodata value, use DeleteNoDataValue().
2623 : *
2624 : * This method is the same as the C function GDALSetRasterNoDataValue().
2625 : *
2626 : * @param dfNoData the value to set.
2627 : *
2628 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2629 : * by the driver, CE_Failure is returned but no error message will have
2630 : * been emitted.
2631 : */
2632 :
2633 : /**/
2634 : /**/
2635 :
2636 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2637 :
2638 : {
2639 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2640 0 : ReportError(CE_Failure, CPLE_NotSupported,
2641 : "SetNoDataValue() not supported for this dataset.");
2642 :
2643 0 : return CE_Failure;
2644 : }
2645 :
2646 : /************************************************************************/
2647 : /* GDALSetRasterNoDataValue() */
2648 : /************************************************************************/
2649 :
2650 : /**
2651 : * \brief Set the no data value for this band.
2652 : *
2653 : * Depending on drivers, changing the no data value may or may not have an
2654 : * effect on the pixel values of a raster that has just been created. It is
2655 : * thus advised to explicitly called Fill() if the intent is to initialize
2656 : * the raster to the nodata value.
2657 : * In any case, changing an existing no data value, when one already exists and
2658 : * the dataset exists or has been initialized, has no effect on the pixel whose
2659 : * value matched the previous nodata value.
2660 : *
2661 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2662 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2663 : * GDALSetRasterNoDataValueAsUInt64() instead.
2664 : *
2665 : * @see GDALRasterBand::SetNoDataValue()
2666 : */
2667 :
2668 818 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2669 : double dfValue)
2670 :
2671 : {
2672 818 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2673 :
2674 818 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2675 818 : return poBand->SetNoDataValue(dfValue);
2676 : }
2677 :
2678 : /************************************************************************/
2679 : /* SetNoDataValueAsInt64() */
2680 : /************************************************************************/
2681 :
2682 : /**
2683 : * \brief Set the no data value for this band.
2684 : *
2685 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2686 : *
2687 : * Depending on drivers, changing the no data value may or may not have an
2688 : * effect on the pixel values of a raster that has just been created. It is
2689 : * thus advised to explicitly called Fill() if the intent is to initialize
2690 : * the raster to the nodata value.
2691 : * In ay case, changing an existing no data value, when one already exists and
2692 : * the dataset exists or has been initialized, has no effect on the pixel whose
2693 : * value matched the previous nodata value.
2694 : *
2695 : * To clear the nodata value, use DeleteNoDataValue().
2696 : *
2697 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2698 : *
2699 : * @param nNoDataValue the value to set.
2700 : *
2701 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2702 : * by the driver, CE_Failure is returned but no error message will have
2703 : * been emitted.
2704 : *
2705 : * @since GDAL 3.5
2706 : */
2707 :
2708 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2709 :
2710 : {
2711 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2712 0 : ReportError(CE_Failure, CPLE_NotSupported,
2713 : "SetNoDataValueAsInt64() not supported for this dataset.");
2714 :
2715 0 : return CE_Failure;
2716 : }
2717 :
2718 : /************************************************************************/
2719 : /* GDALSetRasterNoDataValueAsInt64() */
2720 : /************************************************************************/
2721 :
2722 : /**
2723 : * \brief Set the no data value for this band.
2724 : *
2725 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2726 : *
2727 : * Depending on drivers, changing the no data value may or may not have an
2728 : * effect on the pixel values of a raster that has just been created. It is
2729 : * thus advised to explicitly called Fill() if the intent is to initialize
2730 : * the raster to the nodata value.
2731 : * In ay case, changing an existing no data value, when one already exists and
2732 : * the dataset exists or has been initialized, has no effect on the pixel whose
2733 : * value matched the previous nodata value.
2734 : *
2735 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2736 : *
2737 : * @since GDAL 3.5
2738 : */
2739 :
2740 18 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2741 : int64_t nValue)
2742 :
2743 : {
2744 18 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2745 :
2746 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2747 18 : return poBand->SetNoDataValueAsInt64(nValue);
2748 : }
2749 :
2750 : /************************************************************************/
2751 : /* SetNoDataValueAsUInt64() */
2752 : /************************************************************************/
2753 :
2754 : /**
2755 : * \brief Set the no data value for this band.
2756 : *
2757 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2758 : *
2759 : * Depending on drivers, changing the no data value may or may not have an
2760 : * effect on the pixel values of a raster that has just been created. It is
2761 : * thus advised to explicitly called Fill() if the intent is to initialize
2762 : * the raster to the nodata value.
2763 : * In ay case, changing an existing no data value, when one already exists and
2764 : * the dataset exists or has been initialized, has no effect on the pixel whose
2765 : * value matched the previous nodata value.
2766 : *
2767 : * To clear the nodata value, use DeleteNoDataValue().
2768 : *
2769 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2770 : *
2771 : * @param nNoDataValue the value to set.
2772 : *
2773 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2774 : * by the driver, CE_Failure is returned but no error message will have
2775 : * been emitted.
2776 : *
2777 : * @since GDAL 3.5
2778 : */
2779 :
2780 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2781 :
2782 : {
2783 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2784 0 : ReportError(CE_Failure, CPLE_NotSupported,
2785 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2786 :
2787 0 : return CE_Failure;
2788 : }
2789 :
2790 : /************************************************************************/
2791 : /* GDALSetRasterNoDataValueAsUInt64() */
2792 : /************************************************************************/
2793 :
2794 : /**
2795 : * \brief Set the no data value for this band.
2796 : *
2797 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2798 : *
2799 : * Depending on drivers, changing the no data value may or may not have an
2800 : * effect on the pixel values of a raster that has just been created. It is
2801 : * thus advised to explicitly called Fill() if the intent is to initialize
2802 : * the raster to the nodata value.
2803 : * In ay case, changing an existing no data value, when one already exists and
2804 : * the dataset exists or has been initialized, has no effect on the pixel whose
2805 : * value matched the previous nodata value.
2806 : *
2807 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2808 : *
2809 : * @since GDAL 3.5
2810 : */
2811 :
2812 16 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2813 : uint64_t nValue)
2814 :
2815 : {
2816 16 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2817 :
2818 16 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2819 16 : return poBand->SetNoDataValueAsUInt64(nValue);
2820 : }
2821 :
2822 : /************************************************************************/
2823 : /* DeleteNoDataValue() */
2824 : /************************************************************************/
2825 :
2826 : /**
2827 : * \brief Remove the no data value for this band.
2828 : *
2829 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2830 : *
2831 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2832 : * by the driver, CE_Failure is returned but no error message will have
2833 : * been emitted.
2834 : *
2835 : * @since GDAL 2.1
2836 : */
2837 :
2838 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2839 :
2840 : {
2841 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2842 0 : ReportError(CE_Failure, CPLE_NotSupported,
2843 : "DeleteNoDataValue() not supported for this dataset.");
2844 :
2845 0 : return CE_Failure;
2846 : }
2847 :
2848 : /************************************************************************/
2849 : /* GDALDeleteRasterNoDataValue() */
2850 : /************************************************************************/
2851 :
2852 : /**
2853 : * \brief Remove the no data value for this band.
2854 : *
2855 : * @see GDALRasterBand::DeleteNoDataValue()
2856 : *
2857 : * @since GDAL 2.1
2858 : */
2859 :
2860 66 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2861 :
2862 : {
2863 66 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2864 :
2865 66 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2866 66 : return poBand->DeleteNoDataValue();
2867 : }
2868 :
2869 : /************************************************************************/
2870 : /* GetMaximum() */
2871 : /************************************************************************/
2872 :
2873 : /**
2874 : * \brief Fetch the maximum value for this band.
2875 : *
2876 : * For file formats that don't know this intrinsically, the maximum supported
2877 : * value for the data type will generally be returned.
2878 : *
2879 : * This method is the same as the C function GDALGetRasterMaximum().
2880 : *
2881 : * @param pbSuccess pointer to a boolean to use to indicate if the
2882 : * returned value is a tight maximum or not. May be NULL (default).
2883 : *
2884 : * @return the maximum raster value (excluding no data pixels)
2885 : */
2886 :
2887 508 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2888 :
2889 : {
2890 508 : const char *pszValue = nullptr;
2891 :
2892 508 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2893 : {
2894 46 : if (pbSuccess != nullptr)
2895 41 : *pbSuccess = TRUE;
2896 :
2897 46 : return CPLAtofM(pszValue);
2898 : }
2899 :
2900 462 : if (pbSuccess != nullptr)
2901 458 : *pbSuccess = FALSE;
2902 :
2903 462 : switch (eDataType)
2904 : {
2905 315 : case GDT_Byte:
2906 : {
2907 315 : EnablePixelTypeSignedByteWarning(false);
2908 : const char *pszPixelType =
2909 315 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2910 315 : EnablePixelTypeSignedByteWarning(true);
2911 315 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2912 0 : return 127;
2913 :
2914 315 : return 255;
2915 : }
2916 :
2917 1 : case GDT_Int8:
2918 1 : return 127;
2919 :
2920 18 : case GDT_UInt16:
2921 18 : return 65535;
2922 :
2923 23 : case GDT_Int16:
2924 : case GDT_CInt16:
2925 23 : return 32767;
2926 :
2927 39 : case GDT_Int32:
2928 : case GDT_CInt32:
2929 39 : return 2147483647.0;
2930 :
2931 12 : case GDT_UInt32:
2932 12 : return 4294967295.0;
2933 :
2934 1 : case GDT_Int64:
2935 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2936 :
2937 1 : case GDT_UInt64:
2938 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2939 :
2940 0 : case GDT_Float16:
2941 : case GDT_CFloat16:
2942 0 : return 65504.0;
2943 :
2944 30 : case GDT_Float32:
2945 : case GDT_CFloat32:
2946 30 : return 4294967295.0; // Not actually accurate.
2947 :
2948 22 : case GDT_Float64:
2949 : case GDT_CFloat64:
2950 22 : return 4294967295.0; // Not actually accurate.
2951 :
2952 0 : case GDT_Unknown:
2953 : case GDT_TypeCount:
2954 0 : break;
2955 : }
2956 0 : return 4294967295.0; // Not actually accurate.
2957 : }
2958 :
2959 : /************************************************************************/
2960 : /* GDALGetRasterMaximum() */
2961 : /************************************************************************/
2962 :
2963 : /**
2964 : * \brief Fetch the maximum value for this band.
2965 : *
2966 : * @see GDALRasterBand::GetMaximum()
2967 : */
2968 :
2969 278 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2970 :
2971 : {
2972 278 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2973 :
2974 278 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2975 278 : return poBand->GetMaximum(pbSuccess);
2976 : }
2977 :
2978 : /************************************************************************/
2979 : /* GetMinimum() */
2980 : /************************************************************************/
2981 :
2982 : /**
2983 : * \brief Fetch the minimum value for this band.
2984 : *
2985 : * For file formats that don't know this intrinsically, the minimum supported
2986 : * value for the data type will generally be returned.
2987 : *
2988 : * This method is the same as the C function GDALGetRasterMinimum().
2989 : *
2990 : * @param pbSuccess pointer to a boolean to use to indicate if the
2991 : * returned value is a tight minimum or not. May be NULL (default).
2992 : *
2993 : * @return the minimum raster value (excluding no data pixels)
2994 : */
2995 :
2996 516 : double GDALRasterBand::GetMinimum(int *pbSuccess)
2997 :
2998 : {
2999 516 : const char *pszValue = nullptr;
3000 :
3001 516 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
3002 : {
3003 51 : if (pbSuccess != nullptr)
3004 46 : *pbSuccess = TRUE;
3005 :
3006 51 : return CPLAtofM(pszValue);
3007 : }
3008 :
3009 465 : if (pbSuccess != nullptr)
3010 461 : *pbSuccess = FALSE;
3011 :
3012 465 : switch (eDataType)
3013 : {
3014 318 : case GDT_Byte:
3015 : {
3016 318 : EnablePixelTypeSignedByteWarning(false);
3017 : const char *pszPixelType =
3018 318 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3019 318 : EnablePixelTypeSignedByteWarning(true);
3020 318 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3021 0 : return -128;
3022 :
3023 318 : return 0;
3024 : }
3025 :
3026 1 : case GDT_Int8:
3027 1 : return -128;
3028 : break;
3029 :
3030 18 : case GDT_UInt16:
3031 18 : return 0;
3032 :
3033 23 : case GDT_Int16:
3034 : case GDT_CInt16:
3035 23 : return -32768;
3036 :
3037 39 : case GDT_Int32:
3038 : case GDT_CInt32:
3039 39 : return -2147483648.0;
3040 :
3041 12 : case GDT_UInt32:
3042 12 : return 0;
3043 :
3044 1 : case GDT_Int64:
3045 1 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3046 :
3047 1 : case GDT_UInt64:
3048 1 : return 0;
3049 :
3050 0 : case GDT_Float16:
3051 : case GDT_CFloat16:
3052 0 : return -65504.0;
3053 :
3054 30 : case GDT_Float32:
3055 : case GDT_CFloat32:
3056 30 : return -4294967295.0; // Not actually accurate.
3057 :
3058 22 : case GDT_Float64:
3059 : case GDT_CFloat64:
3060 22 : return -4294967295.0; // Not actually accurate.
3061 :
3062 0 : case GDT_Unknown:
3063 : case GDT_TypeCount:
3064 0 : break;
3065 : }
3066 0 : return -4294967295.0; // Not actually accurate.
3067 : }
3068 :
3069 : /************************************************************************/
3070 : /* GDALGetRasterMinimum() */
3071 : /************************************************************************/
3072 :
3073 : /**
3074 : * \brief Fetch the minimum value for this band.
3075 : *
3076 : * @see GDALRasterBand::GetMinimum()
3077 : */
3078 :
3079 288 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3080 :
3081 : {
3082 288 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3083 :
3084 288 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3085 288 : return poBand->GetMinimum(pbSuccess);
3086 : }
3087 :
3088 : /************************************************************************/
3089 : /* GetColorInterpretation() */
3090 : /************************************************************************/
3091 :
3092 : /**
3093 : * \brief How should this band be interpreted as color?
3094 : *
3095 : * GCI_Undefined is returned when the format doesn't know anything
3096 : * about the color interpretation.
3097 : *
3098 : * This method is the same as the C function
3099 : * GDALGetRasterColorInterpretation().
3100 : *
3101 : * @return color interpretation value for band.
3102 : */
3103 :
3104 153 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
3105 :
3106 : {
3107 153 : return GCI_Undefined;
3108 : }
3109 :
3110 : /************************************************************************/
3111 : /* GDALGetRasterColorInterpretation() */
3112 : /************************************************************************/
3113 :
3114 : /**
3115 : * \brief How should this band be interpreted as color?
3116 : *
3117 : * @see GDALRasterBand::GetColorInterpretation()
3118 : */
3119 :
3120 : GDALColorInterp CPL_STDCALL
3121 5348 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3122 :
3123 : {
3124 5348 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3125 :
3126 5348 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3127 5348 : return poBand->GetColorInterpretation();
3128 : }
3129 :
3130 : /************************************************************************/
3131 : /* SetColorInterpretation() */
3132 : /************************************************************************/
3133 :
3134 : /**
3135 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3136 : * \brief Set color interpretation of a band.
3137 : *
3138 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3139 : *
3140 : * @param eColorInterp the new color interpretation to apply to this band.
3141 : *
3142 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3143 : */
3144 :
3145 : /**/
3146 : /**/
3147 :
3148 3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3149 :
3150 : {
3151 3 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3152 3 : ReportError(CE_Failure, CPLE_NotSupported,
3153 : "SetColorInterpretation() not supported for this dataset.");
3154 3 : return CE_Failure;
3155 : }
3156 :
3157 : /************************************************************************/
3158 : /* GDALSetRasterColorInterpretation() */
3159 : /************************************************************************/
3160 :
3161 : /**
3162 : * \brief Set color interpretation of a band.
3163 : *
3164 : * @see GDALRasterBand::SetColorInterpretation()
3165 : */
3166 :
3167 1804 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3168 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3169 :
3170 : {
3171 1804 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3172 :
3173 1804 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3174 1804 : return poBand->SetColorInterpretation(eColorInterp);
3175 : }
3176 :
3177 : /************************************************************************/
3178 : /* GetColorTable() */
3179 : /************************************************************************/
3180 :
3181 : /**
3182 : * \brief Fetch the color table associated with band.
3183 : *
3184 : * If there is no associated color table, the return result is NULL. The
3185 : * returned color table remains owned by the GDALRasterBand, and can't
3186 : * be depended on for long, nor should it ever be modified by the caller.
3187 : *
3188 : * This method is the same as the C function GDALGetRasterColorTable().
3189 : *
3190 : * @return internal color table, or NULL.
3191 : */
3192 :
3193 243 : GDALColorTable *GDALRasterBand::GetColorTable()
3194 :
3195 : {
3196 243 : return nullptr;
3197 : }
3198 :
3199 : /************************************************************************/
3200 : /* GDALGetRasterColorTable() */
3201 : /************************************************************************/
3202 :
3203 : /**
3204 : * \brief Fetch the color table associated with band.
3205 : *
3206 : * @see GDALRasterBand::GetColorTable()
3207 : */
3208 :
3209 1851 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3210 :
3211 : {
3212 1851 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3213 :
3214 1851 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3215 1851 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3216 : }
3217 :
3218 : /************************************************************************/
3219 : /* SetColorTable() */
3220 : /************************************************************************/
3221 :
3222 : /**
3223 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3224 : * \brief Set the raster color table.
3225 : *
3226 : * The driver will make a copy of all desired data in the colortable. It
3227 : * remains owned by the caller after the call.
3228 : *
3229 : * This method is the same as the C function GDALSetRasterColorTable().
3230 : *
3231 : * @param poCT the color table to apply. This may be NULL to clear the color
3232 : * table (where supported).
3233 : *
3234 : * @return CE_None on success, or CE_Failure on failure. If the action is
3235 : * unsupported by the driver, a value of CE_Failure is returned, but no
3236 : * error is issued.
3237 : */
3238 :
3239 : /**/
3240 : /**/
3241 :
3242 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3243 :
3244 : {
3245 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3246 0 : ReportError(CE_Failure, CPLE_NotSupported,
3247 : "SetColorTable() not supported for this dataset.");
3248 0 : return CE_Failure;
3249 : }
3250 :
3251 : /************************************************************************/
3252 : /* GDALSetRasterColorTable() */
3253 : /************************************************************************/
3254 :
3255 : /**
3256 : * \brief Set the raster color table.
3257 : *
3258 : * @see GDALRasterBand::SetColorTable()
3259 : */
3260 :
3261 77 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3262 : GDALColorTableH hCT)
3263 :
3264 : {
3265 77 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3266 :
3267 77 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3268 77 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3269 : }
3270 :
3271 : /************************************************************************/
3272 : /* HasArbitraryOverviews() */
3273 : /************************************************************************/
3274 :
3275 : /**
3276 : * \brief Check for arbitrary overviews.
3277 : *
3278 : * This returns TRUE if the underlying datastore can compute arbitrary
3279 : * overviews efficiently, such as is the case with OGDI over a network.
3280 : * Datastores with arbitrary overviews don't generally have any fixed
3281 : * overviews, but the RasterIO() method can be used in downsampling mode
3282 : * to get overview data efficiently.
3283 : *
3284 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3285 : *
3286 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3287 : * FALSE.
3288 : */
3289 :
3290 247 : int GDALRasterBand::HasArbitraryOverviews()
3291 :
3292 : {
3293 247 : return FALSE;
3294 : }
3295 :
3296 : /************************************************************************/
3297 : /* GDALHasArbitraryOverviews() */
3298 : /************************************************************************/
3299 :
3300 : /**
3301 : * \brief Check for arbitrary overviews.
3302 : *
3303 : * @see GDALRasterBand::HasArbitraryOverviews()
3304 : */
3305 :
3306 171 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3307 :
3308 : {
3309 171 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3310 :
3311 171 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3312 171 : return poBand->HasArbitraryOverviews();
3313 : }
3314 :
3315 : /************************************************************************/
3316 : /* GetOverviewCount() */
3317 : /************************************************************************/
3318 :
3319 : /**
3320 : * \brief Return the number of overview layers available.
3321 : *
3322 : * This method is the same as the C function GDALGetOverviewCount().
3323 : *
3324 : * @return overview count, zero if none.
3325 : */
3326 :
3327 660875 : int GDALRasterBand::GetOverviewCount()
3328 :
3329 : {
3330 1316770 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3331 655894 : poDS->AreOverviewsEnabled())
3332 655894 : return poDS->oOvManager.GetOverviewCount(nBand);
3333 :
3334 4981 : return 0;
3335 : }
3336 :
3337 : /************************************************************************/
3338 : /* GDALGetOverviewCount() */
3339 : /************************************************************************/
3340 :
3341 : /**
3342 : * \brief Return the number of overview layers available.
3343 : *
3344 : * @see GDALRasterBand::GetOverviewCount()
3345 : */
3346 :
3347 3199 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3348 :
3349 : {
3350 3199 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3351 :
3352 3199 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3353 3199 : return poBand->GetOverviewCount();
3354 : }
3355 :
3356 : /************************************************************************/
3357 : /* GetOverview() */
3358 : /************************************************************************/
3359 :
3360 : /**
3361 : * \brief Fetch overview raster band object.
3362 : *
3363 : * This method is the same as the C function GDALGetOverview().
3364 : *
3365 : * @param i overview index between 0 and GetOverviewCount()-1.
3366 : *
3367 : * @return overview GDALRasterBand.
3368 : */
3369 :
3370 792 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3371 :
3372 : {
3373 1529 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3374 737 : poDS->AreOverviewsEnabled())
3375 737 : return poDS->oOvManager.GetOverview(nBand, i);
3376 :
3377 55 : return nullptr;
3378 : }
3379 :
3380 : /************************************************************************/
3381 : /* GDALGetOverview() */
3382 : /************************************************************************/
3383 :
3384 : /**
3385 : * \brief Fetch overview raster band object.
3386 : *
3387 : * @see GDALRasterBand::GetOverview()
3388 : */
3389 :
3390 5576 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3391 :
3392 : {
3393 5576 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3394 :
3395 5576 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3396 5576 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3397 : }
3398 :
3399 : /************************************************************************/
3400 : /* GetRasterSampleOverview() */
3401 : /************************************************************************/
3402 :
3403 : /**
3404 : * \brief Fetch best sampling overview.
3405 : *
3406 : * Returns the most reduced overview of the given band that still satisfies
3407 : * the desired number of samples. This function can be used with zero
3408 : * as the number of desired samples to fetch the most reduced overview.
3409 : * The same band as was passed in will be returned if it has not overviews,
3410 : * or if none of the overviews have enough samples.
3411 : *
3412 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3413 : * and GDALGetRasterSampleOverviewEx().
3414 : *
3415 : * @param nDesiredSamples the returned band will have at least this many
3416 : * pixels.
3417 : *
3418 : * @return optimal overview or the band itself.
3419 : */
3420 :
3421 : GDALRasterBand *
3422 2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3423 :
3424 : {
3425 2006 : GDALRasterBand *poBestBand = this;
3426 :
3427 2006 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3428 :
3429 4023 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3430 : {
3431 2017 : GDALRasterBand *poOBand = GetOverview(iOverview);
3432 :
3433 2017 : if (poOBand == nullptr)
3434 0 : continue;
3435 :
3436 : const double dfOSamples =
3437 2017 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3438 :
3439 2017 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3440 : {
3441 2014 : dfBestSamples = dfOSamples;
3442 2014 : poBestBand = poOBand;
3443 : }
3444 : }
3445 :
3446 2006 : return poBestBand;
3447 : }
3448 :
3449 : /************************************************************************/
3450 : /* GDALGetRasterSampleOverview() */
3451 : /************************************************************************/
3452 :
3453 : /**
3454 : * \brief Fetch best sampling overview.
3455 : *
3456 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3457 : * billion samples.
3458 : *
3459 : * @see GDALRasterBand::GetRasterSampleOverview()
3460 : * @see GDALGetRasterSampleOverviewEx()
3461 : */
3462 :
3463 2000 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3464 : int nDesiredSamples)
3465 :
3466 : {
3467 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3468 :
3469 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3470 2000 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3471 4000 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3472 : }
3473 :
3474 : /************************************************************************/
3475 : /* GDALGetRasterSampleOverviewEx() */
3476 : /************************************************************************/
3477 :
3478 : /**
3479 : * \brief Fetch best sampling overview.
3480 : *
3481 : * @see GDALRasterBand::GetRasterSampleOverview()
3482 : * @since GDAL 2.0
3483 : */
3484 :
3485 : GDALRasterBandH CPL_STDCALL
3486 0 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3487 :
3488 : {
3489 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3490 :
3491 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3492 0 : return GDALRasterBand::ToHandle(
3493 0 : poBand->GetRasterSampleOverview(nDesiredSamples));
3494 : }
3495 :
3496 : /************************************************************************/
3497 : /* BuildOverviews() */
3498 : /************************************************************************/
3499 :
3500 : /**
3501 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3502 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3503 : *
3504 : * If the operation is unsupported for the indicated dataset, then
3505 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3506 : * CPLE_NotSupported.
3507 : *
3508 : * WARNING: Most formats don't support per-band overview computation, but
3509 : * require that overviews are computed for all bands of a dataset, using
3510 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3511 : * is the HFA driver which supports this method.
3512 : *
3513 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3514 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3515 : * applied.
3516 : * @param nOverviews number of overviews to build.
3517 : * @param panOverviewList the list of overview decimation factors to build.
3518 : * @param pfnProgress a function to call to report progress, or NULL.
3519 : * @param pProgressData application data to pass to the progress function.
3520 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3521 : * key=value pairs, or NULL
3522 : *
3523 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3524 : */
3525 :
3526 : /**/
3527 : /**/
3528 :
3529 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3530 : int /*nOverviews*/,
3531 : const int * /*panOverviewList*/,
3532 : GDALProgressFunc /*pfnProgress*/,
3533 : void * /*pProgressData*/,
3534 : CSLConstList /* papszOptions */)
3535 :
3536 : {
3537 0 : ReportError(CE_Failure, CPLE_NotSupported,
3538 : "BuildOverviews() not supported for this dataset.");
3539 :
3540 0 : return (CE_Failure);
3541 : }
3542 :
3543 : /************************************************************************/
3544 : /* GetOffset() */
3545 : /************************************************************************/
3546 :
3547 : /**
3548 : * \brief Fetch the raster value offset.
3549 : *
3550 : * This value (in combination with the GetScale() value) can be used to
3551 : * transform raw pixel values into the units returned by GetUnitType().
3552 : * For example this might be used to store elevations in GUInt16 bands
3553 : * with a precision of 0.1, and starting from -100.
3554 : *
3555 : * Units value = (raw value * scale) + offset
3556 : *
3557 : * Note that applying scale and offset is of the responsibility of the user,
3558 : * and is not done by methods such as RasterIO() or ReadBlock().
3559 : *
3560 : * For file formats that don't know this intrinsically a value of zero
3561 : * is returned.
3562 : *
3563 : * This method is the same as the C function GDALGetRasterOffset().
3564 : *
3565 : * @param pbSuccess pointer to a boolean to use to indicate if the
3566 : * returned value is meaningful or not. May be NULL (default).
3567 : *
3568 : * @return the raster offset.
3569 : */
3570 :
3571 431 : double GDALRasterBand::GetOffset(int *pbSuccess)
3572 :
3573 : {
3574 431 : if (pbSuccess != nullptr)
3575 351 : *pbSuccess = FALSE;
3576 :
3577 431 : return 0.0;
3578 : }
3579 :
3580 : /************************************************************************/
3581 : /* GDALGetRasterOffset() */
3582 : /************************************************************************/
3583 :
3584 : /**
3585 : * \brief Fetch the raster value offset.
3586 : *
3587 : * @see GDALRasterBand::GetOffset()
3588 : */
3589 :
3590 350 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3591 :
3592 : {
3593 350 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3594 :
3595 350 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3596 350 : return poBand->GetOffset(pbSuccess);
3597 : }
3598 :
3599 : /************************************************************************/
3600 : /* SetOffset() */
3601 : /************************************************************************/
3602 :
3603 : /**
3604 : * \fn GDALRasterBand::SetOffset(double)
3605 : * \brief Set scaling offset.
3606 : *
3607 : * Very few formats implement this method. When not implemented it will
3608 : * issue a CPLE_NotSupported error and return CE_Failure.
3609 : *
3610 : * This method is the same as the C function GDALSetRasterOffset().
3611 : *
3612 : * @param dfNewOffset the new offset.
3613 : *
3614 : * @return CE_None or success or CE_Failure on failure.
3615 : */
3616 :
3617 : /**/
3618 : /**/
3619 :
3620 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3621 : {
3622 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3623 0 : ReportError(CE_Failure, CPLE_NotSupported,
3624 : "SetOffset() not supported on this raster band.");
3625 :
3626 0 : return CE_Failure;
3627 : }
3628 :
3629 : /************************************************************************/
3630 : /* GDALSetRasterOffset() */
3631 : /************************************************************************/
3632 :
3633 : /**
3634 : * \brief Set scaling offset.
3635 : *
3636 : * @see GDALRasterBand::SetOffset()
3637 : */
3638 :
3639 73 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3640 : double dfNewOffset)
3641 :
3642 : {
3643 73 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3644 :
3645 73 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3646 73 : return poBand->SetOffset(dfNewOffset);
3647 : }
3648 :
3649 : /************************************************************************/
3650 : /* GetScale() */
3651 : /************************************************************************/
3652 :
3653 : /**
3654 : * \brief Fetch the raster value scale.
3655 : *
3656 : * This value (in combination with the GetOffset() value) can be used to
3657 : * transform raw pixel values into the units returned by GetUnitType().
3658 : * For example this might be used to store elevations in GUInt16 bands
3659 : * with a precision of 0.1, and starting from -100.
3660 : *
3661 : * Units value = (raw value * scale) + offset
3662 : *
3663 : * Note that applying scale and offset is of the responsibility of the user,
3664 : * and is not done by methods such as RasterIO() or ReadBlock().
3665 : *
3666 : * For file formats that don't know this intrinsically a value of one
3667 : * is returned.
3668 : *
3669 : * This method is the same as the C function GDALGetRasterScale().
3670 : *
3671 : * @param pbSuccess pointer to a boolean to use to indicate if the
3672 : * returned value is meaningful or not. May be NULL (default).
3673 : *
3674 : * @return the raster scale.
3675 : */
3676 :
3677 431 : double GDALRasterBand::GetScale(int *pbSuccess)
3678 :
3679 : {
3680 431 : if (pbSuccess != nullptr)
3681 351 : *pbSuccess = FALSE;
3682 :
3683 431 : return 1.0;
3684 : }
3685 :
3686 : /************************************************************************/
3687 : /* GDALGetRasterScale() */
3688 : /************************************************************************/
3689 :
3690 : /**
3691 : * \brief Fetch the raster value scale.
3692 : *
3693 : * @see GDALRasterBand::GetScale()
3694 : */
3695 :
3696 348 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3697 :
3698 : {
3699 348 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3700 :
3701 348 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3702 348 : return poBand->GetScale(pbSuccess);
3703 : }
3704 :
3705 : /************************************************************************/
3706 : /* SetScale() */
3707 : /************************************************************************/
3708 :
3709 : /**
3710 : * \fn GDALRasterBand::SetScale(double)
3711 : * \brief Set scaling ratio.
3712 : *
3713 : * Very few formats implement this method. When not implemented it will
3714 : * issue a CPLE_NotSupported error and return CE_Failure.
3715 : *
3716 : * This method is the same as the C function GDALSetRasterScale().
3717 : *
3718 : * @param dfNewScale the new scale.
3719 : *
3720 : * @return CE_None or success or CE_Failure on failure.
3721 : */
3722 :
3723 : /**/
3724 : /**/
3725 :
3726 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3727 :
3728 : {
3729 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3730 0 : ReportError(CE_Failure, CPLE_NotSupported,
3731 : "SetScale() not supported on this raster band.");
3732 :
3733 0 : return CE_Failure;
3734 : }
3735 :
3736 : /************************************************************************/
3737 : /* GDALSetRasterScale() */
3738 : /************************************************************************/
3739 :
3740 : /**
3741 : * \brief Set scaling ratio.
3742 : *
3743 : * @see GDALRasterBand::SetScale()
3744 : */
3745 :
3746 74 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3747 :
3748 : {
3749 74 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3750 :
3751 74 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3752 74 : return poBand->SetScale(dfNewOffset);
3753 : }
3754 :
3755 : /************************************************************************/
3756 : /* GetUnitType() */
3757 : /************************************************************************/
3758 :
3759 : /**
3760 : * \brief Return raster unit type.
3761 : *
3762 : * Return a name for the units of this raster's values. For instance, it
3763 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3764 : * units are available, a value of "" will be returned. The returned string
3765 : * should not be modified, nor freed by the calling application.
3766 : *
3767 : * This method is the same as the C function GDALGetRasterUnitType().
3768 : *
3769 : * @return unit name string.
3770 : */
3771 :
3772 167 : const char *GDALRasterBand::GetUnitType()
3773 :
3774 : {
3775 167 : return "";
3776 : }
3777 :
3778 : /************************************************************************/
3779 : /* GDALGetRasterUnitType() */
3780 : /************************************************************************/
3781 :
3782 : /**
3783 : * \brief Return raster unit type.
3784 : *
3785 : * @see GDALRasterBand::GetUnitType()
3786 : */
3787 :
3788 1391 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3789 :
3790 : {
3791 1391 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3792 :
3793 1391 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3794 1391 : return poBand->GetUnitType();
3795 : }
3796 :
3797 : /************************************************************************/
3798 : /* SetUnitType() */
3799 : /************************************************************************/
3800 :
3801 : /**
3802 : * \fn GDALRasterBand::SetUnitType(const char*)
3803 : * \brief Set unit type.
3804 : *
3805 : * Set the unit type for a raster band. Values should be one of
3806 : * "" (the default indicating it is unknown), "m" indicating meters,
3807 : * or "ft" indicating feet, though other nonstandard values are allowed.
3808 : *
3809 : * This method is the same as the C function GDALSetRasterUnitType().
3810 : *
3811 : * @param pszNewValue the new unit type value.
3812 : *
3813 : * @return CE_None on success or CE_Failure if not successful, or
3814 : * unsupported.
3815 : */
3816 :
3817 : /**/
3818 : /**/
3819 :
3820 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3821 :
3822 : {
3823 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3824 0 : ReportError(CE_Failure, CPLE_NotSupported,
3825 : "SetUnitType() not supported on this raster band.");
3826 0 : return CE_Failure;
3827 : }
3828 :
3829 : /************************************************************************/
3830 : /* GDALSetRasterUnitType() */
3831 : /************************************************************************/
3832 :
3833 : /**
3834 : * \brief Set unit type.
3835 : *
3836 : * @see GDALRasterBand::SetUnitType()
3837 : *
3838 : * @since GDAL 1.8.0
3839 : */
3840 :
3841 88 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3842 : const char *pszNewValue)
3843 :
3844 : {
3845 88 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3846 :
3847 88 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3848 88 : return poBand->SetUnitType(pszNewValue);
3849 : }
3850 :
3851 : /************************************************************************/
3852 : /* GetXSize() */
3853 : /************************************************************************/
3854 :
3855 : /**
3856 : * \brief Fetch XSize of raster.
3857 : *
3858 : * This method is the same as the C function GDALGetRasterBandXSize().
3859 : *
3860 : * @return the width in pixels of this band.
3861 : */
3862 :
3863 6759120 : int GDALRasterBand::GetXSize() const
3864 :
3865 : {
3866 6759120 : return nRasterXSize;
3867 : }
3868 :
3869 : /************************************************************************/
3870 : /* GDALGetRasterBandXSize() */
3871 : /************************************************************************/
3872 :
3873 : /**
3874 : * \brief Fetch XSize of raster.
3875 : *
3876 : * @see GDALRasterBand::GetXSize()
3877 : */
3878 :
3879 54594 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3880 :
3881 : {
3882 54594 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3883 :
3884 54594 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3885 54594 : return poBand->GetXSize();
3886 : }
3887 :
3888 : /************************************************************************/
3889 : /* GetYSize() */
3890 : /************************************************************************/
3891 :
3892 : /**
3893 : * \brief Fetch YSize of raster.
3894 : *
3895 : * This method is the same as the C function GDALGetRasterBandYSize().
3896 : *
3897 : * @return the height in pixels of this band.
3898 : */
3899 :
3900 3187340 : int GDALRasterBand::GetYSize() const
3901 :
3902 : {
3903 3187340 : return nRasterYSize;
3904 : }
3905 :
3906 : /************************************************************************/
3907 : /* GDALGetRasterBandYSize() */
3908 : /************************************************************************/
3909 :
3910 : /**
3911 : * \brief Fetch YSize of raster.
3912 : *
3913 : * @see GDALRasterBand::GetYSize()
3914 : */
3915 :
3916 53959 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3917 :
3918 : {
3919 53959 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3920 :
3921 53959 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3922 53959 : return poBand->GetYSize();
3923 : }
3924 :
3925 : /************************************************************************/
3926 : /* GetBand() */
3927 : /************************************************************************/
3928 :
3929 : /**
3930 : * \brief Fetch the band number.
3931 : *
3932 : * This method returns the band that this GDALRasterBand objects represents
3933 : * within its dataset. This method may return a value of 0 to indicate
3934 : * GDALRasterBand objects without an apparently relationship to a dataset,
3935 : * such as GDALRasterBands serving as overviews.
3936 : *
3937 : * This method is the same as the C function GDALGetBandNumber().
3938 : *
3939 : * @return band number (1+) or 0 if the band number isn't known.
3940 : */
3941 :
3942 18866 : int GDALRasterBand::GetBand() const
3943 :
3944 : {
3945 18866 : return nBand;
3946 : }
3947 :
3948 : /************************************************************************/
3949 : /* GDALGetBandNumber() */
3950 : /************************************************************************/
3951 :
3952 : /**
3953 : * \brief Fetch the band number.
3954 : *
3955 : * @see GDALRasterBand::GetBand()
3956 : */
3957 :
3958 178 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3959 :
3960 : {
3961 178 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3962 :
3963 178 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3964 178 : return poBand->GetBand();
3965 : }
3966 :
3967 : /************************************************************************/
3968 : /* GetDataset() */
3969 : /************************************************************************/
3970 :
3971 : /**
3972 : * \brief Fetch the owning dataset handle.
3973 : *
3974 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3975 : * such as overviews or other "freestanding" bands.
3976 : *
3977 : * This method is the same as the C function GDALGetBandDataset().
3978 : *
3979 : * @return the pointer to the GDALDataset to which this band belongs, or
3980 : * NULL if this cannot be determined.
3981 : */
3982 :
3983 3859010 : GDALDataset *GDALRasterBand::GetDataset() const
3984 :
3985 : {
3986 3859010 : return poDS;
3987 : }
3988 :
3989 : /************************************************************************/
3990 : /* GDALGetBandDataset() */
3991 : /************************************************************************/
3992 :
3993 : /**
3994 : * \brief Fetch the owning dataset handle.
3995 : *
3996 : * @see GDALRasterBand::GetDataset()
3997 : */
3998 :
3999 379 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4000 :
4001 : {
4002 379 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4003 :
4004 379 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4005 379 : return GDALDataset::ToHandle(poBand->GetDataset());
4006 : }
4007 :
4008 : /************************************************************************/
4009 : /* ComputeFloat16NoDataValue() */
4010 : /************************************************************************/
4011 :
4012 2032 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4013 : double dfNoDataValue,
4014 : int &bGotNoDataValue,
4015 : GFloat16 &fNoDataValue,
4016 : bool &bGotFloat16NoDataValue)
4017 : {
4018 2032 : if (eDataType == GDT_Float16 && bGotNoDataValue)
4019 : {
4020 0 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4021 0 : if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4022 : {
4023 0 : fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4024 0 : bGotFloat16NoDataValue = true;
4025 0 : bGotNoDataValue = false;
4026 : }
4027 : }
4028 2032 : }
4029 :
4030 : /************************************************************************/
4031 : /* ComputeFloatNoDataValue() */
4032 : /************************************************************************/
4033 :
4034 2032 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4035 : double dfNoDataValue,
4036 : int &bGotNoDataValue,
4037 : float &fNoDataValue,
4038 : bool &bGotFloatNoDataValue)
4039 : {
4040 2032 : if (eDataType == GDT_Float32 && bGotNoDataValue)
4041 : {
4042 72 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4043 72 : if (GDALIsValueInRange<float>(dfNoDataValue))
4044 : {
4045 72 : fNoDataValue = static_cast<float>(dfNoDataValue);
4046 72 : bGotFloatNoDataValue = true;
4047 72 : bGotNoDataValue = false;
4048 : }
4049 : }
4050 2032 : }
4051 :
4052 : /************************************************************************/
4053 : /* struct GDALNoDataValues */
4054 : /************************************************************************/
4055 :
4056 : /**
4057 : * \brief No-data-values for all types
4058 : *
4059 : * The functions below pass various no-data-values around. To avoid
4060 : * long argument lists, this struct collects the no-data-values for
4061 : * all types into a single, convenient place.
4062 : **/
4063 :
4064 : struct GDALNoDataValues
4065 : {
4066 : int bGotNoDataValue;
4067 : double dfNoDataValue;
4068 :
4069 : bool bGotFloatNoDataValue;
4070 : float fNoDataValue;
4071 :
4072 : bool bGotFloat16NoDataValue;
4073 : GFloat16 hfNoDataValue;
4074 :
4075 2032 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4076 2032 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4077 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4078 2032 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4079 : {
4080 2032 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4081 2032 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4082 :
4083 2032 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4084 2032 : fNoDataValue, bGotFloatNoDataValue);
4085 :
4086 2032 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4087 2032 : hfNoDataValue, bGotFloat16NoDataValue);
4088 2032 : }
4089 : };
4090 :
4091 : /************************************************************************/
4092 : /* GetHistogram() */
4093 : /************************************************************************/
4094 :
4095 : /**
4096 : * \brief Compute raster histogram.
4097 : *
4098 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4099 : *
4100 : * For example to compute a simple 256 entry histogram of eight bit data,
4101 : * the following would be suitable. The unusual bounds are to ensure that
4102 : * bucket boundaries don't fall right on integer values causing possible errors
4103 : * due to rounding after scaling.
4104 : \code{.cpp}
4105 : GUIntBig anHistogram[256];
4106 :
4107 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4108 : GDALDummyProgress, nullptr );
4109 : \endcode
4110 : *
4111 : * Note that setting bApproxOK will generally result in a subsampling of the
4112 : * file, and will utilize overviews if available. It should generally
4113 : * produce a representative histogram for the data that is suitable for use
4114 : * in generating histogram based luts for instance. Generally bApproxOK is
4115 : * much faster than an exactly computed histogram.
4116 : *
4117 : * This method is the same as the C functions GDALGetRasterHistogram() and
4118 : * GDALGetRasterHistogramEx().
4119 : *
4120 : * @param dfMin the lower bound of the histogram.
4121 : * @param dfMax the upper bound of the histogram.
4122 : * @param nBuckets the number of buckets in panHistogram.
4123 : * @param panHistogram array into which the histogram totals are placed.
4124 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4125 : * mapped into panHistogram[0], and values above will be mapped into
4126 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4127 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4128 : * @param pfnProgress function to report progress to completion.
4129 : * @param pProgressData application data to pass to pfnProgress.
4130 : *
4131 : * @return CE_None on success, or CE_Failure if something goes wrong.
4132 : */
4133 :
4134 40 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4135 : GUIntBig *panHistogram,
4136 : int bIncludeOutOfRange, int bApproxOK,
4137 : GDALProgressFunc pfnProgress,
4138 : void *pProgressData)
4139 :
4140 : {
4141 40 : CPLAssert(nullptr != panHistogram);
4142 :
4143 40 : if (pfnProgress == nullptr)
4144 26 : pfnProgress = GDALDummyProgress;
4145 :
4146 : /* -------------------------------------------------------------------- */
4147 : /* If we have overviews, use them for the histogram. */
4148 : /* -------------------------------------------------------------------- */
4149 40 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4150 : {
4151 : // FIXME: should we use the most reduced overview here or use some
4152 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4153 : // does?
4154 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4155 :
4156 0 : if (poBestOverview != this)
4157 : {
4158 0 : return poBestOverview->GetHistogram(
4159 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4160 0 : bApproxOK, pfnProgress, pProgressData);
4161 : }
4162 : }
4163 :
4164 : /* -------------------------------------------------------------------- */
4165 : /* Read actual data and build histogram. */
4166 : /* -------------------------------------------------------------------- */
4167 40 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4168 : {
4169 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4170 0 : return CE_Failure;
4171 : }
4172 :
4173 : // Written this way to deal with NaN
4174 40 : if (!(dfMax > dfMin))
4175 : {
4176 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4177 : "dfMax should be strictly greater than dfMin");
4178 5 : return CE_Failure;
4179 : }
4180 :
4181 : GDALRasterIOExtraArg sExtraArg;
4182 35 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4183 :
4184 35 : const double dfScale = nBuckets / (dfMax - dfMin);
4185 35 : if (dfScale == 0 || !std::isfinite(dfScale))
4186 : {
4187 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4188 : "dfMin and dfMax should be finite values such that "
4189 : "nBuckets / (dfMax - dfMin) is non-zero");
4190 5 : return CE_Failure;
4191 : }
4192 30 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4193 :
4194 30 : GDALNoDataValues sNoDataValues(this, eDataType);
4195 30 : GDALRasterBand *poMaskBand = nullptr;
4196 30 : if (!sNoDataValues.bGotNoDataValue)
4197 : {
4198 29 : const int l_nMaskFlags = GetMaskFlags();
4199 30 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
4200 1 : GetColorInterpretation() != GCI_AlphaBand)
4201 : {
4202 1 : poMaskBand = GetMaskBand();
4203 : }
4204 : }
4205 :
4206 30 : bool bSignedByte = false;
4207 30 : if (eDataType == GDT_Byte)
4208 : {
4209 23 : EnablePixelTypeSignedByteWarning(false);
4210 : const char *pszPixelType =
4211 23 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4212 23 : EnablePixelTypeSignedByteWarning(true);
4213 23 : bSignedByte =
4214 23 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4215 : }
4216 :
4217 30 : if (bApproxOK && HasArbitraryOverviews())
4218 : {
4219 : /* --------------------------------------------------------------------
4220 : */
4221 : /* Figure out how much the image should be reduced to get an */
4222 : /* approximate value. */
4223 : /* --------------------------------------------------------------------
4224 : */
4225 : const double dfReduction =
4226 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4227 : GDALSTAT_APPROX_NUMSAMPLES);
4228 :
4229 0 : int nXReduced = nRasterXSize;
4230 0 : int nYReduced = nRasterYSize;
4231 0 : if (dfReduction > 1.0)
4232 : {
4233 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4234 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4235 :
4236 : // Catch the case of huge resizing ratios here
4237 0 : if (nXReduced == 0)
4238 0 : nXReduced = 1;
4239 0 : if (nYReduced == 0)
4240 0 : nYReduced = 1;
4241 : }
4242 :
4243 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4244 : nXReduced, nYReduced);
4245 0 : if (!pData)
4246 0 : return CE_Failure;
4247 :
4248 : const CPLErr eErr =
4249 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4250 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4251 0 : if (eErr != CE_None)
4252 : {
4253 0 : CPLFree(pData);
4254 0 : return eErr;
4255 : }
4256 :
4257 0 : GByte *pabyMaskData = nullptr;
4258 0 : if (poMaskBand)
4259 : {
4260 : pabyMaskData =
4261 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4262 0 : if (!pabyMaskData)
4263 : {
4264 0 : CPLFree(pData);
4265 0 : return CE_Failure;
4266 : }
4267 :
4268 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4269 : pabyMaskData, nXReduced, nYReduced,
4270 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
4271 : {
4272 0 : CPLFree(pData);
4273 0 : CPLFree(pabyMaskData);
4274 0 : return CE_Failure;
4275 : }
4276 : }
4277 :
4278 : // This isn't the fastest way to do this, but is easier for now.
4279 0 : for (int iY = 0; iY < nYReduced; iY++)
4280 : {
4281 0 : for (int iX = 0; iX < nXReduced; iX++)
4282 : {
4283 0 : const int iOffset = iX + iY * nXReduced;
4284 0 : double dfValue = 0.0;
4285 :
4286 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4287 0 : continue;
4288 :
4289 0 : switch (eDataType)
4290 : {
4291 0 : case GDT_Byte:
4292 : {
4293 0 : if (bSignedByte)
4294 0 : dfValue =
4295 0 : static_cast<signed char *>(pData)[iOffset];
4296 : else
4297 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4298 0 : break;
4299 : }
4300 0 : case GDT_Int8:
4301 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4302 0 : break;
4303 0 : case GDT_UInt16:
4304 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4305 0 : break;
4306 0 : case GDT_Int16:
4307 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4308 0 : break;
4309 0 : case GDT_UInt32:
4310 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4311 0 : break;
4312 0 : case GDT_Int32:
4313 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4314 0 : break;
4315 0 : case GDT_UInt64:
4316 0 : dfValue = static_cast<double>(
4317 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4318 0 : break;
4319 0 : case GDT_Int64:
4320 0 : dfValue = static_cast<double>(
4321 0 : static_cast<GInt64 *>(pData)[iOffset]);
4322 0 : break;
4323 0 : case GDT_Float16:
4324 : {
4325 : using namespace std;
4326 0 : const GFloat16 hfValue =
4327 0 : static_cast<GFloat16 *>(pData)[iOffset];
4328 0 : if (isnan(hfValue) ||
4329 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4330 0 : ARE_REAL_EQUAL(hfValue,
4331 : sNoDataValues.hfNoDataValue)))
4332 0 : continue;
4333 0 : dfValue = hfValue;
4334 0 : break;
4335 : }
4336 0 : case GDT_Float32:
4337 : {
4338 0 : const float fValue =
4339 0 : static_cast<float *>(pData)[iOffset];
4340 0 : if (std::isnan(fValue) ||
4341 0 : (sNoDataValues.bGotFloatNoDataValue &&
4342 0 : ARE_REAL_EQUAL(fValue,
4343 : sNoDataValues.fNoDataValue)))
4344 0 : continue;
4345 0 : dfValue = fValue;
4346 0 : break;
4347 : }
4348 0 : case GDT_Float64:
4349 0 : dfValue = static_cast<double *>(pData)[iOffset];
4350 0 : if (std::isnan(dfValue))
4351 0 : continue;
4352 0 : break;
4353 0 : case GDT_CInt16:
4354 : {
4355 0 : const double dfReal =
4356 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4357 0 : const double dfImag =
4358 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4359 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4360 0 : continue;
4361 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4362 : }
4363 0 : break;
4364 0 : case GDT_CInt32:
4365 : {
4366 0 : const double dfReal =
4367 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4368 0 : const double dfImag =
4369 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4370 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4371 0 : continue;
4372 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4373 : }
4374 0 : break;
4375 0 : case GDT_CFloat16:
4376 : {
4377 : const double dfReal =
4378 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4379 : const double dfImag =
4380 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4381 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4382 0 : continue;
4383 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4384 0 : break;
4385 : }
4386 0 : case GDT_CFloat32:
4387 : {
4388 0 : const double dfReal =
4389 0 : static_cast<float *>(pData)[iOffset * 2];
4390 0 : const double dfImag =
4391 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
4392 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4393 0 : continue;
4394 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4395 0 : break;
4396 : }
4397 0 : case GDT_CFloat64:
4398 : {
4399 0 : const double dfReal =
4400 0 : static_cast<double *>(pData)[iOffset * 2];
4401 0 : const double dfImag =
4402 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4403 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4404 0 : continue;
4405 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4406 0 : break;
4407 : }
4408 0 : case GDT_Unknown:
4409 : case GDT_TypeCount:
4410 0 : CPLAssert(false);
4411 : }
4412 :
4413 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4414 0 : sNoDataValues.bGotNoDataValue &&
4415 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4416 0 : continue;
4417 :
4418 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4419 : // finite, the result of the multiplication cannot be NaN
4420 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4421 :
4422 0 : if (dfIndex < 0)
4423 : {
4424 0 : if (bIncludeOutOfRange)
4425 0 : panHistogram[0]++;
4426 : }
4427 0 : else if (dfIndex >= nBuckets)
4428 : {
4429 0 : if (bIncludeOutOfRange)
4430 0 : ++panHistogram[nBuckets - 1];
4431 : }
4432 : else
4433 : {
4434 0 : ++panHistogram[static_cast<int>(dfIndex)];
4435 : }
4436 : }
4437 : }
4438 :
4439 0 : CPLFree(pData);
4440 0 : CPLFree(pabyMaskData);
4441 : }
4442 : else // No arbitrary overviews.
4443 : {
4444 30 : if (!InitBlockInfo())
4445 0 : return CE_Failure;
4446 :
4447 : /* --------------------------------------------------------------------
4448 : */
4449 : /* Figure out the ratio of blocks we will read to get an */
4450 : /* approximate value. */
4451 : /* --------------------------------------------------------------------
4452 : */
4453 :
4454 30 : int nSampleRate = 1;
4455 30 : if (bApproxOK)
4456 : {
4457 8 : nSampleRate = static_cast<int>(std::max(
4458 16 : 1.0,
4459 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4460 : // We want to avoid probing only the first column of blocks for
4461 : // a square shaped raster, because it is not unlikely that it may
4462 : // be padding only (#6378).
4463 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4464 1 : nSampleRate += 1;
4465 : }
4466 :
4467 30 : GByte *pabyMaskData = nullptr;
4468 30 : if (poMaskBand)
4469 : {
4470 : pabyMaskData = static_cast<GByte *>(
4471 1 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4472 1 : if (!pabyMaskData)
4473 : {
4474 0 : return CE_Failure;
4475 : }
4476 : }
4477 :
4478 : /* --------------------------------------------------------------------
4479 : */
4480 : /* Read the blocks, and add to histogram. */
4481 : /* --------------------------------------------------------------------
4482 : */
4483 30 : for (GIntBig iSampleBlock = 0;
4484 150 : iSampleBlock <
4485 150 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4486 120 : iSampleBlock += nSampleRate)
4487 : {
4488 120 : if (!pfnProgress(
4489 120 : static_cast<double>(iSampleBlock) /
4490 120 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4491 : "Compute Histogram", pProgressData))
4492 : {
4493 0 : CPLFree(pabyMaskData);
4494 0 : return CE_Failure;
4495 : }
4496 :
4497 120 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4498 120 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4499 :
4500 120 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4501 120 : if (poBlock == nullptr)
4502 : {
4503 0 : CPLFree(pabyMaskData);
4504 0 : return CE_Failure;
4505 : }
4506 :
4507 120 : void *pData = poBlock->GetDataRef();
4508 :
4509 120 : int nXCheck = 0, nYCheck = 0;
4510 120 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4511 :
4512 121 : if (poMaskBand &&
4513 1 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4514 1 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4515 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4516 1 : 0, nBlockXSize, nullptr) != CE_None)
4517 : {
4518 0 : CPLFree(pabyMaskData);
4519 0 : poBlock->DropLock();
4520 0 : return CE_Failure;
4521 : }
4522 :
4523 : // this is a special case for a common situation.
4524 120 : if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4525 86 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4526 83 : nXCheck == nBlockXSize && nBuckets == 256)
4527 : {
4528 83 : const GPtrDiff_t nPixels =
4529 83 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4530 83 : GByte *pabyData = static_cast<GByte *>(pData);
4531 :
4532 72137 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4533 : {
4534 72054 : if (pabyMaskData && pabyMaskData[i] == 0)
4535 0 : continue;
4536 72054 : if (!(sNoDataValues.bGotNoDataValue &&
4537 512 : (pabyData[i] ==
4538 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4539 : {
4540 71798 : panHistogram[pabyData[i]]++;
4541 : }
4542 : }
4543 :
4544 83 : poBlock->DropLock();
4545 83 : continue; // To next sample block.
4546 : }
4547 :
4548 : // This isn't the fastest way to do this, but is easier for now.
4549 253 : for (int iY = 0; iY < nYCheck; iY++)
4550 : {
4551 36385 : for (int iX = 0; iX < nXCheck; iX++)
4552 : {
4553 36169 : const GPtrDiff_t iOffset =
4554 36169 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4555 :
4556 36169 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4557 1 : continue;
4558 :
4559 36168 : double dfValue = 0.0;
4560 :
4561 36168 : switch (eDataType)
4562 : {
4563 19716 : case GDT_Byte:
4564 : {
4565 19716 : if (bSignedByte)
4566 0 : dfValue =
4567 0 : static_cast<signed char *>(pData)[iOffset];
4568 : else
4569 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4570 19716 : break;
4571 : }
4572 0 : case GDT_Int8:
4573 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4574 0 : break;
4575 16384 : case GDT_UInt16:
4576 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4577 16384 : break;
4578 2 : case GDT_Int16:
4579 2 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4580 2 : break;
4581 0 : case GDT_UInt32:
4582 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4583 0 : break;
4584 60 : case GDT_Int32:
4585 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4586 60 : break;
4587 0 : case GDT_UInt64:
4588 0 : dfValue = static_cast<double>(
4589 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4590 0 : break;
4591 0 : case GDT_Int64:
4592 0 : dfValue = static_cast<double>(
4593 0 : static_cast<GInt64 *>(pData)[iOffset]);
4594 0 : break;
4595 0 : case GDT_Float16:
4596 : {
4597 : using namespace std;
4598 0 : const GFloat16 hfValue =
4599 0 : static_cast<GFloat16 *>(pData)[iOffset];
4600 0 : if (isnan(hfValue) ||
4601 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4602 0 : ARE_REAL_EQUAL(hfValue,
4603 : sNoDataValues.hfNoDataValue)))
4604 0 : continue;
4605 0 : dfValue = hfValue;
4606 0 : break;
4607 : }
4608 4 : case GDT_Float32:
4609 : {
4610 4 : const float fValue =
4611 4 : static_cast<float *>(pData)[iOffset];
4612 8 : if (std::isnan(fValue) ||
4613 8 : (sNoDataValues.bGotFloatNoDataValue &&
4614 4 : ARE_REAL_EQUAL(fValue,
4615 : sNoDataValues.fNoDataValue)))
4616 1 : continue;
4617 3 : dfValue = fValue;
4618 3 : break;
4619 : }
4620 2 : case GDT_Float64:
4621 2 : dfValue = static_cast<double *>(pData)[iOffset];
4622 2 : if (std::isnan(dfValue))
4623 0 : continue;
4624 2 : break;
4625 0 : case GDT_CInt16:
4626 : {
4627 0 : double dfReal =
4628 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4629 0 : double dfImag =
4630 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4631 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4632 0 : break;
4633 : }
4634 0 : case GDT_CInt32:
4635 : {
4636 0 : double dfReal =
4637 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4638 0 : double dfImag =
4639 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4640 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4641 0 : break;
4642 : }
4643 0 : case GDT_CFloat16:
4644 : {
4645 : double dfReal =
4646 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4647 : double dfImag =
4648 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4649 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4650 0 : continue;
4651 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4652 0 : break;
4653 : }
4654 0 : case GDT_CFloat32:
4655 : {
4656 0 : double dfReal =
4657 0 : static_cast<float *>(pData)[iOffset * 2];
4658 0 : double dfImag =
4659 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
4660 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4661 0 : continue;
4662 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4663 0 : break;
4664 : }
4665 0 : case GDT_CFloat64:
4666 : {
4667 0 : double dfReal =
4668 0 : static_cast<double *>(pData)[iOffset * 2];
4669 0 : double dfImag =
4670 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4671 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4672 0 : continue;
4673 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4674 0 : break;
4675 : }
4676 0 : case GDT_Unknown:
4677 : case GDT_TypeCount:
4678 0 : CPLAssert(false);
4679 : CPLFree(pabyMaskData);
4680 : return CE_Failure;
4681 : }
4682 :
4683 36167 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4684 72334 : sNoDataValues.bGotNoDataValue &&
4685 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4686 0 : continue;
4687 :
4688 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4689 : // and finite, the result of the multiplication cannot be
4690 : // NaN
4691 36167 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4692 :
4693 36167 : if (dfIndex < 0)
4694 : {
4695 1 : if (bIncludeOutOfRange)
4696 1 : panHistogram[0]++;
4697 : }
4698 36166 : else if (dfIndex >= nBuckets)
4699 : {
4700 7 : if (bIncludeOutOfRange)
4701 4 : ++panHistogram[nBuckets - 1];
4702 : }
4703 : else
4704 : {
4705 36159 : ++panHistogram[static_cast<int>(dfIndex)];
4706 : }
4707 : }
4708 : }
4709 :
4710 37 : poBlock->DropLock();
4711 : }
4712 :
4713 30 : CPLFree(pabyMaskData);
4714 : }
4715 :
4716 30 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4717 :
4718 30 : return CE_None;
4719 : }
4720 :
4721 : /************************************************************************/
4722 : /* GDALGetRasterHistogram() */
4723 : /************************************************************************/
4724 :
4725 : /**
4726 : * \brief Compute raster histogram.
4727 : *
4728 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4729 : * exceeding 2 billion.
4730 : *
4731 : * @see GDALRasterBand::GetHistogram()
4732 : * @see GDALGetRasterHistogramEx()
4733 : */
4734 :
4735 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4736 : double dfMax, int nBuckets,
4737 : int *panHistogram,
4738 : int bIncludeOutOfRange, int bApproxOK,
4739 : GDALProgressFunc pfnProgress,
4740 : void *pProgressData)
4741 :
4742 : {
4743 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4744 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4745 :
4746 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4747 :
4748 : GUIntBig *panHistogramTemp =
4749 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4750 0 : if (panHistogramTemp == nullptr)
4751 : {
4752 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4753 : "Out of memory in GDALGetRasterHistogram().");
4754 0 : return CE_Failure;
4755 : }
4756 :
4757 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4758 : bIncludeOutOfRange, bApproxOK,
4759 0 : pfnProgress, pProgressData);
4760 :
4761 0 : if (eErr == CE_None)
4762 : {
4763 0 : for (int i = 0; i < nBuckets; i++)
4764 : {
4765 0 : if (panHistogramTemp[i] > INT_MAX)
4766 : {
4767 0 : CPLError(CE_Warning, CPLE_AppDefined,
4768 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4769 : " exceeds maximum 32 bit value",
4770 0 : i, panHistogramTemp[i]);
4771 0 : panHistogram[i] = INT_MAX;
4772 : }
4773 : else
4774 : {
4775 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4776 : }
4777 : }
4778 : }
4779 :
4780 0 : CPLFree(panHistogramTemp);
4781 :
4782 0 : return eErr;
4783 : }
4784 :
4785 : /************************************************************************/
4786 : /* GDALGetRasterHistogramEx() */
4787 : /************************************************************************/
4788 :
4789 : /**
4790 : * \brief Compute raster histogram.
4791 : *
4792 : * @see GDALRasterBand::GetHistogram()
4793 : *
4794 : * @since GDAL 2.0
4795 : */
4796 :
4797 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4798 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4799 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4800 : GDALProgressFunc pfnProgress, void *pProgressData)
4801 :
4802 : {
4803 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4804 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4805 :
4806 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4807 :
4808 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4809 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4810 26 : pProgressData);
4811 : }
4812 :
4813 : /************************************************************************/
4814 : /* GetDefaultHistogram() */
4815 : /************************************************************************/
4816 :
4817 : /**
4818 : * \brief Fetch default raster histogram.
4819 : *
4820 : * The default method in GDALRasterBand will compute a default histogram. This
4821 : * method is overridden by derived classes (such as GDALPamRasterBand,
4822 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4823 : * stored histogram.
4824 : *
4825 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4826 : * GDALGetDefaultHistogramEx().
4827 : *
4828 : * @param pdfMin pointer to double value that will contain the lower bound of
4829 : * the histogram.
4830 : * @param pdfMax pointer to double value that will contain the upper bound of
4831 : * the histogram.
4832 : * @param pnBuckets pointer to int value that will contain the number of buckets
4833 : * in *ppanHistogram.
4834 : * @param ppanHistogram pointer to array into which the histogram totals are
4835 : * placed. To be freed with VSIFree
4836 : * @param bForce TRUE to force the computation. If FALSE and no default
4837 : * histogram is available, the method will return CE_Warning
4838 : * @param pfnProgress function to report progress to completion.
4839 : * @param pProgressData application data to pass to pfnProgress.
4840 : *
4841 : * @return CE_None on success, CE_Failure if something goes wrong, or
4842 : * CE_Warning if no default histogram is available.
4843 : */
4844 :
4845 23 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4846 : int *pnBuckets,
4847 : GUIntBig **ppanHistogram, int bForce,
4848 : GDALProgressFunc pfnProgress,
4849 : void *pProgressData)
4850 :
4851 : {
4852 23 : CPLAssert(nullptr != pnBuckets);
4853 23 : CPLAssert(nullptr != ppanHistogram);
4854 23 : CPLAssert(nullptr != pdfMin);
4855 23 : CPLAssert(nullptr != pdfMax);
4856 :
4857 23 : *pnBuckets = 0;
4858 23 : *ppanHistogram = nullptr;
4859 :
4860 23 : if (!bForce)
4861 6 : return CE_Warning;
4862 :
4863 17 : const int nBuckets = 256;
4864 :
4865 17 : bool bSignedByte = false;
4866 17 : if (eDataType == GDT_Byte)
4867 : {
4868 17 : EnablePixelTypeSignedByteWarning(false);
4869 : const char *pszPixelType =
4870 17 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4871 17 : EnablePixelTypeSignedByteWarning(true);
4872 17 : bSignedByte =
4873 17 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4874 : }
4875 :
4876 17 : if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4877 : {
4878 17 : *pdfMin = -0.5;
4879 17 : *pdfMax = 255.5;
4880 : }
4881 : else
4882 : {
4883 :
4884 : const CPLErr eErr =
4885 0 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4886 0 : const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4887 0 : *pdfMin -= dfHalfBucket;
4888 0 : *pdfMax += dfHalfBucket;
4889 :
4890 0 : if (eErr != CE_None)
4891 0 : return eErr;
4892 : }
4893 :
4894 17 : *ppanHistogram =
4895 17 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4896 17 : if (*ppanHistogram == nullptr)
4897 : {
4898 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4899 : "Out of memory in InitBlockInfo().");
4900 0 : return CE_Failure;
4901 : }
4902 :
4903 17 : *pnBuckets = nBuckets;
4904 34 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4905 17 : TRUE, FALSE, pfnProgress, pProgressData);
4906 17 : if (eErr != CE_None)
4907 : {
4908 0 : *pnBuckets = 0;
4909 : }
4910 17 : return eErr;
4911 : }
4912 :
4913 : /************************************************************************/
4914 : /* GDALGetDefaultHistogram() */
4915 : /************************************************************************/
4916 :
4917 : /**
4918 : * \brief Fetch default raster histogram.
4919 : *
4920 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4921 : * exceeding 2 billion.
4922 : *
4923 : * @see GDALRasterBand::GDALGetDefaultHistogram()
4924 : * @see GDALGetRasterHistogramEx()
4925 : */
4926 :
4927 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4928 : double *pdfMin, double *pdfMax,
4929 : int *pnBuckets, int **ppanHistogram,
4930 : int bForce,
4931 : GDALProgressFunc pfnProgress,
4932 : void *pProgressData)
4933 :
4934 : {
4935 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4936 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4937 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4938 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4939 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4940 :
4941 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4942 0 : GUIntBig *panHistogramTemp = nullptr;
4943 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
4944 : &panHistogramTemp, bForce,
4945 0 : pfnProgress, pProgressData);
4946 0 : if (eErr == CE_None)
4947 : {
4948 0 : const int nBuckets = *pnBuckets;
4949 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
4950 0 : if (*ppanHistogram == nullptr)
4951 : {
4952 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4953 : "Out of memory in GDALGetDefaultHistogram().");
4954 0 : VSIFree(panHistogramTemp);
4955 0 : return CE_Failure;
4956 : }
4957 :
4958 0 : for (int i = 0; i < nBuckets; ++i)
4959 : {
4960 0 : if (panHistogramTemp[i] > INT_MAX)
4961 : {
4962 0 : CPLError(CE_Warning, CPLE_AppDefined,
4963 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4964 : " exceeds maximum 32 bit value",
4965 0 : i, panHistogramTemp[i]);
4966 0 : (*ppanHistogram)[i] = INT_MAX;
4967 : }
4968 : else
4969 : {
4970 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
4971 : }
4972 : }
4973 :
4974 0 : CPLFree(panHistogramTemp);
4975 : }
4976 : else
4977 : {
4978 0 : *ppanHistogram = nullptr;
4979 : }
4980 :
4981 0 : return eErr;
4982 : }
4983 :
4984 : /************************************************************************/
4985 : /* GDALGetDefaultHistogramEx() */
4986 : /************************************************************************/
4987 :
4988 : /**
4989 : * \brief Fetch default raster histogram.
4990 : *
4991 : * @see GDALRasterBand::GetDefaultHistogram()
4992 : *
4993 : * @since GDAL 2.0
4994 : */
4995 :
4996 : CPLErr CPL_STDCALL
4997 28 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
4998 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
4999 : GDALProgressFunc pfnProgress, void *pProgressData)
5000 :
5001 : {
5002 28 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5003 28 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5004 28 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5005 28 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5006 28 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5007 :
5008 28 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5009 28 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5010 28 : bForce, pfnProgress, pProgressData);
5011 : }
5012 :
5013 : /************************************************************************/
5014 : /* AdviseRead() */
5015 : /************************************************************************/
5016 :
5017 : /**
5018 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5019 : * \brief Advise driver of upcoming read requests.
5020 : *
5021 : * Some GDAL drivers operate more efficiently if they know in advance what
5022 : * set of upcoming read requests will be made. The AdviseRead() method allows
5023 : * an application to notify the driver of the region of interest,
5024 : * and at what resolution the region will be read.
5025 : *
5026 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
5027 : * accelerate access via some drivers.
5028 : *
5029 : * Depending on call paths, drivers might receive several calls to
5030 : * AdviseRead() with the same parameters.
5031 : *
5032 : * @param nXOff The pixel offset to the top left corner of the region
5033 : * of the band to be accessed. This would be zero to start from the left side.
5034 : *
5035 : * @param nYOff The line offset to the top left corner of the region
5036 : * of the band to be accessed. This would be zero to start from the top.
5037 : *
5038 : * @param nXSize The width of the region of the band to be accessed in pixels.
5039 : *
5040 : * @param nYSize The height of the region of the band to be accessed in lines.
5041 : *
5042 : * @param nBufXSize the width of the buffer image into which the desired region
5043 : * is to be read, or from which it is to be written.
5044 : *
5045 : * @param nBufYSize the height of the buffer image into which the desired
5046 : * region is to be read, or from which it is to be written.
5047 : *
5048 : * @param eBufType the type of the pixel values in the pData data buffer. The
5049 : * pixel values will automatically be translated to/from the GDALRasterBand
5050 : * data type as needed.
5051 : *
5052 : * @param papszOptions a list of name=value strings with special control
5053 : * options. Normally this is NULL.
5054 : *
5055 : * @return CE_Failure if the request is invalid and CE_None if it works or
5056 : * is ignored.
5057 : */
5058 :
5059 : /**/
5060 : /**/
5061 :
5062 41502 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5063 : int /*nYSize*/, int /*nBufXSize*/,
5064 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5065 : char ** /*papszOptions*/)
5066 : {
5067 41502 : return CE_None;
5068 : }
5069 :
5070 : /************************************************************************/
5071 : /* GDALRasterAdviseRead() */
5072 : /************************************************************************/
5073 :
5074 : /**
5075 : * \brief Advise driver of upcoming read requests.
5076 : *
5077 : * @see GDALRasterBand::AdviseRead()
5078 : */
5079 :
5080 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5081 : int nYOff, int nXSize, int nYSize,
5082 : int nBufXSize, int nBufYSize,
5083 : GDALDataType eDT,
5084 : CSLConstList papszOptions)
5085 :
5086 : {
5087 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5088 :
5089 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5090 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5091 : nBufYSize, eDT,
5092 2 : const_cast<char **>(papszOptions));
5093 : }
5094 :
5095 : /************************************************************************/
5096 : /* GetStatistics() */
5097 : /************************************************************************/
5098 :
5099 : /**
5100 : * \brief Fetch image statistics.
5101 : *
5102 : * Returns the minimum, maximum, mean and standard deviation of all
5103 : * pixel values in this band. If approximate statistics are sufficient,
5104 : * the bApproxOK flag can be set to true in which case overviews, or a
5105 : * subset of image tiles may be used in computing the statistics.
5106 : *
5107 : * If bForce is FALSE results will only be returned if it can be done
5108 : * quickly (i.e. without scanning the image, typically by using pre-existing
5109 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5110 : * returned efficiently, the method will return CE_Warning but no warning will
5111 : * be issued. This is a non-standard use of the CE_Warning return value
5112 : * to indicate "nothing done".
5113 : *
5114 : * If bForce is TRUE, and results are quickly available without scanning the
5115 : * image, they will be used. If bForce is TRUE and results are not quickly
5116 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5117 : * which will scan the image.
5118 : *
5119 : * To always force recomputation of statistics, use ComputeStatistics() instead
5120 : * of this method.
5121 : *
5122 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5123 : * will generally cache statistics in the .pam file allowing fast fetch
5124 : * after the first request.
5125 : *
5126 : * This method is the same as the C function GDALGetRasterStatistics().
5127 : *
5128 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5129 : * or a subset of all tiles.
5130 : *
5131 : * @param bForce If FALSE statistics will only be returned if it can
5132 : * be done without rescanning the image. If TRUE, statistics computation will
5133 : * be forced if pre-existing values are not quickly available.
5134 : *
5135 : * @param pdfMin Location into which to load image minimum (may be NULL).
5136 : *
5137 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5138 : *
5139 : * @param pdfMean Location into which to load image mean (may be NULL).
5140 : *
5141 : * @param pdfStdDev Location into which to load image standard deviation
5142 : * (may be NULL).
5143 : *
5144 : * @return CE_None on success, CE_Warning if no values returned,
5145 : * CE_Failure if an error occurs.
5146 : */
5147 :
5148 617 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5149 : double *pdfMax, double *pdfMean,
5150 : double *pdfStdDev)
5151 :
5152 : {
5153 : /* -------------------------------------------------------------------- */
5154 : /* Do we already have metadata items for the requested values? */
5155 : /* -------------------------------------------------------------------- */
5156 1234 : if ((pdfMin == nullptr ||
5157 617 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5158 202 : (pdfMax == nullptr ||
5159 202 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5160 1436 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5161 202 : (pdfStdDev == nullptr ||
5162 202 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5163 : {
5164 202 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5165 : {
5166 195 : if (pdfMin != nullptr)
5167 195 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5168 195 : if (pdfMax != nullptr)
5169 195 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5170 195 : if (pdfMean != nullptr)
5171 195 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5172 195 : if (pdfStdDev != nullptr)
5173 195 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5174 :
5175 195 : return CE_None;
5176 : }
5177 : }
5178 :
5179 : /* -------------------------------------------------------------------- */
5180 : /* Does the driver already know the min/max? */
5181 : /* -------------------------------------------------------------------- */
5182 422 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5183 : {
5184 0 : int bSuccessMin = FALSE;
5185 0 : int bSuccessMax = FALSE;
5186 :
5187 0 : const double dfMin = GetMinimum(&bSuccessMin);
5188 0 : const double dfMax = GetMaximum(&bSuccessMax);
5189 :
5190 0 : if (bSuccessMin && bSuccessMax)
5191 : {
5192 0 : if (pdfMin != nullptr)
5193 0 : *pdfMin = dfMin;
5194 0 : if (pdfMax != nullptr)
5195 0 : *pdfMax = dfMax;
5196 0 : return CE_None;
5197 : }
5198 : }
5199 :
5200 : /* -------------------------------------------------------------------- */
5201 : /* Either return without results, or force computation. */
5202 : /* -------------------------------------------------------------------- */
5203 422 : if (!bForce)
5204 167 : return CE_Warning;
5205 : else
5206 255 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5207 255 : GDALDummyProgress, nullptr);
5208 : }
5209 :
5210 : /************************************************************************/
5211 : /* GDALGetRasterStatistics() */
5212 : /************************************************************************/
5213 :
5214 : /**
5215 : * \brief Fetch image statistics.
5216 : *
5217 : * @see GDALRasterBand::GetStatistics()
5218 : */
5219 :
5220 266 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5221 : int bForce, double *pdfMin,
5222 : double *pdfMax, double *pdfMean,
5223 : double *pdfStdDev)
5224 :
5225 : {
5226 266 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5227 :
5228 266 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5229 266 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5230 266 : pdfStdDev);
5231 : }
5232 :
5233 : /************************************************************************/
5234 : /* GDALUInt128 */
5235 : /************************************************************************/
5236 :
5237 : #ifdef HAVE_UINT128_T
5238 : class GDALUInt128
5239 : {
5240 : __uint128_t val;
5241 :
5242 636 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5243 : {
5244 636 : }
5245 :
5246 : public:
5247 424 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5248 : {
5249 : // Evaluates to just a single mul on x86_64
5250 424 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5251 : }
5252 :
5253 212 : GDALUInt128 operator-(const GDALUInt128 &other) const
5254 : {
5255 212 : return GDALUInt128(val - other.val);
5256 : }
5257 :
5258 203 : operator double() const
5259 : {
5260 203 : return static_cast<double>(val);
5261 : }
5262 : };
5263 : #else
5264 :
5265 : #if defined(_MSC_VER) && defined(_M_X64)
5266 : #include <intrin.h>
5267 : #endif
5268 :
5269 : class GDALUInt128
5270 : {
5271 : GUIntBig low, high;
5272 :
5273 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5274 : {
5275 : }
5276 :
5277 : public:
5278 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5279 : {
5280 : #if defined(_MSC_VER) && defined(_M_X64)
5281 : GUIntBig highRes;
5282 : GUIntBig lowRes = _umul128(first, second, &highRes);
5283 : return GDALUInt128(lowRes, highRes);
5284 : #else
5285 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5286 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5287 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5288 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5289 : GUIntBig highRes = 0;
5290 : const GUIntBig firstLowSecondHigh =
5291 : static_cast<GUIntBig>(firstLow) * secondHigh;
5292 : const GUIntBig firstHighSecondLow =
5293 : static_cast<GUIntBig>(firstHigh) * secondLow;
5294 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5295 : if (middleTerm < firstLowSecondHigh) // check for overflow
5296 : highRes += static_cast<GUIntBig>(1) << 32;
5297 : const GUIntBig firstLowSecondLow =
5298 : static_cast<GUIntBig>(firstLow) * secondLow;
5299 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5300 : if (lowRes < firstLowSecondLow) // check for overflow
5301 : highRes++;
5302 : highRes +=
5303 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5304 : return GDALUInt128(lowRes, highRes);
5305 : #endif
5306 : }
5307 :
5308 : GDALUInt128 operator-(const GDALUInt128 &other) const
5309 : {
5310 : GUIntBig highRes = high - other.high;
5311 : GUIntBig lowRes = low - other.low;
5312 : if (lowRes > low) // check for underflow
5313 : --highRes;
5314 : return GDALUInt128(lowRes, highRes);
5315 : }
5316 :
5317 : operator double() const
5318 : {
5319 : const double twoPow64 = 18446744073709551616.0;
5320 : return high * twoPow64 + low;
5321 : }
5322 : };
5323 : #endif
5324 :
5325 : /************************************************************************/
5326 : /* ComputeStatisticsInternal() */
5327 : /************************************************************************/
5328 :
5329 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5330 : // not needed.
5331 : #define static_cast_for_coverity_scan static_cast
5332 :
5333 : // The rationale for below optimizations is detailed in statistics.txt
5334 :
5335 : // Use with T = GByte or GUInt16 only !
5336 : template <class T, bool COMPUTE_OTHER_STATS>
5337 : struct ComputeStatisticsInternalGeneric
5338 : {
5339 204 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5340 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5341 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5342 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5343 : {
5344 : static_assert(std::is_same<T, GByte>::value ||
5345 : std::is_same<T, GUInt16>::value,
5346 : "bad type for T");
5347 204 : if (bHasNoData)
5348 : {
5349 : // General case
5350 386 : for (int iY = 0; iY < nYCheck; iY++)
5351 : {
5352 81751 : for (int iX = 0; iX < nXCheck; iX++)
5353 : {
5354 81468 : const GPtrDiff_t iOffset =
5355 81468 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5356 81468 : const GUInt32 nValue = pData[iOffset];
5357 81468 : if (nValue == nNoDataValue)
5358 175 : continue;
5359 81293 : if (nValue < nMin)
5360 26 : nMin = nValue;
5361 81293 : if (nValue > nMax)
5362 57 : nMax = nValue;
5363 : if constexpr (COMPUTE_OTHER_STATS)
5364 : {
5365 79657 : nValidCount++;
5366 79657 : nSum += nValue;
5367 79657 : nSumSquare +=
5368 79657 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5369 79657 : nValue;
5370 : }
5371 : }
5372 : }
5373 : if constexpr (COMPUTE_OTHER_STATS)
5374 : {
5375 20 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5376 : }
5377 : }
5378 111 : else if (nMin == std::numeric_limits<T>::lowest() &&
5379 10 : nMax == std::numeric_limits<T>::max())
5380 : {
5381 : if constexpr (COMPUTE_OTHER_STATS)
5382 : {
5383 : // Optimization when there is no nodata and we know we have already
5384 : // reached the min and max
5385 208 : for (int iY = 0; iY < nYCheck; iY++)
5386 : {
5387 : int iX;
5388 1002 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5389 : {
5390 800 : const GPtrDiff_t iOffset =
5391 800 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5392 800 : const GUIntBig nValue = pData[iOffset];
5393 800 : const GUIntBig nValue2 = pData[iOffset + 1];
5394 800 : const GUIntBig nValue3 = pData[iOffset + 2];
5395 800 : const GUIntBig nValue4 = pData[iOffset + 3];
5396 800 : nSum += nValue;
5397 800 : nSumSquare += nValue * nValue;
5398 800 : nSum += nValue2;
5399 800 : nSumSquare += nValue2 * nValue2;
5400 800 : nSum += nValue3;
5401 800 : nSumSquare += nValue3 * nValue3;
5402 800 : nSum += nValue4;
5403 800 : nSumSquare += nValue4 * nValue4;
5404 : }
5405 207 : for (; iX < nXCheck; ++iX)
5406 : {
5407 5 : const GPtrDiff_t iOffset =
5408 5 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5409 5 : const GUIntBig nValue = pData[iOffset];
5410 5 : nSum += nValue;
5411 5 : nSumSquare += nValue * nValue;
5412 : }
5413 : }
5414 6 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5415 6 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5416 : }
5417 : }
5418 : else
5419 : {
5420 3426 : for (int iY = 0; iY < nYCheck; iY++)
5421 : {
5422 : int iX;
5423 643292 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5424 : {
5425 639961 : const GPtrDiff_t iOffset =
5426 639961 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5427 639961 : const GUInt32 nValue = pData[iOffset];
5428 639961 : const GUInt32 nValue2 = pData[iOffset + 1];
5429 639961 : if (nValue < nValue2)
5430 : {
5431 2320 : if (nValue < nMin)
5432 48 : nMin = nValue;
5433 2320 : if (nValue2 > nMax)
5434 116 : nMax = nValue2;
5435 : }
5436 : else
5437 : {
5438 637641 : if (nValue2 < nMin)
5439 65 : nMin = nValue2;
5440 637641 : if (nValue > nMax)
5441 214 : nMax = nValue;
5442 : }
5443 : if constexpr (COMPUTE_OTHER_STATS)
5444 : {
5445 632911 : nSum += nValue;
5446 632911 : nSumSquare +=
5447 632911 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5448 632911 : nValue;
5449 632911 : nSum += nValue2;
5450 632911 : nSumSquare +=
5451 632911 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5452 632911 : nValue2;
5453 : }
5454 : }
5455 3331 : if (iX < nXCheck)
5456 : {
5457 15 : const GPtrDiff_t iOffset =
5458 15 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5459 15 : const GUInt32 nValue = pData[iOffset];
5460 15 : if (nValue < nMin)
5461 10 : nMin = nValue;
5462 15 : if (nValue > nMax)
5463 11 : nMax = nValue;
5464 : if (COMPUTE_OTHER_STATS)
5465 : {
5466 9 : nSum += nValue;
5467 9 : nSumSquare +=
5468 9 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5469 9 : nValue;
5470 : }
5471 : }
5472 : }
5473 : if constexpr (COMPUTE_OTHER_STATS)
5474 : {
5475 44 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5476 44 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5477 : }
5478 : }
5479 204 : }
5480 : };
5481 :
5482 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5483 : // using 64bit accumulators in internal loops. This also slightly helps in
5484 : // 64bit mode.
5485 : template <bool COMPUTE_OTHER_STATS>
5486 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5487 : {
5488 13515 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5489 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5490 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5491 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5492 : {
5493 13515 : int nOuterLoops = nXCheck / 65536;
5494 13515 : if (nXCheck % 65536)
5495 13515 : nOuterLoops++;
5496 :
5497 13515 : if (bHasNoData)
5498 : {
5499 : // General case
5500 23471 : for (int iY = 0; iY < nYCheck; iY++)
5501 : {
5502 12899 : int iX = 0;
5503 25798 : for (int k = 0; k < nOuterLoops; k++)
5504 : {
5505 12899 : int iMax = iX + 65536;
5506 12899 : if (iMax > nXCheck)
5507 12899 : iMax = nXCheck;
5508 12899 : GUInt32 nSum32bit = 0;
5509 12899 : GUInt32 nSumSquare32bit = 0;
5510 12899 : GUInt32 nValidCount32bit = 0;
5511 12899 : GUInt32 nSampleCount32bit = 0;
5512 20707057 : for (; iX < iMax; iX++)
5513 : {
5514 20694207 : const GPtrDiff_t iOffset =
5515 20694207 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5516 20694207 : const GUInt32 nValue = pData[iOffset];
5517 :
5518 20694207 : nSampleCount32bit++;
5519 20694207 : if (nValue == nNoDataValue)
5520 20353460 : continue;
5521 340692 : if (nValue < nMin)
5522 335 : nMin = nValue;
5523 340692 : if (nValue > nMax)
5524 809 : nMax = nValue;
5525 : if constexpr (COMPUTE_OTHER_STATS)
5526 : {
5527 16947 : nValidCount32bit++;
5528 16947 : nSum32bit += nValue;
5529 16947 : nSumSquare32bit += nValue * nValue;
5530 : }
5531 : }
5532 : if constexpr (COMPUTE_OTHER_STATS)
5533 : {
5534 650 : nSampleCount += nSampleCount32bit;
5535 650 : nValidCount += nValidCount32bit;
5536 650 : nSum += nSum32bit;
5537 650 : nSumSquare += nSumSquare32bit;
5538 : }
5539 : }
5540 : }
5541 : }
5542 2943 : else if (nMin == 0 && nMax == 255)
5543 : {
5544 : if constexpr (COMPUTE_OTHER_STATS)
5545 : {
5546 : // Optimization when there is no nodata and we know we have already
5547 : // reached the min and max
5548 2644 : for (int iY = 0; iY < nYCheck; iY++)
5549 : {
5550 2617 : int iX = 0;
5551 5234 : for (int k = 0; k < nOuterLoops; k++)
5552 : {
5553 2617 : int iMax = iX + 65536;
5554 2617 : if (iMax > nXCheck)
5555 2617 : iMax = nXCheck;
5556 2617 : GUInt32 nSum32bit = 0;
5557 2617 : GUInt32 nSumSquare32bit = 0;
5558 176297 : for (; iX + 3 < iMax; iX += 4)
5559 : {
5560 173680 : const GPtrDiff_t iOffset =
5561 173680 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5562 173680 : const GUInt32 nValue = pData[iOffset];
5563 173680 : const GUInt32 nValue2 = pData[iOffset + 1];
5564 173680 : const GUInt32 nValue3 = pData[iOffset + 2];
5565 173680 : const GUInt32 nValue4 = pData[iOffset + 3];
5566 173680 : nSum32bit += nValue;
5567 173680 : nSumSquare32bit += nValue * nValue;
5568 173680 : nSum32bit += nValue2;
5569 173680 : nSumSquare32bit += nValue2 * nValue2;
5570 173680 : nSum32bit += nValue3;
5571 173680 : nSumSquare32bit += nValue3 * nValue3;
5572 173680 : nSum32bit += nValue4;
5573 173680 : nSumSquare32bit += nValue4 * nValue4;
5574 : }
5575 2617 : nSum += nSum32bit;
5576 2617 : nSumSquare += nSumSquare32bit;
5577 : }
5578 2620 : for (; iX < nXCheck; ++iX)
5579 : {
5580 3 : const GPtrDiff_t iOffset =
5581 3 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5582 3 : const GUIntBig nValue = pData[iOffset];
5583 3 : nSum += nValue;
5584 3 : nSumSquare += nValue * nValue;
5585 : }
5586 : }
5587 27 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5588 27 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5589 27 : }
5590 : }
5591 : else
5592 : {
5593 7490 : for (int iY = 0; iY < nYCheck; iY++)
5594 : {
5595 4574 : int iX = 0;
5596 9149 : for (int k = 0; k < nOuterLoops; k++)
5597 : {
5598 4575 : int iMax = iX + 65536;
5599 4575 : if (iMax > nXCheck)
5600 4575 : iMax = nXCheck;
5601 4575 : GUInt32 nSum32bit = 0;
5602 4575 : GUInt32 nSumSquare32bit = 0;
5603 159202 : for (; iX + 1 < iMax; iX += 2)
5604 : {
5605 154627 : const GPtrDiff_t iOffset =
5606 154627 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5607 154627 : const GUInt32 nValue = pData[iOffset];
5608 154627 : const GUInt32 nValue2 = pData[iOffset + 1];
5609 154627 : if (nValue < nValue2)
5610 : {
5611 8100 : if (nValue < nMin)
5612 232 : nMin = nValue;
5613 8100 : if (nValue2 > nMax)
5614 219 : nMax = nValue2;
5615 : }
5616 : else
5617 : {
5618 146527 : if (nValue2 < nMin)
5619 277 : nMin = nValue2;
5620 146527 : if (nValue > nMax)
5621 779 : nMax = nValue;
5622 : }
5623 : if constexpr (COMPUTE_OTHER_STATS)
5624 : {
5625 132607 : nSum32bit += nValue;
5626 132607 : nSumSquare32bit += nValue * nValue;
5627 132607 : nSum32bit += nValue2;
5628 132607 : nSumSquare32bit += nValue2 * nValue2;
5629 : }
5630 : }
5631 : if constexpr (COMPUTE_OTHER_STATS)
5632 : {
5633 1629 : nSum += nSum32bit;
5634 1629 : nSumSquare += nSumSquare32bit;
5635 : }
5636 : }
5637 4574 : if (iX < nXCheck)
5638 : {
5639 1400 : const GPtrDiff_t iOffset =
5640 1400 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5641 1400 : const GUInt32 nValue = pData[iOffset];
5642 1400 : if (nValue < nMin)
5643 50 : nMin = nValue;
5644 1400 : if (nValue > nMax)
5645 62 : nMax = nValue;
5646 : if constexpr (COMPUTE_OTHER_STATS)
5647 : {
5648 312 : nSum += nValue;
5649 312 : nSumSquare +=
5650 312 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5651 312 : nValue;
5652 : }
5653 : }
5654 : }
5655 : if constexpr (COMPUTE_OTHER_STATS)
5656 : {
5657 928 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5658 928 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5659 : }
5660 : }
5661 13515 : }
5662 : };
5663 :
5664 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5665 : {
5666 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5667 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5668 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5669 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5670 : {
5671 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5672 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5673 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5674 : }
5675 : };
5676 :
5677 : #if (defined(__x86_64__) || defined(_M_X64)) && \
5678 : (defined(__GNUC__) || defined(_MSC_VER))
5679 :
5680 : #include "gdal_avx2_emulation.hpp"
5681 :
5682 : #define ZERO256 GDALmm256_setzero_si256()
5683 :
5684 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5685 : static void
5686 20930 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5687 : // assumed to be aligned on 256 bits
5688 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5689 : GUIntBig &nSum, GUIntBig &nSumSquare,
5690 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5691 : {
5692 : // 32-byte alignment may not be enforced by linker, so do it at hand
5693 : GByte
5694 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5695 20930 : GByte *paby32ByteAligned =
5696 : aby32ByteUnaligned +
5697 20930 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5698 20930 : GByte *pabyMin = paby32ByteAligned;
5699 20930 : GByte *pabyMax = paby32ByteAligned + 32;
5700 20930 : GUInt32 *panSum =
5701 : COMPUTE_OTHER_STATS
5702 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5703 : : nullptr;
5704 20930 : GUInt32 *panSumSquare =
5705 : COMPUTE_OTHER_STATS
5706 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5707 : : nullptr;
5708 :
5709 20930 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5710 :
5711 20930 : GPtrDiff_t i = 0;
5712 : // Make sure that sumSquare can fit on uint32
5713 : // * 8 since we can hold 8 sums per vector register
5714 20930 : const int nMaxIterationsPerInnerLoop =
5715 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5716 20930 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5717 20930 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5718 20930 : nOuterLoops++;
5719 :
5720 : GDALm256i ymm_min =
5721 20930 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5722 20930 : GDALm256i ymm_max = ymm_min;
5723 20930 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5724 :
5725 41860 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5726 : {
5727 20930 : const auto iMax =
5728 20930 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5729 :
5730 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5731 20930 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5732 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5733 20930 : ZERO256; // holds 8 uint32 sums
5734 705499 : for (; i + 31 < iMax; i += 32)
5735 : {
5736 684569 : const GDALm256i ymm = GDALmm256_load_si256(
5737 684569 : reinterpret_cast<const GDALm256i *>(pData + i));
5738 : if (COMPUTE_MIN)
5739 : {
5740 226732 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5741 : }
5742 : if (COMPUTE_MAX)
5743 : {
5744 593628 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5745 : }
5746 :
5747 : if constexpr (COMPUTE_OTHER_STATS)
5748 : {
5749 : // Extract even-8bit values
5750 : const GDALm256i ymm_even =
5751 493495 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5752 : // Compute square of those 16 values as 32 bit result
5753 : // and add adjacent pairs
5754 : const GDALm256i ymm_even_square =
5755 493495 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5756 : // Add to the sumsquare accumulator
5757 : ymm_sumsquare =
5758 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5759 :
5760 : // Extract odd-8bit values
5761 493495 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5762 : const GDALm256i ymm_odd_square =
5763 493495 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5764 : ymm_sumsquare =
5765 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5766 :
5767 : // Now compute the sums
5768 493495 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5769 : GDALmm256_sad_epu8(ymm, ZERO256));
5770 : }
5771 : }
5772 :
5773 : if constexpr (COMPUTE_OTHER_STATS)
5774 : {
5775 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5776 : ymm_sum);
5777 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5778 : ymm_sumsquare);
5779 :
5780 10649 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5781 10649 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5782 10649 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5783 10649 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5784 : panSumSquare[7];
5785 : }
5786 : }
5787 :
5788 : if constexpr (COMPUTE_MIN)
5789 : {
5790 8056 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5791 : }
5792 : if constexpr (COMPUTE_MAX)
5793 : {
5794 16933 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5795 : }
5796 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5797 : {
5798 576279 : for (int j = 0; j < 32; j++)
5799 : {
5800 : if constexpr (COMPUTE_MIN)
5801 : {
5802 257792 : if (pabyMin[j] < nMin)
5803 1245 : nMin = pabyMin[j];
5804 : }
5805 : if constexpr (COMPUTE_MAX)
5806 : {
5807 541856 : if (pabyMax[j] > nMax)
5808 1793 : nMax = pabyMax[j];
5809 : }
5810 : }
5811 : }
5812 :
5813 227580 : for (; i < nBlockPixels; i++)
5814 : {
5815 206650 : const GUInt32 nValue = pData[i];
5816 : if constexpr (COMPUTE_MIN)
5817 : {
5818 81974 : if (nValue < nMin)
5819 1 : nMin = nValue;
5820 : }
5821 : if constexpr (COMPUTE_MAX)
5822 : {
5823 203875 : if (nValue > nMax)
5824 1149 : nMax = nValue;
5825 : }
5826 : if constexpr (COMPUTE_OTHER_STATS)
5827 : {
5828 77195 : nSum += nValue;
5829 77195 : nSumSquare +=
5830 77195 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5831 : }
5832 : }
5833 :
5834 : if constexpr (COMPUTE_OTHER_STATS)
5835 : {
5836 10649 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5837 10649 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5838 : }
5839 20930 : }
5840 :
5841 : // SSE2/AVX2 optimization for GByte case
5842 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5843 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5844 : // there are strictly equivalent to 2 parallel SSE2 streams.
5845 : template <bool COMPUTE_OTHER_STATS>
5846 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5847 : {
5848 29858 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5849 : // assumed to be aligned on 256 bits
5850 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5851 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5852 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5853 : GUIntBig &nValidCount)
5854 : {
5855 29858 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5856 29858 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5857 11452 : nMin <= nMax)
5858 : {
5859 : // 32-byte alignment may not be enforced by linker, so do it at hand
5860 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5861 1339 : GByte *paby32ByteAligned =
5862 : aby32ByteUnaligned +
5863 1339 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5864 1339 : GByte *pabyMin = paby32ByteAligned;
5865 1339 : GByte *pabyMax = paby32ByteAligned + 32;
5866 1339 : GUInt32 *panSum =
5867 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5868 1339 : GUInt32 *panSumSquare =
5869 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5870 :
5871 1339 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5872 :
5873 1339 : GPtrDiff_t i = 0;
5874 : // Make sure that sumSquare can fit on uint32
5875 : // * 8 since we can hold 8 sums per vector register
5876 1339 : const int nMaxIterationsPerInnerLoop =
5877 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5878 1339 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5879 1339 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5880 1339 : nOuterLoops++;
5881 :
5882 : const GDALm256i ymm_nodata =
5883 1339 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5884 : // any non noData value in [min,max] would do.
5885 : const GDALm256i ymm_neutral =
5886 1339 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5887 1339 : GDALm256i ymm_min = ymm_neutral;
5888 1339 : GDALm256i ymm_max = ymm_neutral;
5889 : [[maybe_unused]] const auto ymm_mask_8bits =
5890 1339 : GDALmm256_set1_epi16(0xFF);
5891 :
5892 1339 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5893 1339 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5894 1339 : const bool bComputeMinMax =
5895 1339 : nMin > nMinThreshold || nMax < nMaxThreshold;
5896 :
5897 2678 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5898 : {
5899 1339 : const auto iMax =
5900 1339 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5901 :
5902 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5903 1339 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5904 : // holds 8 uint32 sums
5905 1339 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5906 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5907 1339 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5908 1339 : const auto iInit = i;
5909 14195 : for (; i + 31 < iMax; i += 32)
5910 : {
5911 12856 : const GDALm256i ymm = GDALmm256_load_si256(
5912 12856 : reinterpret_cast<const GDALm256i *>(pData + i));
5913 :
5914 : // Check which values are nodata
5915 : const GDALm256i ymm_eq_nodata =
5916 12856 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5917 : if constexpr (COMPUTE_OTHER_STATS)
5918 : {
5919 : // Count how many values are nodata (due to cmpeq
5920 : // putting 255 when condition is met, this will actually
5921 : // be 255 times the number of nodata value, spread in 4
5922 : // 64 bits words). We can use add_epi32 as the counter
5923 : // will not overflow uint32
5924 4514 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5925 : ymm_count_nodata_mul_255,
5926 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5927 : }
5928 : // Replace all nodata values by zero for the purpose of sum
5929 : // and sumquare.
5930 : const GDALm256i ymm_nodata_by_zero =
5931 12856 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5932 12856 : if (bComputeMinMax)
5933 : {
5934 : // Replace all nodata values by a neutral value for the
5935 : // purpose of min and max.
5936 : const GDALm256i ymm_nodata_by_neutral =
5937 8471 : GDALmm256_or_si256(
5938 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5939 : ymm_nodata_by_zero);
5940 :
5941 : ymm_min =
5942 8471 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5943 : ymm_max =
5944 8471 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
5945 : }
5946 :
5947 : if constexpr (COMPUTE_OTHER_STATS)
5948 : {
5949 : // Extract even-8bit values
5950 4514 : const GDALm256i ymm_even = GDALmm256_and_si256(
5951 : ymm_nodata_by_zero, ymm_mask_8bits);
5952 : // Compute square of those 16 values as 32 bit result
5953 : // and add adjacent pairs
5954 : const GDALm256i ymm_even_square =
5955 4514 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5956 : // Add to the sumsquare accumulator
5957 : ymm_sumsquare =
5958 4514 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5959 :
5960 : // Extract odd-8bit values
5961 : const GDALm256i ymm_odd =
5962 4514 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
5963 : const GDALm256i ymm_odd_square =
5964 4514 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5965 : ymm_sumsquare =
5966 4514 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5967 :
5968 : // Now compute the sums
5969 4514 : ymm_sum = GDALmm256_add_epi32(
5970 : ymm_sum,
5971 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
5972 : }
5973 : }
5974 :
5975 : if constexpr (COMPUTE_OTHER_STATS)
5976 : {
5977 33 : GUInt32 *panCoutNoDataMul255 = panSum;
5978 33 : GDALmm256_store_si256(
5979 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
5980 : ymm_count_nodata_mul_255);
5981 :
5982 33 : nSampleCount += (i - iInit);
5983 :
5984 33 : nValidCount +=
5985 33 : (i - iInit) -
5986 33 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
5987 33 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
5988 : 255;
5989 :
5990 33 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5991 : ymm_sum);
5992 33 : GDALmm256_store_si256(
5993 : reinterpret_cast<GDALm256i *>(panSumSquare),
5994 : ymm_sumsquare);
5995 33 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5996 33 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5997 33 : panSumSquare[1] + panSumSquare[2] +
5998 33 : panSumSquare[3] + panSumSquare[4] +
5999 33 : panSumSquare[5] + panSumSquare[6] +
6000 : panSumSquare[7];
6001 : }
6002 : }
6003 :
6004 1339 : if (bComputeMinMax)
6005 : {
6006 1308 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6007 : ymm_min);
6008 1308 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6009 : ymm_max);
6010 43164 : for (int j = 0; j < 32; j++)
6011 : {
6012 41856 : if (pabyMin[j] < nMin)
6013 32 : nMin = pabyMin[j];
6014 41856 : if (pabyMax[j] > nMax)
6015 157 : nMax = pabyMax[j];
6016 : }
6017 : }
6018 :
6019 : if constexpr (COMPUTE_OTHER_STATS)
6020 : {
6021 33 : nSampleCount += nBlockPixels - i;
6022 : }
6023 30305 : for (; i < nBlockPixels; i++)
6024 : {
6025 28966 : const GUInt32 nValue = pData[i];
6026 28966 : if (nValue == nNoDataValue)
6027 24923 : continue;
6028 4043 : if (nValue < nMin)
6029 1 : nMin = nValue;
6030 4043 : if (nValue > nMax)
6031 13 : nMax = nValue;
6032 : if constexpr (COMPUTE_OTHER_STATS)
6033 : {
6034 110 : nValidCount++;
6035 110 : nSum += nValue;
6036 110 : nSumSquare +=
6037 110 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6038 110 : nValue;
6039 : }
6040 1339 : }
6041 : }
6042 28519 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6043 : {
6044 14974 : if (nMin > 0)
6045 : {
6046 2100 : if (nMax < 255)
6047 : {
6048 : ComputeStatisticsByteNoNodata<true, true,
6049 1570 : COMPUTE_OTHER_STATS>(
6050 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6051 : nSampleCount, nValidCount);
6052 : }
6053 : else
6054 : {
6055 : ComputeStatisticsByteNoNodata<true, false,
6056 530 : COMPUTE_OTHER_STATS>(
6057 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6058 : nSampleCount, nValidCount);
6059 : }
6060 : }
6061 : else
6062 : {
6063 12874 : if (nMax < 255)
6064 : {
6065 : ComputeStatisticsByteNoNodata<false, true,
6066 9407 : COMPUTE_OTHER_STATS>(
6067 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6068 : nSampleCount, nValidCount);
6069 : }
6070 : else
6071 : {
6072 : ComputeStatisticsByteNoNodata<false, false,
6073 3467 : COMPUTE_OTHER_STATS>(
6074 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6075 : nSampleCount, nValidCount);
6076 : }
6077 : }
6078 : }
6079 12274 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6080 31 : (nBlockXSize % 32) == 0)
6081 : {
6082 5987 : for (int iY = 0; iY < nYCheck; iY++)
6083 : {
6084 5956 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6085 5956 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6086 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6087 31 : }
6088 : }
6089 : else
6090 : {
6091 13514 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6092 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6093 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6094 : }
6095 29859 : }
6096 : };
6097 :
6098 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6099 400 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6100 : GUIntBig i)
6101 : {
6102 400 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6103 400 : }
6104 :
6105 : // AVX2/SSE2 optimization for GUInt16 case
6106 : template <bool COMPUTE_OTHER_STATS>
6107 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6108 : {
6109 1366 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
6110 : // assumed to be aligned on 128 bits
6111 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6112 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6113 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6114 : GUIntBig &nValidCount)
6115 : {
6116 1366 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6117 1366 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6118 : {
6119 1162 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6120 :
6121 1162 : GPtrDiff_t i = 0;
6122 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6123 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6124 : // Furthermore the shift is also needed to use madd_epi16
6125 1162 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6126 1162 : GDALm256i ymm_min = GDALmm256_load_si256(
6127 1162 : reinterpret_cast<const GDALm256i *>(pData + i));
6128 1162 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6129 1162 : GDALm256i ymm_max = ymm_min;
6130 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6131 1162 : ZERO256; // holds 4 uint64 sums
6132 :
6133 : // Make sure that sum can fit on uint32
6134 : // * 8 since we can hold 8 sums per vector register
6135 1162 : const int nMaxIterationsPerInnerLoop =
6136 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6137 1162 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6138 1162 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6139 1162 : nOuterLoops++;
6140 :
6141 1162 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6142 : [[maybe_unused]] const auto ymm_mask_16bits =
6143 1162 : GDALmm256_set1_epi32(0xFFFF);
6144 : [[maybe_unused]] const auto ymm_mask_32bits =
6145 1162 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6146 :
6147 1162 : GUIntBig nSumThis = 0;
6148 2348 : for (int k = 0; k < nOuterLoops; k++)
6149 : {
6150 1186 : const auto iMax =
6151 1186 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6152 :
6153 : [[maybe_unused]] GDALm256i ymm_sum =
6154 1186 : ZERO256; // holds 8 uint32 sums
6155 955422 : for (; i + 15 < iMax; i += 16)
6156 : {
6157 954236 : const GDALm256i ymm = GDALmm256_load_si256(
6158 954236 : reinterpret_cast<const GDALm256i *>(pData + i));
6159 : const GDALm256i ymm_shifted =
6160 954236 : GDALmm256_add_epi16(ymm, ymm_m32768);
6161 954236 : if (bComputeMinMax)
6162 : {
6163 945217 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6164 945217 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6165 : }
6166 :
6167 : if constexpr (COMPUTE_OTHER_STATS)
6168 : {
6169 : // Note: the int32 range can overflow for (0-32768)^2 +
6170 : // (0-32768)^2 = 0x80000000, but as we know the result
6171 : // is positive, this is OK as we interpret is a uint32.
6172 : const GDALm256i ymm_square =
6173 95410 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6174 95410 : ymm_sumsquare = GDALmm256_add_epi64(
6175 : ymm_sumsquare,
6176 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6177 95410 : ymm_sumsquare = GDALmm256_add_epi64(
6178 : ymm_sumsquare,
6179 : GDALmm256_srli_epi64(ymm_square, 32));
6180 :
6181 : // Now compute the sums
6182 95410 : ymm_sum = GDALmm256_add_epi32(
6183 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6184 95410 : ymm_sum = GDALmm256_add_epi32(
6185 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6186 : }
6187 : }
6188 :
6189 : if constexpr (COMPUTE_OTHER_STATS)
6190 : {
6191 : GUInt32 anSum[8];
6192 400 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6193 : ymm_sum);
6194 400 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6195 400 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6196 400 : anSum[6] + anSum[7];
6197 : }
6198 : }
6199 :
6200 1162 : if (bComputeMinMax)
6201 : {
6202 : GUInt16 anMin[16];
6203 : GUInt16 anMax[16];
6204 :
6205 : // Unshift the result
6206 1121 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6207 1121 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6208 1121 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6209 : ymm_min);
6210 1121 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6211 : ymm_max);
6212 19057 : for (int j = 0; j < 16; j++)
6213 : {
6214 17936 : if (anMin[j] < nMin)
6215 341 : nMin = anMin[j];
6216 17936 : if (anMax[j] > nMax)
6217 480 : nMax = anMax[j];
6218 : }
6219 : }
6220 :
6221 : if constexpr (COMPUTE_OTHER_STATS)
6222 : {
6223 : GUIntBig anSumSquare[4];
6224 400 : GDALmm256_storeu_si256(
6225 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6226 400 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6227 : anSumSquare[3];
6228 :
6229 : // Unshift the sum of squares
6230 400 : UnshiftSumSquare(nSumSquare, nSumThis,
6231 : static_cast<GUIntBig>(i));
6232 :
6233 400 : nSum += nSumThis;
6234 :
6235 722 : for (; i < nBlockPixels; i++)
6236 : {
6237 322 : const GUInt32 nValue = pData[i];
6238 322 : if (nValue < nMin)
6239 1 : nMin = nValue;
6240 322 : if (nValue > nMax)
6241 1 : nMax = nValue;
6242 322 : nSum += nValue;
6243 322 : nSumSquare +=
6244 322 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6245 322 : nValue;
6246 : }
6247 :
6248 400 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6249 400 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6250 1162 : }
6251 : }
6252 : else
6253 : {
6254 204 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6255 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6256 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6257 : }
6258 1366 : }
6259 : };
6260 :
6261 : #endif
6262 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6263 : // defined(_MSC_VER))
6264 :
6265 : /************************************************************************/
6266 : /* GetPixelValue() */
6267 : /************************************************************************/
6268 :
6269 23152800 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6270 : const void *pData, GPtrDiff_t iOffset,
6271 : const GDALNoDataValues &sNoDataValues,
6272 : bool &bValid)
6273 : {
6274 23152800 : bValid = true;
6275 23152800 : double dfValue = 0;
6276 23152800 : switch (eDataType)
6277 : {
6278 1413680 : case GDT_Byte:
6279 : {
6280 1413680 : if (bSignedByte)
6281 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6282 : else
6283 1413490 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6284 1413680 : break;
6285 : }
6286 10409 : case GDT_Int8:
6287 10409 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6288 10409 : break;
6289 4000 : case GDT_UInt16:
6290 4000 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6291 4000 : break;
6292 60192 : case GDT_Int16:
6293 60192 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6294 60192 : break;
6295 27600 : case GDT_UInt32:
6296 27600 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6297 27600 : break;
6298 455610 : case GDT_Int32:
6299 455610 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6300 455610 : break;
6301 2602 : case GDT_UInt64:
6302 2602 : dfValue = static_cast<double>(
6303 2602 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6304 2602 : break;
6305 7402 : case GDT_Int64:
6306 7402 : dfValue = static_cast<double>(
6307 7402 : static_cast<const std::int64_t *>(pData)[iOffset]);
6308 7402 : break;
6309 0 : case GDT_Float16:
6310 : {
6311 : using namespace std;
6312 0 : const GFloat16 hfValue =
6313 0 : static_cast<const GFloat16 *>(pData)[iOffset];
6314 0 : if (isnan(hfValue) ||
6315 0 : (sNoDataValues.bGotFloat16NoDataValue &&
6316 0 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6317 : {
6318 0 : bValid = false;
6319 0 : return 0.0;
6320 : }
6321 0 : dfValue = hfValue;
6322 0 : return dfValue;
6323 : }
6324 17477400 : case GDT_Float32:
6325 : {
6326 17477400 : const float fValue = static_cast<const float *>(pData)[iOffset];
6327 34927900 : if (std::isnan(fValue) ||
6328 30655700 : (sNoDataValues.bGotFloatNoDataValue &&
6329 13205200 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6330 : {
6331 119866 : bValid = false;
6332 119866 : return 0.0;
6333 : }
6334 17357500 : dfValue = fValue;
6335 17357500 : return dfValue;
6336 : }
6337 3676860 : case GDT_Float64:
6338 3676860 : dfValue = static_cast<const double *>(pData)[iOffset];
6339 3676860 : if (std::isnan(dfValue))
6340 : {
6341 52 : bValid = false;
6342 52 : return 0.0;
6343 : }
6344 3676800 : break;
6345 2692 : case GDT_CInt16:
6346 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6347 2692 : break;
6348 2692 : case GDT_CInt32:
6349 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6350 2692 : break;
6351 0 : case GDT_CFloat16:
6352 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6353 0 : if (std::isnan(dfValue))
6354 : {
6355 0 : bValid = false;
6356 0 : return 0.0;
6357 : }
6358 0 : break;
6359 5812 : case GDT_CFloat32:
6360 5812 : dfValue = static_cast<const float *>(pData)[iOffset * 2];
6361 5812 : if (std::isnan(dfValue))
6362 : {
6363 0 : bValid = false;
6364 0 : return 0.0;
6365 : }
6366 5812 : break;
6367 5892 : case GDT_CFloat64:
6368 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6369 5892 : if (std::isnan(dfValue))
6370 : {
6371 0 : bValid = false;
6372 0 : return 0.0;
6373 : }
6374 5892 : break;
6375 0 : case GDT_Unknown:
6376 : case GDT_TypeCount:
6377 0 : CPLAssert(false);
6378 : break;
6379 : }
6380 :
6381 9414380 : if (sNoDataValues.bGotNoDataValue &&
6382 3738990 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6383 : {
6384 3346220 : bValid = false;
6385 3346220 : return 0.0;
6386 : }
6387 2329170 : return dfValue;
6388 : }
6389 :
6390 : /************************************************************************/
6391 : /* SetValidPercent() */
6392 : /************************************************************************/
6393 :
6394 : //! @cond Doxygen_Suppress
6395 : /**
6396 : * \brief Set percentage of valid (not nodata) pixels.
6397 : *
6398 : * Stores the percentage of valid pixels in the metadata item
6399 : * STATISTICS_VALID_PERCENT
6400 : *
6401 : * @param nSampleCount Number of sampled pixels.
6402 : *
6403 : * @param nValidCount Number of valid pixels.
6404 : */
6405 :
6406 470 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6407 : GUIntBig nValidCount)
6408 : {
6409 470 : if (nValidCount == 0)
6410 : {
6411 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6412 : }
6413 458 : else if (nValidCount == nSampleCount)
6414 : {
6415 415 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6416 : }
6417 : else /* nValidCount < nSampleCount */
6418 : {
6419 43 : char szValue[128] = {0};
6420 :
6421 : /* percentage is only an indicator: limit precision */
6422 43 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6423 43 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6424 :
6425 43 : if (EQUAL(szValue, "100"))
6426 : {
6427 : /* don't set 100 percent valid
6428 : * because some of the sampled pixels were nodata */
6429 0 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6430 : }
6431 : else
6432 : {
6433 43 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6434 : }
6435 : }
6436 470 : }
6437 :
6438 : //! @endcond
6439 :
6440 : /************************************************************************/
6441 : /* ComputeStatistics() */
6442 : /************************************************************************/
6443 :
6444 : /**
6445 : * \brief Compute image statistics.
6446 : *
6447 : * Returns the minimum, maximum, mean and standard deviation of all
6448 : * pixel values in this band. If approximate statistics are sufficient,
6449 : * the bApproxOK flag can be set to true in which case overviews, or a
6450 : * subset of image tiles may be used in computing the statistics.
6451 : *
6452 : * Once computed, the statistics will generally be "set" back on the
6453 : * raster band using SetStatistics().
6454 : *
6455 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6456 : *
6457 : * This method is the same as the C function GDALComputeRasterStatistics().
6458 : *
6459 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6460 : * or a subset of all tiles.
6461 : *
6462 : * @param pdfMin Location into which to load image minimum (may be NULL).
6463 : *
6464 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6465 : *
6466 : * @param pdfMean Location into which to load image mean (may be NULL).
6467 : *
6468 : * @param pdfStdDev Location into which to load image standard deviation
6469 : * (may be NULL).
6470 : *
6471 : * @param pfnProgress a function to call to report progress, or NULL.
6472 : *
6473 : * @param pProgressData application data to pass to the progress function.
6474 : *
6475 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6476 : * is terminated by the user.
6477 : */
6478 :
6479 453 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6480 : double *pdfMax, double *pdfMean,
6481 : double *pdfStdDev,
6482 : GDALProgressFunc pfnProgress,
6483 : void *pProgressData)
6484 :
6485 : {
6486 453 : if (pfnProgress == nullptr)
6487 155 : pfnProgress = GDALDummyProgress;
6488 :
6489 : /* -------------------------------------------------------------------- */
6490 : /* If we have overview bands, use them for statistics. */
6491 : /* -------------------------------------------------------------------- */
6492 453 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6493 : {
6494 : GDALRasterBand *poBand =
6495 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6496 :
6497 3 : if (poBand != this)
6498 : {
6499 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6500 : pdfMean, pdfStdDev,
6501 3 : pfnProgress, pProgressData);
6502 3 : if (eErr == CE_None)
6503 : {
6504 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6505 : {
6506 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6507 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6508 : }
6509 :
6510 : /* transfer metadata from overview band to this */
6511 : const char *pszPercentValid =
6512 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6513 :
6514 3 : if (pszPercentValid != nullptr)
6515 : {
6516 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6517 3 : pszPercentValid);
6518 : }
6519 : }
6520 3 : return eErr;
6521 : }
6522 : }
6523 :
6524 450 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6525 : {
6526 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6527 0 : return CE_Failure;
6528 : }
6529 :
6530 : /* -------------------------------------------------------------------- */
6531 : /* Read actual data and compute statistics. */
6532 : /* -------------------------------------------------------------------- */
6533 : // Using Welford algorithm:
6534 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6535 : // to compute standard deviation in a more numerically robust way than
6536 : // the difference of the sum of square values with the square of the sum.
6537 : // dfMean and dfM2 are updated at each sample.
6538 : // dfM2 is the sum of square of differences to the current mean.
6539 450 : double dfMin = std::numeric_limits<double>::max();
6540 450 : double dfMax = -std::numeric_limits<double>::max();
6541 450 : double dfMean = 0.0;
6542 450 : double dfM2 = 0.0;
6543 :
6544 : GDALRasterIOExtraArg sExtraArg;
6545 450 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6546 :
6547 450 : GDALNoDataValues sNoDataValues(this, eDataType);
6548 450 : GDALRasterBand *poMaskBand = nullptr;
6549 450 : if (!sNoDataValues.bGotNoDataValue)
6550 : {
6551 425 : const int l_nMaskFlags = GetMaskFlags();
6552 441 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
6553 16 : GetColorInterpretation() != GCI_AlphaBand)
6554 : {
6555 16 : poMaskBand = GetMaskBand();
6556 : }
6557 : }
6558 :
6559 450 : bool bSignedByte = false;
6560 450 : if (eDataType == GDT_Byte)
6561 : {
6562 198 : EnablePixelTypeSignedByteWarning(false);
6563 : const char *pszPixelType =
6564 198 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6565 198 : EnablePixelTypeSignedByteWarning(true);
6566 198 : bSignedByte =
6567 198 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6568 : }
6569 :
6570 450 : GUIntBig nSampleCount = 0;
6571 450 : GUIntBig nValidCount = 0;
6572 :
6573 450 : if (bApproxOK && HasArbitraryOverviews())
6574 : {
6575 : /* --------------------------------------------------------------------
6576 : */
6577 : /* Figure out how much the image should be reduced to get an */
6578 : /* approximate value. */
6579 : /* --------------------------------------------------------------------
6580 : */
6581 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6582 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6583 :
6584 0 : int nXReduced = nRasterXSize;
6585 0 : int nYReduced = nRasterYSize;
6586 0 : if (dfReduction > 1.0)
6587 : {
6588 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6589 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6590 :
6591 : // Catch the case of huge resizing ratios here
6592 0 : if (nXReduced == 0)
6593 0 : nXReduced = 1;
6594 0 : if (nYReduced == 0)
6595 0 : nYReduced = 1;
6596 : }
6597 :
6598 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
6599 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6600 :
6601 : const CPLErr eErr =
6602 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6603 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6604 0 : if (eErr != CE_None)
6605 : {
6606 0 : CPLFree(pData);
6607 0 : return eErr;
6608 : }
6609 :
6610 0 : GByte *pabyMaskData = nullptr;
6611 0 : if (poMaskBand)
6612 : {
6613 : pabyMaskData =
6614 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6615 0 : if (!pabyMaskData)
6616 : {
6617 0 : CPLFree(pData);
6618 0 : return CE_Failure;
6619 : }
6620 :
6621 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6622 : pabyMaskData, nXReduced, nYReduced,
6623 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
6624 : {
6625 0 : CPLFree(pData);
6626 0 : CPLFree(pabyMaskData);
6627 0 : return CE_Failure;
6628 : }
6629 : }
6630 :
6631 : /* this isn't the fastest way to do this, but is easier for now */
6632 0 : for (int iY = 0; iY < nYReduced; iY++)
6633 : {
6634 0 : for (int iX = 0; iX < nXReduced; iX++)
6635 : {
6636 0 : const int iOffset = iX + iY * nXReduced;
6637 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6638 0 : continue;
6639 :
6640 0 : bool bValid = true;
6641 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
6642 0 : iOffset, sNoDataValues, bValid);
6643 0 : if (!bValid)
6644 0 : continue;
6645 :
6646 0 : dfMin = std::min(dfMin, dfValue);
6647 0 : dfMax = std::max(dfMax, dfValue);
6648 :
6649 0 : nValidCount++;
6650 0 : const double dfDelta = dfValue - dfMean;
6651 0 : dfMean += dfDelta / nValidCount;
6652 0 : dfM2 += dfDelta * (dfValue - dfMean);
6653 : }
6654 : }
6655 :
6656 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6657 :
6658 0 : CPLFree(pData);
6659 0 : CPLFree(pabyMaskData);
6660 : }
6661 :
6662 : else // No arbitrary overviews.
6663 : {
6664 450 : if (!InitBlockInfo())
6665 0 : return CE_Failure;
6666 :
6667 : /* --------------------------------------------------------------------
6668 : */
6669 : /* Figure out the ratio of blocks we will read to get an */
6670 : /* approximate value. */
6671 : /* --------------------------------------------------------------------
6672 : */
6673 450 : int nSampleRate = 1;
6674 450 : if (bApproxOK)
6675 : {
6676 42 : nSampleRate = static_cast<int>(std::max(
6677 84 : 1.0,
6678 42 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6679 : // We want to avoid probing only the first column of blocks for
6680 : // a square shaped raster, because it is not unlikely that it may
6681 : // be padding only (#6378)
6682 42 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6683 1 : nSampleRate += 1;
6684 : }
6685 450 : if (nSampleRate == 1)
6686 416 : bApproxOK = false;
6687 :
6688 : // Particular case for GDT_Byte that only use integral types for all
6689 : // intermediate computations. Only possible if the number of pixels
6690 : // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6691 : // can fit on a uint64. Should be 99.99999% of cases.
6692 : // For GUInt16, this limits to raster of 4 giga pixels
6693 450 : if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6694 183 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6695 183 : nSampleRate <
6696 183 : GUINTBIG_MAX / (255U * 255U) /
6697 183 : (static_cast<GUInt64>(nBlockXSize) *
6698 183 : static_cast<GUInt64>(nBlockYSize))) ||
6699 267 : (eDataType == GDT_UInt16 &&
6700 29 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6701 29 : nSampleRate <
6702 29 : GUINTBIG_MAX / (65535U * 65535U) /
6703 29 : (static_cast<GUInt64>(nBlockXSize) *
6704 29 : static_cast<GUInt64>(nBlockYSize))))
6705 : {
6706 212 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6707 212 : GUInt32 nMin = nMaxValueType;
6708 212 : GUInt32 nMax = 0;
6709 212 : GUIntBig nSum = 0;
6710 212 : GUIntBig nSumSquare = 0;
6711 : // If no valid nodata, map to invalid value (256 for Byte)
6712 212 : const GUInt32 nNoDataValue =
6713 233 : (sNoDataValues.bGotNoDataValue &&
6714 21 : sNoDataValues.dfNoDataValue >= 0 &&
6715 21 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
6716 21 : fabs(sNoDataValues.dfNoDataValue -
6717 21 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
6718 : 1e-10)) < 1e-10)
6719 233 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
6720 : : nMaxValueType + 1;
6721 :
6722 212 : for (GIntBig iSampleBlock = 0;
6723 12635 : iSampleBlock <
6724 12635 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6725 12423 : iSampleBlock += nSampleRate)
6726 : {
6727 12423 : const int iYBlock =
6728 12423 : static_cast<int>(iSampleBlock / nBlocksPerRow);
6729 12423 : const int iXBlock =
6730 12423 : static_cast<int>(iSampleBlock % nBlocksPerRow);
6731 :
6732 : GDALRasterBlock *const poBlock =
6733 12423 : GetLockedBlockRef(iXBlock, iYBlock);
6734 12424 : if (poBlock == nullptr)
6735 0 : return CE_Failure;
6736 :
6737 12424 : void *const pData = poBlock->GetDataRef();
6738 :
6739 12424 : int nXCheck = 0, nYCheck = 0;
6740 12424 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6741 :
6742 12424 : if (eDataType == GDT_Byte)
6743 : {
6744 : ComputeStatisticsInternal<
6745 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
6746 11954 : f(nXCheck, nBlockXSize, nYCheck,
6747 : static_cast<const GByte *>(pData),
6748 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6749 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6750 : }
6751 : else
6752 : {
6753 : ComputeStatisticsInternal<
6754 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6755 470 : f(nXCheck, nBlockXSize, nYCheck,
6756 : static_cast<const GUInt16 *>(pData),
6757 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6758 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6759 : }
6760 :
6761 12424 : poBlock->DropLock();
6762 :
6763 12422 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
6764 12424 : (static_cast<double>(nBlocksPerRow) *
6765 12424 : nBlocksPerColumn),
6766 : "Compute Statistics", pProgressData))
6767 : {
6768 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
6769 : "User terminated");
6770 0 : return CE_Failure;
6771 : }
6772 : }
6773 :
6774 212 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6775 : {
6776 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6777 0 : return CE_Failure;
6778 : }
6779 :
6780 : /* --------------------------------------------------------------------
6781 : */
6782 : /* Save computed information. */
6783 : /* --------------------------------------------------------------------
6784 : */
6785 212 : if (nValidCount)
6786 203 : dfMean = static_cast<double>(nSum) / nValidCount;
6787 :
6788 : // To avoid potential precision issues when doing the difference,
6789 : // we need to do that computation on 128 bit rather than casting
6790 : // to double
6791 : const GDALUInt128 nTmpForStdDev(
6792 212 : GDALUInt128::Mul(nSumSquare, nValidCount) -
6793 424 : GDALUInt128::Mul(nSum, nSum));
6794 : const double dfStdDev =
6795 212 : nValidCount > 0
6796 212 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6797 212 : : 0.0;
6798 :
6799 212 : if (nValidCount > 0)
6800 : {
6801 203 : if (bApproxOK)
6802 : {
6803 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6804 : }
6805 179 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6806 : {
6807 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6808 : }
6809 203 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
6810 : }
6811 :
6812 212 : SetValidPercent(nSampleCount, nValidCount);
6813 :
6814 : /* --------------------------------------------------------------------
6815 : */
6816 : /* Record results. */
6817 : /* --------------------------------------------------------------------
6818 : */
6819 212 : if (pdfMin != nullptr)
6820 209 : *pdfMin = nValidCount ? nMin : 0;
6821 212 : if (pdfMax != nullptr)
6822 209 : *pdfMax = nValidCount ? nMax : 0;
6823 :
6824 212 : if (pdfMean != nullptr)
6825 205 : *pdfMean = dfMean;
6826 :
6827 212 : if (pdfStdDev != nullptr)
6828 205 : *pdfStdDev = dfStdDev;
6829 :
6830 212 : if (nValidCount > 0)
6831 203 : return CE_None;
6832 :
6833 9 : ReportError(CE_Failure, CPLE_AppDefined,
6834 : "Failed to compute statistics, no valid pixels found "
6835 : "in sampling.");
6836 9 : return CE_Failure;
6837 : }
6838 :
6839 238 : GByte *pabyMaskData = nullptr;
6840 238 : if (poMaskBand)
6841 : {
6842 : pabyMaskData = static_cast<GByte *>(
6843 16 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6844 16 : if (!pabyMaskData)
6845 : {
6846 0 : return CE_Failure;
6847 : }
6848 : }
6849 :
6850 238 : for (GIntBig iSampleBlock = 0;
6851 5489 : iSampleBlock <
6852 5489 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6853 5251 : iSampleBlock += nSampleRate)
6854 : {
6855 5251 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6856 5251 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6857 :
6858 : GDALRasterBlock *const poBlock =
6859 5251 : GetLockedBlockRef(iXBlock, iYBlock);
6860 5251 : if (poBlock == nullptr)
6861 : {
6862 0 : CPLFree(pabyMaskData);
6863 0 : return CE_Failure;
6864 : }
6865 :
6866 5251 : void *const pData = poBlock->GetDataRef();
6867 :
6868 5251 : int nXCheck = 0, nYCheck = 0;
6869 5251 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6870 :
6871 5352 : if (poMaskBand &&
6872 101 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6873 101 : iYBlock * nBlockYSize, nXCheck, nYCheck,
6874 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6875 101 : 0, nBlockXSize, nullptr) != CE_None)
6876 : {
6877 0 : CPLFree(pabyMaskData);
6878 0 : poBlock->DropLock();
6879 0 : return CE_Failure;
6880 : }
6881 :
6882 : // This isn't the fastest way to do this, but is easier for now.
6883 10686 : for (int iY = 0; iY < nYCheck; iY++)
6884 : {
6885 4342140 : for (int iX = 0; iX < nXCheck; iX++)
6886 : {
6887 4336710 : const GPtrDiff_t iOffset =
6888 4336710 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6889 4336710 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6890 109941 : continue;
6891 :
6892 4326840 : bool bValid = true;
6893 : double dfValue =
6894 4326840 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6895 4326840 : sNoDataValues, bValid);
6896 :
6897 4326840 : if (!bValid)
6898 100070 : continue;
6899 :
6900 4226770 : dfMin = std::min(dfMin, dfValue);
6901 4226770 : dfMax = std::max(dfMax, dfValue);
6902 :
6903 4226770 : nValidCount++;
6904 4226770 : const double dfDelta = dfValue - dfMean;
6905 4226770 : dfMean += dfDelta / nValidCount;
6906 4226770 : dfM2 += dfDelta * (dfValue - dfMean);
6907 : }
6908 : }
6909 :
6910 5251 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6911 :
6912 5251 : poBlock->DropLock();
6913 :
6914 5251 : if (!pfnProgress(
6915 5251 : static_cast<double>(iSampleBlock) /
6916 5251 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6917 : "Compute Statistics", pProgressData))
6918 : {
6919 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6920 0 : CPLFree(pabyMaskData);
6921 0 : return CE_Failure;
6922 : }
6923 : }
6924 :
6925 238 : CPLFree(pabyMaskData);
6926 : }
6927 :
6928 238 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6929 : {
6930 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6931 0 : return CE_Failure;
6932 : }
6933 :
6934 : /* -------------------------------------------------------------------- */
6935 : /* Save computed information. */
6936 : /* -------------------------------------------------------------------- */
6937 238 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
6938 :
6939 238 : if (nValidCount > 0)
6940 : {
6941 237 : if (bApproxOK)
6942 : {
6943 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6944 : }
6945 229 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6946 : {
6947 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6948 : }
6949 237 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6950 : }
6951 : else
6952 : {
6953 1 : dfMin = 0.0;
6954 1 : dfMax = 0.0;
6955 : }
6956 :
6957 238 : SetValidPercent(nSampleCount, nValidCount);
6958 :
6959 : /* -------------------------------------------------------------------- */
6960 : /* Record results. */
6961 : /* -------------------------------------------------------------------- */
6962 238 : if (pdfMin != nullptr)
6963 235 : *pdfMin = dfMin;
6964 238 : if (pdfMax != nullptr)
6965 235 : *pdfMax = dfMax;
6966 :
6967 238 : if (pdfMean != nullptr)
6968 233 : *pdfMean = dfMean;
6969 :
6970 238 : if (pdfStdDev != nullptr)
6971 233 : *pdfStdDev = dfStdDev;
6972 :
6973 238 : if (nValidCount > 0)
6974 237 : return CE_None;
6975 :
6976 1 : ReportError(
6977 : CE_Failure, CPLE_AppDefined,
6978 : "Failed to compute statistics, no valid pixels found in sampling.");
6979 1 : return CE_Failure;
6980 : }
6981 :
6982 : /************************************************************************/
6983 : /* GDALComputeRasterStatistics() */
6984 : /************************************************************************/
6985 :
6986 : /**
6987 : * \brief Compute image statistics.
6988 : *
6989 : * @see GDALRasterBand::ComputeStatistics()
6990 : */
6991 :
6992 142 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
6993 : int bApproxOK, double *pdfMin,
6994 : double *pdfMax, double *pdfMean,
6995 : double *pdfStdDev,
6996 : GDALProgressFunc pfnProgress,
6997 : void *pProgressData)
6998 :
6999 : {
7000 142 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7001 :
7002 142 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7003 :
7004 142 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7005 142 : pdfStdDev, pfnProgress, pProgressData);
7006 : }
7007 :
7008 : /************************************************************************/
7009 : /* SetStatistics() */
7010 : /************************************************************************/
7011 :
7012 : /**
7013 : * \brief Set statistics on band.
7014 : *
7015 : * This method can be used to store min/max/mean/standard deviation
7016 : * statistics on a raster band.
7017 : *
7018 : * The default implementation stores them as metadata, and will only work
7019 : * on formats that can save arbitrary metadata. This method cannot detect
7020 : * whether metadata will be properly saved and so may return CE_None even
7021 : * if the statistics will never be saved.
7022 : *
7023 : * This method is the same as the C function GDALSetRasterStatistics().
7024 : *
7025 : * @param dfMin minimum pixel value.
7026 : *
7027 : * @param dfMax maximum pixel value.
7028 : *
7029 : * @param dfMean mean (average) of all pixel values.
7030 : *
7031 : * @param dfStdDev Standard deviation of all pixel values.
7032 : *
7033 : * @return CE_None on success or CE_Failure on failure.
7034 : */
7035 :
7036 468 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7037 : double dfStdDev)
7038 :
7039 : {
7040 468 : char szValue[128] = {0};
7041 :
7042 468 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7043 468 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
7044 :
7045 468 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7046 468 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7047 :
7048 468 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7049 468 : SetMetadataItem("STATISTICS_MEAN", szValue);
7050 :
7051 468 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7052 468 : SetMetadataItem("STATISTICS_STDDEV", szValue);
7053 :
7054 468 : return CE_None;
7055 : }
7056 :
7057 : /************************************************************************/
7058 : /* GDALSetRasterStatistics() */
7059 : /************************************************************************/
7060 :
7061 : /**
7062 : * \brief Set statistics on band.
7063 : *
7064 : * @see GDALRasterBand::SetStatistics()
7065 : */
7066 :
7067 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7068 : double dfMax, double dfMean,
7069 : double dfStdDev)
7070 :
7071 : {
7072 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7073 :
7074 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7075 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7076 : }
7077 :
7078 : /************************************************************************/
7079 : /* ComputeRasterMinMax() */
7080 : /************************************************************************/
7081 :
7082 : template <class T, bool HAS_NODATA>
7083 120175 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7084 : T *pMax)
7085 : {
7086 120175 : T min0 = *pMin;
7087 120175 : T max0 = *pMax;
7088 120175 : T min1 = *pMin;
7089 120175 : T max1 = *pMax;
7090 : size_t i;
7091 214453 : for (i = 0; i + 1 < nElts; i += 2)
7092 : {
7093 81892 : if (!HAS_NODATA || buffer[i] != nodataValue)
7094 : {
7095 94278 : min0 = std::min(min0, buffer[i]);
7096 94278 : max0 = std::max(max0, buffer[i]);
7097 : }
7098 81892 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7099 : {
7100 94278 : min1 = std::min(min1, buffer[i + 1]);
7101 94278 : max1 = std::max(max1, buffer[i + 1]);
7102 : }
7103 : }
7104 120175 : T min = std::min(min0, min1);
7105 120175 : T max = std::max(max0, max1);
7106 120175 : if (i < nElts)
7107 : {
7108 118460 : if (!HAS_NODATA || buffer[i] != nodataValue)
7109 : {
7110 118480 : min = std::min(min, buffer[i]);
7111 118480 : max = std::max(max, buffer[i]);
7112 : }
7113 : }
7114 120175 : *pMin = min;
7115 120175 : *pMax = max;
7116 120175 : }
7117 :
7118 : template <GDALDataType eDataType, bool bSignedByte>
7119 : static void
7120 11076 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7121 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7122 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
7123 : {
7124 11076 : double dfLocalMin = dfMin;
7125 11076 : double dfLocalMax = dfMax;
7126 :
7127 40263 : for (int iY = 0; iY < nYCheck; iY++)
7128 : {
7129 18949417 : for (int iX = 0; iX < nXCheck; iX++)
7130 : {
7131 18920221 : const GPtrDiff_t iOffset =
7132 18920221 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7133 18920221 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7134 3460310 : continue;
7135 18825980 : bool bValid = true;
7136 18825980 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7137 : iOffset, sNoDataValues, bValid);
7138 18825980 : if (!bValid)
7139 3366069 : continue;
7140 :
7141 15459874 : dfLocalMin = std::min(dfLocalMin, dfValue);
7142 15459874 : dfLocalMax = std::max(dfLocalMax, dfValue);
7143 : }
7144 : }
7145 :
7146 11076 : dfMin = dfLocalMin;
7147 11076 : dfMax = dfLocalMax;
7148 11076 : }
7149 :
7150 11076 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
7151 : bool bSignedByte, int nXCheck, int nYCheck,
7152 : int nBlockXSize,
7153 : const GDALNoDataValues &sNoDataValues,
7154 : const GByte *pabyMaskData, double &dfMin,
7155 : double &dfMax)
7156 : {
7157 11076 : switch (eDataType)
7158 : {
7159 0 : case GDT_Unknown:
7160 0 : CPLAssert(false);
7161 : break;
7162 672 : case GDT_Byte:
7163 672 : if (bSignedByte)
7164 : {
7165 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
7166 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7167 : pabyMaskData, dfMin, dfMax);
7168 : }
7169 : else
7170 : {
7171 669 : ComputeMinMaxGeneric<GDT_Byte, false>(
7172 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7173 : pabyMaskData, dfMin, dfMax);
7174 : }
7175 672 : break;
7176 106 : case GDT_Int8:
7177 106 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
7178 : nBlockXSize, sNoDataValues,
7179 : pabyMaskData, dfMin, dfMax);
7180 106 : break;
7181 200 : case GDT_UInt16:
7182 200 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
7183 : nBlockXSize, sNoDataValues,
7184 : pabyMaskData, dfMin, dfMax);
7185 200 : break;
7186 1 : case GDT_Int16:
7187 1 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
7188 : nBlockXSize, sNoDataValues,
7189 : pabyMaskData, dfMin, dfMax);
7190 1 : break;
7191 201 : case GDT_UInt32:
7192 201 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
7193 : nBlockXSize, sNoDataValues,
7194 : pabyMaskData, dfMin, dfMax);
7195 201 : break;
7196 1048 : case GDT_Int32:
7197 1048 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
7198 : nBlockXSize, sNoDataValues,
7199 : pabyMaskData, dfMin, dfMax);
7200 1048 : break;
7201 16 : case GDT_UInt64:
7202 16 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
7203 : nBlockXSize, sNoDataValues,
7204 : pabyMaskData, dfMin, dfMax);
7205 16 : break;
7206 28 : case GDT_Int64:
7207 28 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
7208 : nBlockXSize, sNoDataValues,
7209 : pabyMaskData, dfMin, dfMax);
7210 28 : break;
7211 0 : case GDT_Float16:
7212 0 : ComputeMinMaxGeneric<GDT_Float16, false>(
7213 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7214 : pabyMaskData, dfMin, dfMax);
7215 0 : break;
7216 5425 : case GDT_Float32:
7217 5425 : ComputeMinMaxGeneric<GDT_Float32, false>(
7218 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7219 : pabyMaskData, dfMin, dfMax);
7220 5425 : break;
7221 3269 : case GDT_Float64:
7222 3269 : ComputeMinMaxGeneric<GDT_Float64, false>(
7223 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7224 : pabyMaskData, dfMin, dfMax);
7225 3269 : break;
7226 9 : case GDT_CInt16:
7227 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
7228 : nBlockXSize, sNoDataValues,
7229 : pabyMaskData, dfMin, dfMax);
7230 9 : break;
7231 9 : case GDT_CInt32:
7232 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
7233 : nBlockXSize, sNoDataValues,
7234 : pabyMaskData, dfMin, dfMax);
7235 9 : break;
7236 0 : case GDT_CFloat16:
7237 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
7238 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7239 : pabyMaskData, dfMin, dfMax);
7240 0 : break;
7241 75 : case GDT_CFloat32:
7242 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
7243 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7244 : pabyMaskData, dfMin, dfMax);
7245 75 : break;
7246 17 : case GDT_CFloat64:
7247 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
7248 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7249 : pabyMaskData, dfMin, dfMax);
7250 17 : break;
7251 0 : case GDT_TypeCount:
7252 0 : CPLAssert(false);
7253 : break;
7254 : }
7255 11076 : }
7256 :
7257 709 : static bool ComputeMinMaxGenericIterBlocks(
7258 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
7259 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
7260 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
7261 : double &dfMin, double &dfMax)
7262 :
7263 : {
7264 709 : GByte *pabyMaskData = nullptr;
7265 : int nBlockXSize, nBlockYSize;
7266 709 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7267 :
7268 709 : if (poMaskBand)
7269 : {
7270 : pabyMaskData =
7271 40 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7272 40 : if (!pabyMaskData)
7273 : {
7274 0 : return false;
7275 : }
7276 : }
7277 :
7278 11785 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7279 11076 : iSampleBlock += nSampleRate)
7280 : {
7281 11076 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7282 11076 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7283 :
7284 11076 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7285 11076 : if (poBlock == nullptr)
7286 : {
7287 0 : CPLFree(pabyMaskData);
7288 0 : return false;
7289 : }
7290 :
7291 11076 : void *const pData = poBlock->GetDataRef();
7292 :
7293 11076 : int nXCheck = 0, nYCheck = 0;
7294 11076 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7295 :
7296 11947 : if (poMaskBand &&
7297 871 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7298 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7299 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7300 : nBlockXSize, nullptr) != CE_None)
7301 : {
7302 0 : poBlock->DropLock();
7303 0 : CPLFree(pabyMaskData);
7304 0 : return false;
7305 : }
7306 :
7307 11076 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7308 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
7309 : dfMax);
7310 :
7311 11076 : poBlock->DropLock();
7312 : }
7313 :
7314 709 : CPLFree(pabyMaskData);
7315 709 : return true;
7316 : }
7317 :
7318 : /**
7319 : * \brief Compute the min/max values for a band.
7320 : *
7321 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7322 : * be trusted. If it doesn't work, a subsample of blocks will be read to
7323 : * get an approximate min/max. If the band has a nodata value it will
7324 : * be excluded from the minimum and maximum.
7325 : *
7326 : * If bApprox is FALSE, then all pixels will be read and used to compute
7327 : * an exact range.
7328 : *
7329 : * This method is the same as the C function GDALComputeRasterMinMax().
7330 : *
7331 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7332 : * FALSE.
7333 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7334 : * maximum (adfMinMax[1]) are returned.
7335 : *
7336 : * @return CE_None on success or CE_Failure on failure.
7337 : */
7338 :
7339 1545 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7340 : {
7341 : /* -------------------------------------------------------------------- */
7342 : /* Does the driver already know the min/max? */
7343 : /* -------------------------------------------------------------------- */
7344 1545 : if (bApproxOK)
7345 : {
7346 21 : int bSuccessMin = FALSE;
7347 21 : int bSuccessMax = FALSE;
7348 :
7349 21 : double dfMin = GetMinimum(&bSuccessMin);
7350 21 : double dfMax = GetMaximum(&bSuccessMax);
7351 :
7352 21 : if (bSuccessMin && bSuccessMax)
7353 : {
7354 1 : adfMinMax[0] = dfMin;
7355 1 : adfMinMax[1] = dfMax;
7356 1 : return CE_None;
7357 : }
7358 : }
7359 :
7360 : /* -------------------------------------------------------------------- */
7361 : /* If we have overview bands, use them for min/max. */
7362 : /* -------------------------------------------------------------------- */
7363 : // cppcheck-suppress knownConditionTrueFalse
7364 1544 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7365 : {
7366 : GDALRasterBand *poBand =
7367 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7368 :
7369 0 : if (poBand != this)
7370 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7371 : }
7372 :
7373 : /* -------------------------------------------------------------------- */
7374 : /* Read actual data and compute minimum and maximum. */
7375 : /* -------------------------------------------------------------------- */
7376 1544 : GDALNoDataValues sNoDataValues(this, eDataType);
7377 1544 : GDALRasterBand *poMaskBand = nullptr;
7378 1544 : if (!sNoDataValues.bGotNoDataValue)
7379 : {
7380 1299 : const int l_nMaskFlags = GetMaskFlags();
7381 1339 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7382 40 : GetColorInterpretation() != GCI_AlphaBand)
7383 : {
7384 40 : poMaskBand = GetMaskBand();
7385 : }
7386 : }
7387 :
7388 1544 : bool bSignedByte = false;
7389 1544 : if (eDataType == GDT_Byte)
7390 : {
7391 630 : EnablePixelTypeSignedByteWarning(false);
7392 : const char *pszPixelType =
7393 630 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7394 630 : EnablePixelTypeSignedByteWarning(true);
7395 630 : bSignedByte =
7396 630 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7397 : }
7398 :
7399 : GDALRasterIOExtraArg sExtraArg;
7400 1544 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7401 :
7402 3088 : GUInt32 nMin = (eDataType == GDT_Byte)
7403 1544 : ? 255
7404 : : 65535; // used for GByte & GUInt16 cases
7405 1544 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
7406 1544 : GInt16 nMinInt16 =
7407 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
7408 1544 : GInt16 nMaxInt16 =
7409 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
7410 1544 : double dfMin =
7411 : std::numeric_limits<double>::max(); // used for generic code path
7412 1544 : double dfMax =
7413 : std::numeric_limits<double>::lowest(); // used for generic code path
7414 1544 : const bool bUseOptimizedPath =
7415 2449 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7416 905 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7417 :
7418 : const auto ComputeMinMaxForBlock =
7419 20189 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
7420 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
7421 239505 : int nYCheck)
7422 : {
7423 20189 : if (eDataType == GDT_Byte && !bSignedByte)
7424 : {
7425 : const bool bHasNoData =
7426 11561 : sNoDataValues.bGotNoDataValue &&
7427 29466 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
7428 11561 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
7429 11561 : sNoDataValues.dfNoDataValue;
7430 17905 : const GUInt32 nNoDataValue =
7431 17905 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
7432 : : 0;
7433 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7434 : ComputeStatisticsInternal<GByte,
7435 : /* COMPUTE_OTHER_STATS = */ false>::
7436 17905 : f(nXCheck, nBufferWidth, nYCheck,
7437 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7438 17905 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7439 : }
7440 2284 : else if (eDataType == GDT_UInt16)
7441 : {
7442 : const bool bHasNoData =
7443 83 : sNoDataValues.bGotNoDataValue &&
7444 979 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
7445 83 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
7446 83 : sNoDataValues.dfNoDataValue;
7447 896 : const GUInt32 nNoDataValue =
7448 896 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
7449 : : 0;
7450 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7451 : ComputeStatisticsInternal<GUInt16,
7452 : /* COMPUTE_OTHER_STATS = */ false>::
7453 896 : f(nXCheck, nBufferWidth, nYCheck,
7454 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7455 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7456 : }
7457 1388 : else if (eDataType == GDT_Int16)
7458 : {
7459 : const bool bHasNoData =
7460 1214 : sNoDataValues.bGotNoDataValue &&
7461 2602 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
7462 1214 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
7463 1214 : sNoDataValues.dfNoDataValue;
7464 1388 : if (bHasNoData)
7465 : {
7466 1214 : const int16_t nNoDataValue =
7467 1214 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
7468 120117 : for (int iY = 0; iY < nYCheck; iY++)
7469 : {
7470 118903 : ComputeMinMax<int16_t, true>(
7471 118903 : static_cast<const int16_t *>(pData) +
7472 118903 : static_cast<size_t>(iY) * nBufferWidth,
7473 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7474 : }
7475 : }
7476 : else
7477 : {
7478 1446 : for (int iY = 0; iY < nYCheck; iY++)
7479 : {
7480 1272 : ComputeMinMax<int16_t, false>(
7481 1272 : static_cast<const int16_t *>(pData) +
7482 1272 : static_cast<size_t>(iY) * nBufferWidth,
7483 : nXCheck, 0, &nMinInt16, &nMaxInt16);
7484 : }
7485 : }
7486 : }
7487 20189 : };
7488 :
7489 1544 : if (bApproxOK && HasArbitraryOverviews())
7490 : {
7491 : /* --------------------------------------------------------------------
7492 : */
7493 : /* Figure out how much the image should be reduced to get an */
7494 : /* approximate value. */
7495 : /* --------------------------------------------------------------------
7496 : */
7497 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7498 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7499 :
7500 0 : int nXReduced = nRasterXSize;
7501 0 : int nYReduced = nRasterYSize;
7502 0 : if (dfReduction > 1.0)
7503 : {
7504 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7505 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7506 :
7507 : // Catch the case of huge resizing ratios here
7508 0 : if (nXReduced == 0)
7509 0 : nXReduced = 1;
7510 0 : if (nYReduced == 0)
7511 0 : nYReduced = 1;
7512 : }
7513 :
7514 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
7515 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7516 :
7517 : const CPLErr eErr =
7518 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7519 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7520 0 : if (eErr != CE_None)
7521 : {
7522 0 : CPLFree(pData);
7523 0 : return eErr;
7524 : }
7525 :
7526 0 : GByte *pabyMaskData = nullptr;
7527 0 : if (poMaskBand)
7528 : {
7529 : pabyMaskData =
7530 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7531 0 : if (!pabyMaskData)
7532 : {
7533 0 : CPLFree(pData);
7534 0 : return CE_Failure;
7535 : }
7536 :
7537 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7538 : pabyMaskData, nXReduced, nYReduced,
7539 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
7540 : {
7541 0 : CPLFree(pData);
7542 0 : CPLFree(pabyMaskData);
7543 0 : return CE_Failure;
7544 : }
7545 : }
7546 :
7547 0 : if (bUseOptimizedPath)
7548 : {
7549 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7550 : }
7551 : else
7552 : {
7553 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
7554 : nYReduced, nXReduced, sNoDataValues,
7555 : pabyMaskData, dfMin, dfMax);
7556 : }
7557 :
7558 0 : CPLFree(pData);
7559 0 : CPLFree(pabyMaskData);
7560 : }
7561 :
7562 : else // No arbitrary overviews
7563 : {
7564 1544 : if (!InitBlockInfo())
7565 0 : return CE_Failure;
7566 :
7567 : /* --------------------------------------------------------------------
7568 : */
7569 : /* Figure out the ratio of blocks we will read to get an */
7570 : /* approximate value. */
7571 : /* --------------------------------------------------------------------
7572 : */
7573 1544 : int nSampleRate = 1;
7574 :
7575 1544 : if (bApproxOK)
7576 : {
7577 20 : nSampleRate = static_cast<int>(std::max(
7578 40 : 1.0,
7579 20 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7580 : // We want to avoid probing only the first column of blocks for
7581 : // a square shaped raster, because it is not unlikely that it may
7582 : // be padding only (#6378).
7583 20 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7584 0 : nSampleRate += 1;
7585 : }
7586 :
7587 1544 : if (bUseOptimizedPath)
7588 : {
7589 835 : for (GIntBig iSampleBlock = 0;
7590 20949 : iSampleBlock <
7591 20949 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7592 20114 : iSampleBlock += nSampleRate)
7593 : {
7594 20190 : const int iYBlock =
7595 20190 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7596 20190 : const int iXBlock =
7597 20190 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7598 :
7599 20190 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7600 20190 : if (poBlock == nullptr)
7601 1 : return CE_Failure;
7602 :
7603 20189 : void *const pData = poBlock->GetDataRef();
7604 :
7605 20189 : int nXCheck = 0, nYCheck = 0;
7606 20189 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7607 :
7608 20189 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7609 :
7610 20189 : poBlock->DropLock();
7611 :
7612 20189 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7613 4023 : nMax == 255)
7614 75 : break;
7615 : }
7616 : }
7617 : else
7618 : {
7619 709 : const GIntBig nTotalBlocks =
7620 709 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7621 709 : if (!ComputeMinMaxGenericIterBlocks(
7622 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7623 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
7624 : {
7625 0 : return CE_Failure;
7626 : }
7627 : }
7628 : }
7629 :
7630 1543 : if (bUseOptimizedPath)
7631 : {
7632 834 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7633 : {
7634 732 : dfMin = nMin;
7635 732 : dfMax = nMax;
7636 : }
7637 102 : else if (eDataType == GDT_Int16)
7638 : {
7639 102 : dfMin = nMinInt16;
7640 102 : dfMax = nMaxInt16;
7641 : }
7642 : }
7643 :
7644 1543 : if (dfMin > dfMax)
7645 : {
7646 8 : adfMinMax[0] = 0;
7647 8 : adfMinMax[1] = 0;
7648 8 : ReportError(
7649 : CE_Failure, CPLE_AppDefined,
7650 : "Failed to compute min/max, no valid pixels found in sampling.");
7651 8 : return CE_Failure;
7652 : }
7653 :
7654 1535 : adfMinMax[0] = dfMin;
7655 1535 : adfMinMax[1] = dfMax;
7656 :
7657 1535 : return CE_None;
7658 : }
7659 :
7660 : /************************************************************************/
7661 : /* GDALComputeRasterMinMax() */
7662 : /************************************************************************/
7663 :
7664 : /**
7665 : * \brief Compute the min/max values for a band.
7666 : *
7667 : * @see GDALRasterBand::ComputeRasterMinMax()
7668 : *
7669 : * @note Prior to GDAL 3.6, this function returned void
7670 : */
7671 :
7672 1467 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7673 : double adfMinMax[2])
7674 :
7675 : {
7676 1467 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7677 :
7678 1467 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7679 1467 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7680 : }
7681 :
7682 : /************************************************************************/
7683 : /* ComputeRasterMinMaxLocation() */
7684 : /************************************************************************/
7685 :
7686 : /**
7687 : * \brief Compute the min/max values for a band, and their location.
7688 : *
7689 : * Pixels whose value matches the nodata value or are masked by the mask
7690 : * band are ignored.
7691 : *
7692 : * If the minimum or maximum value is hit in several locations, it is not
7693 : * specified which one will be returned.
7694 : *
7695 : * @param[out] pdfMin Pointer to the minimum value.
7696 : * @param[out] pdfMax Pointer to the maximum value.
7697 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7698 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7699 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7700 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7701 : *
7702 : * @return CE_None in case of success, CE_Warning if there are no valid values,
7703 : * CE_Failure in case of error.
7704 : *
7705 : * @since GDAL 3.11
7706 : */
7707 :
7708 8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7709 : double *pdfMax, int *pnMinX,
7710 : int *pnMinY, int *pnMaxX,
7711 : int *pnMaxY)
7712 : {
7713 8 : int nMinX = -1;
7714 8 : int nMinY = -1;
7715 8 : int nMaxX = -1;
7716 8 : int nMaxY = -1;
7717 8 : double dfMin = std::numeric_limits<double>::infinity();
7718 8 : double dfMax = -std::numeric_limits<double>::infinity();
7719 8 : if (pdfMin)
7720 5 : *pdfMin = dfMin;
7721 8 : if (pdfMax)
7722 5 : *pdfMax = dfMax;
7723 8 : if (pnMinX)
7724 6 : *pnMinX = nMinX;
7725 8 : if (pnMinY)
7726 6 : *pnMinY = nMinY;
7727 8 : if (pnMaxX)
7728 6 : *pnMaxX = nMaxX;
7729 8 : if (pnMaxY)
7730 6 : *pnMaxY = nMaxY;
7731 :
7732 8 : if (GDALDataTypeIsComplex(eDataType))
7733 : {
7734 0 : CPLError(CE_Failure, CPLE_NotSupported,
7735 : "Complex data type not supported");
7736 0 : return CE_Failure;
7737 : }
7738 :
7739 8 : if (!InitBlockInfo())
7740 0 : return CE_Failure;
7741 :
7742 8 : GDALNoDataValues sNoDataValues(this, eDataType);
7743 8 : GDALRasterBand *poMaskBand = nullptr;
7744 8 : if (!sNoDataValues.bGotNoDataValue)
7745 : {
7746 8 : const int l_nMaskFlags = GetMaskFlags();
7747 9 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7748 1 : GetColorInterpretation() != GCI_AlphaBand)
7749 : {
7750 1 : poMaskBand = GetMaskBand();
7751 : }
7752 : }
7753 :
7754 8 : bool bSignedByte = false;
7755 8 : if (eDataType == GDT_Byte)
7756 : {
7757 7 : EnablePixelTypeSignedByteWarning(false);
7758 : const char *pszPixelType =
7759 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7760 7 : EnablePixelTypeSignedByteWarning(true);
7761 7 : bSignedByte =
7762 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7763 : }
7764 :
7765 8 : GByte *pabyMaskData = nullptr;
7766 8 : if (poMaskBand)
7767 : {
7768 : pabyMaskData =
7769 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7770 1 : if (!pabyMaskData)
7771 : {
7772 0 : return CE_Failure;
7773 : }
7774 : }
7775 :
7776 8 : const GIntBig nTotalBlocks =
7777 8 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7778 8 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7779 8 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7780 16 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7781 : {
7782 11 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7783 11 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7784 :
7785 11 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7786 11 : if (poBlock == nullptr)
7787 : {
7788 0 : CPLFree(pabyMaskData);
7789 0 : return CE_Failure;
7790 : }
7791 :
7792 11 : void *const pData = poBlock->GetDataRef();
7793 :
7794 11 : int nXCheck = 0, nYCheck = 0;
7795 11 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7796 :
7797 13 : if (poMaskBand &&
7798 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7799 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7800 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7801 2 : nBlockXSize, nullptr) != CE_None)
7802 : {
7803 0 : poBlock->DropLock();
7804 0 : CPLFree(pabyMaskData);
7805 0 : return CE_Failure;
7806 : }
7807 :
7808 11 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7809 : {
7810 4 : for (int iY = 0; iY < nYCheck; ++iY)
7811 : {
7812 6 : for (int iX = 0; iX < nXCheck; ++iX)
7813 : {
7814 4 : const GPtrDiff_t iOffset =
7815 4 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7816 4 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7817 2 : continue;
7818 2 : bool bValid = true;
7819 : double dfValue =
7820 2 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
7821 : sNoDataValues, bValid);
7822 2 : if (!bValid)
7823 0 : continue;
7824 2 : if (dfValue < dfMin)
7825 : {
7826 2 : dfMin = dfValue;
7827 2 : nMinX = iXBlock * nBlockXSize + iX;
7828 2 : nMinY = iYBlock * nBlockYSize + iY;
7829 : }
7830 2 : if (dfValue > dfMax)
7831 : {
7832 1 : dfMax = dfValue;
7833 1 : nMaxX = iXBlock * nBlockXSize + iX;
7834 1 : nMaxY = iYBlock * nBlockYSize + iY;
7835 : }
7836 : }
7837 2 : }
7838 : }
7839 : else
7840 : {
7841 9 : size_t pos_min = 0;
7842 9 : size_t pos_max = 0;
7843 9 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7844 9 : if (bNeedsMin && bNeedsMax)
7845 : {
7846 10 : std::tie(pos_min, pos_max) = gdal::minmax_element(
7847 5 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7848 5 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7849 10 : sNoDataValues.dfNoDataValue);
7850 : }
7851 4 : else if (bNeedsMin)
7852 : {
7853 1 : pos_min = gdal::min_element(
7854 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7855 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7856 : sNoDataValues.dfNoDataValue);
7857 : }
7858 3 : else if (bNeedsMax)
7859 : {
7860 2 : pos_max = gdal::max_element(
7861 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7862 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7863 : sNoDataValues.dfNoDataValue);
7864 : }
7865 :
7866 9 : if (bNeedsMin)
7867 : {
7868 6 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7869 6 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7870 6 : bool bValid = true;
7871 : const double dfMinValueBlock =
7872 6 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
7873 : sNoDataValues, bValid);
7874 6 : if (bValid && dfMinValueBlock < dfMin)
7875 : {
7876 5 : dfMin = dfMinValueBlock;
7877 5 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
7878 5 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
7879 : }
7880 : }
7881 :
7882 9 : if (bNeedsMax)
7883 : {
7884 7 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7885 7 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7886 7 : bool bValid = true;
7887 : const double dfMaxValueBlock =
7888 7 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
7889 : sNoDataValues, bValid);
7890 7 : if (bValid && dfMaxValueBlock > dfMax)
7891 : {
7892 5 : dfMax = dfMaxValueBlock;
7893 5 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7894 5 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7895 : }
7896 : }
7897 : }
7898 :
7899 11 : poBlock->DropLock();
7900 :
7901 11 : if (eDataType == GDT_Byte)
7902 : {
7903 10 : if (bNeedsMin && dfMin == 0)
7904 : {
7905 1 : bNeedsMin = false;
7906 : }
7907 10 : if (bNeedsMax && dfMax == 255)
7908 : {
7909 4 : bNeedsMax = false;
7910 : }
7911 10 : if (!bNeedsMin && !bNeedsMax)
7912 : {
7913 3 : break;
7914 : }
7915 : }
7916 : }
7917 :
7918 8 : CPLFree(pabyMaskData);
7919 :
7920 8 : if (pdfMin)
7921 5 : *pdfMin = dfMin;
7922 8 : if (pdfMax)
7923 5 : *pdfMax = dfMax;
7924 8 : if (pnMinX)
7925 6 : *pnMinX = nMinX;
7926 8 : if (pnMinY)
7927 6 : *pnMinY = nMinY;
7928 8 : if (pnMaxX)
7929 6 : *pnMaxX = nMaxX;
7930 8 : if (pnMaxY)
7931 6 : *pnMaxY = nMaxY;
7932 8 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
7933 8 : : CE_None;
7934 : }
7935 :
7936 : /************************************************************************/
7937 : /* GDALComputeRasterMinMaxLocation() */
7938 : /************************************************************************/
7939 :
7940 : /**
7941 : * \brief Compute the min/max values for a band, and their location.
7942 : *
7943 : * @see GDALRasterBand::ComputeRasterMinMax()
7944 : * @since GDAL 3.11
7945 : */
7946 :
7947 6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
7948 : double *pdfMax, int *pnMinX, int *pnMinY,
7949 : int *pnMaxX, int *pnMaxY)
7950 :
7951 : {
7952 6 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
7953 :
7954 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7955 6 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
7956 6 : pnMaxX, pnMaxY);
7957 : }
7958 :
7959 : /************************************************************************/
7960 : /* SetDefaultHistogram() */
7961 : /************************************************************************/
7962 :
7963 : /* FIXME : add proper documentation */
7964 : /**
7965 : * \brief Set default histogram.
7966 : *
7967 : * This method is the same as the C function GDALSetDefaultHistogram() and
7968 : * GDALSetDefaultHistogramEx()
7969 : */
7970 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
7971 : double /* dfMax */,
7972 : int /* nBuckets */,
7973 : GUIntBig * /* panHistogram */)
7974 :
7975 : {
7976 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
7977 0 : ReportError(CE_Failure, CPLE_NotSupported,
7978 : "SetDefaultHistogram() not implemented for this format.");
7979 :
7980 0 : return CE_Failure;
7981 : }
7982 :
7983 : /************************************************************************/
7984 : /* GDALSetDefaultHistogram() */
7985 : /************************************************************************/
7986 :
7987 : /**
7988 : * \brief Set default histogram.
7989 : *
7990 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
7991 : * 2 billion.
7992 : *
7993 : * @see GDALRasterBand::SetDefaultHistogram()
7994 : * @see GDALSetRasterHistogramEx()
7995 : */
7996 :
7997 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
7998 : double dfMax, int nBuckets,
7999 : int *panHistogram)
8000 :
8001 : {
8002 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8003 :
8004 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8005 :
8006 : GUIntBig *panHistogramTemp =
8007 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8008 0 : if (panHistogramTemp == nullptr)
8009 : {
8010 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8011 : "Out of memory in GDALSetDefaultHistogram().");
8012 0 : return CE_Failure;
8013 : }
8014 :
8015 0 : for (int i = 0; i < nBuckets; ++i)
8016 : {
8017 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8018 : }
8019 :
8020 : const CPLErr eErr =
8021 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8022 :
8023 0 : CPLFree(panHistogramTemp);
8024 :
8025 0 : return eErr;
8026 : }
8027 :
8028 : /************************************************************************/
8029 : /* GDALSetDefaultHistogramEx() */
8030 : /************************************************************************/
8031 :
8032 : /**
8033 : * \brief Set default histogram.
8034 : *
8035 : * @see GDALRasterBand::SetDefaultHistogram()
8036 : *
8037 : * @since GDAL 2.0
8038 : */
8039 :
8040 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8041 : double dfMin, double dfMax,
8042 : int nBuckets,
8043 : GUIntBig *panHistogram)
8044 :
8045 : {
8046 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8047 :
8048 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8049 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8050 : }
8051 :
8052 : /************************************************************************/
8053 : /* GetDefaultRAT() */
8054 : /************************************************************************/
8055 :
8056 : /**
8057 : * \brief Fetch default Raster Attribute Table.
8058 : *
8059 : * A RAT will be returned if there is a default one associated with the
8060 : * band, otherwise NULL is returned. The returned RAT is owned by the
8061 : * band and should not be deleted by the application.
8062 : *
8063 : * This method is the same as the C function GDALGetDefaultRAT().
8064 : *
8065 : * @return NULL, or a pointer to an internal RAT owned by the band.
8066 : */
8067 :
8068 150 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8069 :
8070 : {
8071 150 : return nullptr;
8072 : }
8073 :
8074 : /************************************************************************/
8075 : /* GDALGetDefaultRAT() */
8076 : /************************************************************************/
8077 :
8078 : /**
8079 : * \brief Fetch default Raster Attribute Table.
8080 : *
8081 : * @see GDALRasterBand::GetDefaultRAT()
8082 : */
8083 :
8084 1047 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8085 :
8086 : {
8087 1047 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8088 :
8089 1047 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8090 1047 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8091 : }
8092 :
8093 : /************************************************************************/
8094 : /* SetDefaultRAT() */
8095 : /************************************************************************/
8096 :
8097 : /**
8098 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8099 : * \brief Set default Raster Attribute Table.
8100 : *
8101 : * Associates a default RAT with the band. If not implemented for the
8102 : * format a CPLE_NotSupported error will be issued. If successful a copy
8103 : * of the RAT is made, the original remains owned by the caller.
8104 : *
8105 : * This method is the same as the C function GDALSetDefaultRAT().
8106 : *
8107 : * @param poRAT the RAT to assign to the band.
8108 : *
8109 : * @return CE_None on success or CE_Failure if unsupported or otherwise
8110 : * failing.
8111 : */
8112 :
8113 : /**/
8114 : /**/
8115 :
8116 : CPLErr
8117 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8118 : {
8119 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8120 : {
8121 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
8122 0 : ReportError(CE_Failure, CPLE_NotSupported,
8123 : "SetDefaultRAT() not implemented for this format.");
8124 0 : CPLPopErrorHandler();
8125 : }
8126 0 : return CE_Failure;
8127 : }
8128 :
8129 : /************************************************************************/
8130 : /* GDALSetDefaultRAT() */
8131 : /************************************************************************/
8132 :
8133 : /**
8134 : * \brief Set default Raster Attribute Table.
8135 : *
8136 : * @see GDALRasterBand::GDALSetDefaultRAT()
8137 : */
8138 :
8139 18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
8140 : GDALRasterAttributeTableH hRAT)
8141 :
8142 : {
8143 18 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
8144 :
8145 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8146 :
8147 18 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
8148 : }
8149 :
8150 : /************************************************************************/
8151 : /* GetMaskBand() */
8152 : /************************************************************************/
8153 :
8154 : /**
8155 : * \brief Return the mask band associated with the band.
8156 : *
8157 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8158 : * that returns one of four default implementations :
8159 : * <ul>
8160 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8161 : * </li>
8162 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8163 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8164 : * GMF_NODATA | GMF_PER_DATASET.
8165 : * </li>
8166 : * <li>If the band has a nodata value set, an instance of the new
8167 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8168 : * GMF_NODATA.
8169 : * </li>
8170 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
8171 : * to apply to this band (specific rules yet to be determined) and that is of
8172 : * type GDT_Byte then that alpha band will be returned, and the flags
8173 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8174 : * </li>
8175 : * <li>If neither of the above apply, an instance of the new
8176 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8177 : * pixels. The null flags will return GMF_ALL_VALID.
8178 : * </li>
8179 : * </ul>
8180 : *
8181 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
8182 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
8183 : *
8184 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8185 : * dataset, with the same name as the main dataset and suffixed with .msk,
8186 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8187 : * main dataset.
8188 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8189 : * level, where xx matches the band number of a band of the main dataset. The
8190 : * value of those items is a combination of the flags GMF_ALL_VALID,
8191 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8192 : * a band, then the other rules explained above will be used to generate a
8193 : * on-the-fly mask band.
8194 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8195 : *
8196 : * This method is the same as the C function GDALGetMaskBand().
8197 : *
8198 : * @return a valid mask band.
8199 : *
8200 : * @since GDAL 1.5.0
8201 : *
8202 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8203 : *
8204 : */
8205 692241 : GDALRasterBand *GDALRasterBand::GetMaskBand()
8206 :
8207 : {
8208 180055 : const auto HasNoData = [this]()
8209 : {
8210 59735 : int bHaveNoDataRaw = FALSE;
8211 59735 : bool bHaveNoData = false;
8212 59735 : if (eDataType == GDT_Int64)
8213 : {
8214 64 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
8215 64 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8216 : }
8217 59671 : else if (eDataType == GDT_UInt64)
8218 : {
8219 46 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
8220 46 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8221 : }
8222 : else
8223 : {
8224 59625 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
8225 58961 : if (bHaveNoDataRaw &&
8226 58961 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
8227 : {
8228 873 : bHaveNoData = true;
8229 : }
8230 : }
8231 58791 : return bHaveNoData;
8232 692241 : };
8233 :
8234 692241 : if (poMask != nullptr)
8235 : {
8236 667984 : if (poMask.IsOwned())
8237 : {
8238 301074 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
8239 : {
8240 31681 : if (HasNoData())
8241 : {
8242 9 : InvalidateMaskBand();
8243 : }
8244 : }
8245 270574 : else if (auto poNoDataMaskBand =
8246 277009 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
8247 : {
8248 195 : int bHaveNoDataRaw = FALSE;
8249 195 : bool bIsSame = false;
8250 195 : if (eDataType == GDT_Int64)
8251 9 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
8252 11 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
8253 2 : bHaveNoDataRaw;
8254 186 : else if (eDataType == GDT_UInt64)
8255 9 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8256 11 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8257 2 : bHaveNoDataRaw;
8258 : else
8259 : {
8260 : const double dfNoDataValue =
8261 177 : GetNoDataValue(&bHaveNoDataRaw);
8262 177 : if (bHaveNoDataRaw)
8263 : {
8264 174 : bIsSame =
8265 174 : std::isnan(dfNoDataValue)
8266 174 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8267 148 : : poNoDataMaskBand->m_dfNoDataValue ==
8268 : dfNoDataValue;
8269 : }
8270 : }
8271 195 : if (!bIsSame)
8272 23 : InvalidateMaskBand();
8273 : }
8274 : }
8275 :
8276 684324 : if (poMask)
8277 687011 : return poMask.get();
8278 : }
8279 :
8280 : /* -------------------------------------------------------------------- */
8281 : /* Check for a mask in a .msk file. */
8282 : /* -------------------------------------------------------------------- */
8283 28123 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8284 : {
8285 46 : poMask.reset(poDS->oOvManager.GetMaskBand(nBand), false);
8286 46 : if (poMask != nullptr)
8287 : {
8288 44 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8289 44 : return poMask.get();
8290 : }
8291 : }
8292 :
8293 : /* -------------------------------------------------------------------- */
8294 : /* Check for NODATA_VALUES metadata. */
8295 : /* -------------------------------------------------------------------- */
8296 28079 : if (poDS != nullptr)
8297 : {
8298 : const char *pszGDALNoDataValues =
8299 28066 : poDS->GetMetadataItem("NODATA_VALUES");
8300 28066 : if (pszGDALNoDataValues != nullptr)
8301 : {
8302 66 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
8303 : pszGDALNoDataValues, " ", FALSE, FALSE);
8304 :
8305 : // Make sure we have as many values as bands.
8306 132 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
8307 66 : poDS->GetRasterCount() != 0)
8308 : {
8309 : // Make sure that all bands have the same data type
8310 : // This is clearly not a fundamental condition, just a
8311 : // condition to make implementation easier.
8312 66 : GDALDataType eDT = GDT_Unknown;
8313 66 : int i = 0; // Used after for.
8314 263 : for (; i < poDS->GetRasterCount(); ++i)
8315 : {
8316 197 : if (i == 0)
8317 66 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8318 131 : else if (eDT !=
8319 131 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
8320 : {
8321 0 : break;
8322 : }
8323 : }
8324 66 : if (i == poDS->GetRasterCount())
8325 : {
8326 66 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8327 : try
8328 : {
8329 66 : poMask.reset(new GDALNoDataValuesMaskBand(poDS), true);
8330 : }
8331 0 : catch (const std::bad_alloc &)
8332 : {
8333 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8334 0 : poMask.reset();
8335 : }
8336 66 : CSLDestroy(papszGDALNoDataValues);
8337 66 : return poMask.get();
8338 : }
8339 : else
8340 : {
8341 0 : ReportError(CE_Warning, CPLE_AppDefined,
8342 : "All bands should have the same type in "
8343 : "order the NODATA_VALUES metadata item "
8344 : "to be used as a mask.");
8345 : }
8346 : }
8347 : else
8348 : {
8349 0 : ReportError(
8350 : CE_Warning, CPLE_AppDefined,
8351 : "NODATA_VALUES metadata item doesn't have the same number "
8352 : "of values as the number of bands. "
8353 : "Ignoring it for mask.");
8354 : }
8355 :
8356 0 : CSLDestroy(papszGDALNoDataValues);
8357 : }
8358 : }
8359 :
8360 : /* -------------------------------------------------------------------- */
8361 : /* Check for nodata case. */
8362 : /* -------------------------------------------------------------------- */
8363 28013 : if (HasNoData())
8364 : {
8365 895 : nMaskFlags = GMF_NODATA;
8366 : try
8367 : {
8368 895 : poMask.reset(new GDALNoDataMaskBand(this), true);
8369 : }
8370 0 : catch (const std::bad_alloc &)
8371 : {
8372 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8373 0 : poMask.reset();
8374 : }
8375 895 : return poMask.get();
8376 : }
8377 :
8378 : /* -------------------------------------------------------------------- */
8379 : /* Check for alpha case. */
8380 : /* -------------------------------------------------------------------- */
8381 27106 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8382 54778 : this == poDS->GetRasterBand(1) &&
8383 554 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8384 : {
8385 198 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8386 : {
8387 154 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8388 154 : poMask.reset(poDS->GetRasterBand(2), false);
8389 154 : return poMask.get();
8390 : }
8391 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8392 : {
8393 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8394 : try
8395 : {
8396 23 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(2)),
8397 : true);
8398 : }
8399 0 : catch (const std::bad_alloc &)
8400 : {
8401 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8402 0 : poMask.reset();
8403 : }
8404 23 : return poMask.get();
8405 : }
8406 : }
8407 :
8408 26929 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8409 2716 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8410 54516 : this == poDS->GetRasterBand(3)) &&
8411 2117 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8412 : {
8413 1247 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8414 : {
8415 1200 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8416 1200 : poMask.reset(poDS->GetRasterBand(4), false);
8417 1200 : return poMask.get();
8418 : }
8419 47 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8420 : {
8421 35 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8422 : try
8423 : {
8424 35 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(4)),
8425 : true);
8426 : }
8427 0 : catch (const std::bad_alloc &)
8428 : {
8429 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8430 0 : poMask.reset();
8431 : }
8432 35 : return poMask.get();
8433 : }
8434 : }
8435 :
8436 : /* -------------------------------------------------------------------- */
8437 : /* Fallback to all valid case. */
8438 : /* -------------------------------------------------------------------- */
8439 25706 : nMaskFlags = GMF_ALL_VALID;
8440 : try
8441 : {
8442 25706 : poMask.reset(new GDALAllValidMaskBand(this), true);
8443 : }
8444 0 : catch (const std::bad_alloc &)
8445 : {
8446 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8447 0 : poMask.reset();
8448 : }
8449 :
8450 25706 : return poMask.get();
8451 : }
8452 :
8453 : /************************************************************************/
8454 : /* GDALGetMaskBand() */
8455 : /************************************************************************/
8456 :
8457 : /**
8458 : * \brief Return the mask band associated with the band.
8459 : *
8460 : * @see GDALRasterBand::GetMaskBand()
8461 : */
8462 :
8463 10950 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8464 :
8465 : {
8466 10950 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8467 :
8468 10950 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8469 10950 : return poBand->GetMaskBand();
8470 : }
8471 :
8472 : /************************************************************************/
8473 : /* GetMaskFlags() */
8474 : /************************************************************************/
8475 :
8476 : /**
8477 : * \brief Return the status flags of the mask band associated with the band.
8478 : *
8479 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8480 : * the following available definitions that may be extended in the future:
8481 : * <ul>
8482 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8483 : * 255. When used this will normally be the only flag set.
8484 : * </li>
8485 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8486 : * dataset.
8487 : * </li>
8488 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8489 : * and may have values other than 0 and 255.
8490 : * </li>
8491 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8492 : * nodata values. (mutually exclusive of GMF_ALPHA)
8493 : * </li>
8494 : * </ul>
8495 : *
8496 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8497 : * that returns one of four default implementations:
8498 : * <ul>
8499 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8500 : * </li>
8501 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8502 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8503 : * GMF_NODATA | GMF_PER_DATASET.
8504 : * </li>
8505 : * <li>If the band has a nodata value set, an instance of the new
8506 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8507 : * GMF_NODATA.
8508 : * </li>
8509 : * <li>If there is no nodata value, but the dataset has an alpha band that
8510 : * seems to apply to this band (specific rules yet to be determined) and that is
8511 : * of type GDT_Byte then that alpha band will be returned, and the flags
8512 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8513 : * </li>
8514 : * <li>If neither of the above apply, an instance of the new
8515 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8516 : * pixels. The null flags will return GMF_ALL_VALID.
8517 : * </li>
8518 : * </ul>
8519 : *
8520 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8521 : * dataset, with the same name as the main dataset and suffixed with .msk,
8522 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8523 : * main dataset.
8524 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8525 : * level, where xx matches the band number of a band of the main dataset. The
8526 : * value of those items is a combination of the flags GMF_ALL_VALID,
8527 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8528 : * a band, then the other rules explained above will be used to generate a
8529 : * on-the-fly mask band.
8530 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8531 : *
8532 : * This method is the same as the C function GDALGetMaskFlags().
8533 : *
8534 : * @since GDAL 1.5.0
8535 : *
8536 : * @return a valid mask band.
8537 : *
8538 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8539 : *
8540 : */
8541 79495 : int GDALRasterBand::GetMaskFlags()
8542 :
8543 : {
8544 : // If we don't have a band yet, force this now so that the masks value
8545 : // will be initialized.
8546 :
8547 79495 : if (poMask == nullptr)
8548 26879 : GetMaskBand();
8549 :
8550 79490 : return nMaskFlags;
8551 : }
8552 :
8553 : /************************************************************************/
8554 : /* GDALGetMaskFlags() */
8555 : /************************************************************************/
8556 :
8557 : /**
8558 : * \brief Return the status flags of the mask band associated with the band.
8559 : *
8560 : * @see GDALRasterBand::GetMaskFlags()
8561 : */
8562 :
8563 6329 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8564 :
8565 : {
8566 6329 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8567 :
8568 6329 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8569 6329 : return poBand->GetMaskFlags();
8570 : }
8571 :
8572 : /************************************************************************/
8573 : /* InvalidateMaskBand() */
8574 : /************************************************************************/
8575 :
8576 : //! @cond Doxygen_Suppress
8577 1202240 : void GDALRasterBand::InvalidateMaskBand()
8578 : {
8579 1202240 : poMask.reset();
8580 1202230 : nMaskFlags = 0;
8581 1202230 : }
8582 :
8583 : //! @endcond
8584 :
8585 : /************************************************************************/
8586 : /* CreateMaskBand() */
8587 : /************************************************************************/
8588 :
8589 : /**
8590 : * \brief Adds a mask band to the current band
8591 : *
8592 : * The default implementation of the CreateMaskBand() method is implemented
8593 : * based on similar rules to the .ovr handling implemented using the
8594 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8595 : * be created with the same basename as the original file, and it will have
8596 : * as many bands as the original image (or just one for GMF_PER_DATASET).
8597 : * The mask images will be deflate compressed tiled images with the same
8598 : * block size as the original image if possible.
8599 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8600 : * level, where xx matches the band number of a band of the main dataset. The
8601 : * value of those items will be the one of the nFlagsIn parameter.
8602 : *
8603 : * Note that if you got a mask band with a previous call to GetMaskBand(),
8604 : * it might be invalidated by CreateMaskBand(). So you have to call
8605 : * GetMaskBand() again.
8606 : *
8607 : * This method is the same as the C function GDALCreateMaskBand().
8608 : *
8609 : * @since GDAL 1.5.0
8610 : *
8611 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8612 : *
8613 : * @return CE_None on success or CE_Failure on an error.
8614 : *
8615 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8616 : * @see GDALDataset::CreateMaskBand()
8617 : *
8618 : */
8619 :
8620 9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8621 :
8622 : {
8623 9 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8624 : {
8625 9 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8626 9 : if (eErr != CE_None)
8627 1 : return eErr;
8628 :
8629 8 : InvalidateMaskBand();
8630 :
8631 8 : return CE_None;
8632 : }
8633 :
8634 0 : ReportError(CE_Failure, CPLE_NotSupported,
8635 : "CreateMaskBand() not supported for this band.");
8636 :
8637 0 : return CE_Failure;
8638 : }
8639 :
8640 : /************************************************************************/
8641 : /* GDALCreateMaskBand() */
8642 : /************************************************************************/
8643 :
8644 : /**
8645 : * \brief Adds a mask band to the current band
8646 : *
8647 : * @see GDALRasterBand::CreateMaskBand()
8648 : */
8649 :
8650 33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8651 :
8652 : {
8653 33 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8654 :
8655 33 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8656 33 : return poBand->CreateMaskBand(nFlags);
8657 : }
8658 :
8659 : /************************************************************************/
8660 : /* IsMaskBand() */
8661 : /************************************************************************/
8662 :
8663 : /**
8664 : * \brief Returns whether a band is a mask band.
8665 : *
8666 : * Mask band must be understood in the broad term: it can be a per-dataset
8667 : * mask band, an alpha band, or an implicit mask band.
8668 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8669 : *
8670 : * This method is the same as the C function GDALIsMaskBand().
8671 : *
8672 : * @return true if the band is a mask band.
8673 : *
8674 : * @see GDALDataset::CreateMaskBand()
8675 : *
8676 : * @since GDAL 3.5.0
8677 : *
8678 : */
8679 :
8680 409 : bool GDALRasterBand::IsMaskBand() const
8681 : {
8682 : // The GeoTIFF driver, among others, override this method to
8683 : // also handle external .msk bands.
8684 409 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8685 409 : GCI_AlphaBand;
8686 : }
8687 :
8688 : /************************************************************************/
8689 : /* GDALIsMaskBand() */
8690 : /************************************************************************/
8691 :
8692 : /**
8693 : * \brief Returns whether a band is a mask band.
8694 : *
8695 : * Mask band must be understood in the broad term: it can be a per-dataset
8696 : * mask band, an alpha band, or an implicit mask band.
8697 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8698 : *
8699 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8700 : *
8701 : * @return true if the band is a mask band.
8702 : *
8703 : * @see GDALRasterBand::IsMaskBand()
8704 : *
8705 : * @since GDAL 3.5.0
8706 : *
8707 : */
8708 :
8709 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
8710 :
8711 : {
8712 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8713 :
8714 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8715 37 : return poBand->IsMaskBand();
8716 : }
8717 :
8718 : /************************************************************************/
8719 : /* GetMaskValueRange() */
8720 : /************************************************************************/
8721 :
8722 : /**
8723 : * \brief Returns the range of values that a mask band can take.
8724 : *
8725 : * @return the range of values that a mask band can take.
8726 : *
8727 : * @since GDAL 3.5.0
8728 : *
8729 : */
8730 :
8731 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8732 : {
8733 0 : return GMVR_UNKNOWN;
8734 : }
8735 :
8736 : /************************************************************************/
8737 : /* GetIndexColorTranslationTo() */
8738 : /************************************************************************/
8739 :
8740 : /**
8741 : * \brief Compute translation table for color tables.
8742 : *
8743 : * When the raster band has a palette index, it may be useful to compute
8744 : * the "translation" of this palette to the palette of another band.
8745 : * The translation tries to do exact matching first, and then approximate
8746 : * matching if no exact matching is possible.
8747 : * This method returns a table such that table[i] = j where i is an index
8748 : * of the 'this' rasterband and j the corresponding index for the reference
8749 : * rasterband.
8750 : *
8751 : * This method is thought as internal to GDAL and is used for drivers
8752 : * like RPFTOC.
8753 : *
8754 : * The implementation only supports 1-byte palette rasterbands.
8755 : *
8756 : * @param poReferenceBand the raster band
8757 : * @param pTranslationTable an already allocated translation table (at least 256
8758 : * bytes), or NULL to let the method allocate it
8759 : * @param pApproximateMatching a pointer to a flag that is set if the matching
8760 : * is approximate. May be NULL.
8761 : *
8762 : * @return a translation table if the two bands are palette index and that they
8763 : * do not match or NULL in other cases. The table must be freed with CPLFree if
8764 : * NULL was passed for pTranslationTable.
8765 : */
8766 :
8767 : unsigned char *
8768 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8769 : unsigned char *pTranslationTable,
8770 : int *pApproximateMatching)
8771 : {
8772 4 : if (poReferenceBand == nullptr)
8773 0 : return nullptr;
8774 :
8775 : // cppcheck-suppress knownConditionTrueFalse
8776 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8777 : // cppcheck-suppress knownConditionTrueFalse
8778 4 : GetColorInterpretation() == GCI_PaletteIndex &&
8779 12 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
8780 4 : GetRasterDataType() == GDT_Byte)
8781 : {
8782 4 : const GDALColorTable *srcColorTable = GetColorTable();
8783 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8784 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
8785 : {
8786 4 : const int nEntries = srcColorTable->GetColorEntryCount();
8787 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
8788 :
8789 4 : int bHasNoDataValueSrc = FALSE;
8790 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8791 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8792 4 : dfNoDataValueSrc <= 255 &&
8793 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8794 0 : bHasNoDataValueSrc = FALSE;
8795 4 : const int noDataValueSrc =
8796 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8797 :
8798 4 : int bHasNoDataValueRef = FALSE;
8799 : const double dfNoDataValueRef =
8800 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8801 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8802 3 : dfNoDataValueRef <= 255 &&
8803 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8804 1 : bHasNoDataValueRef = FALSE;
8805 4 : const int noDataValueRef =
8806 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8807 :
8808 4 : bool samePalette = false;
8809 :
8810 4 : if (pApproximateMatching)
8811 3 : *pApproximateMatching = FALSE;
8812 :
8813 4 : if (nEntries == nRefEntries &&
8814 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
8815 3 : (bHasNoDataValueSrc == FALSE ||
8816 : noDataValueSrc == noDataValueRef))
8817 : {
8818 3 : samePalette = true;
8819 654 : for (int i = 0; i < nEntries; ++i)
8820 : {
8821 651 : if (noDataValueSrc == i)
8822 3 : continue;
8823 : const GDALColorEntry *entry =
8824 648 : srcColorTable->GetColorEntry(i);
8825 : const GDALColorEntry *entryRef =
8826 648 : destColorTable->GetColorEntry(i);
8827 648 : if (entry->c1 != entryRef->c1 ||
8828 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8829 : {
8830 0 : samePalette = false;
8831 : }
8832 : }
8833 : }
8834 :
8835 4 : if (!samePalette)
8836 : {
8837 1 : if (pTranslationTable == nullptr)
8838 : {
8839 : pTranslationTable = static_cast<unsigned char *>(
8840 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8841 1 : if (pTranslationTable == nullptr)
8842 1 : return nullptr;
8843 : }
8844 :
8845 : // Trying to remap the product palette on the subdataset
8846 : // palette.
8847 5 : for (int i = 0; i < nEntries; ++i)
8848 : {
8849 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8850 : noDataValueSrc == i)
8851 0 : continue;
8852 : const GDALColorEntry *entry =
8853 4 : srcColorTable->GetColorEntry(i);
8854 4 : bool bMatchFound = false;
8855 13 : for (int j = 0; j < nRefEntries; ++j)
8856 : {
8857 10 : if (bHasNoDataValueRef && noDataValueRef == j)
8858 0 : continue;
8859 : const GDALColorEntry *entryRef =
8860 10 : destColorTable->GetColorEntry(j);
8861 10 : if (entry->c1 == entryRef->c1 &&
8862 2 : entry->c2 == entryRef->c2 &&
8863 2 : entry->c3 == entryRef->c3)
8864 : {
8865 1 : pTranslationTable[i] =
8866 : static_cast<unsigned char>(j);
8867 1 : bMatchFound = true;
8868 1 : break;
8869 : }
8870 : }
8871 4 : if (!bMatchFound)
8872 : {
8873 : // No exact match. Looking for closest color now.
8874 3 : int best_j = 0;
8875 3 : int best_distance = 0;
8876 3 : if (pApproximateMatching)
8877 0 : *pApproximateMatching = TRUE;
8878 12 : for (int j = 0; j < nRefEntries; ++j)
8879 : {
8880 : const GDALColorEntry *entryRef =
8881 9 : destColorTable->GetColorEntry(j);
8882 9 : int distance = (entry->c1 - entryRef->c1) *
8883 9 : (entry->c1 - entryRef->c1) +
8884 9 : (entry->c2 - entryRef->c2) *
8885 9 : (entry->c2 - entryRef->c2) +
8886 9 : (entry->c3 - entryRef->c3) *
8887 9 : (entry->c3 - entryRef->c3);
8888 9 : if (j == 0 || distance < best_distance)
8889 : {
8890 7 : best_j = j;
8891 7 : best_distance = distance;
8892 : }
8893 : }
8894 3 : pTranslationTable[i] =
8895 : static_cast<unsigned char>(best_j);
8896 : }
8897 : }
8898 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
8899 0 : pTranslationTable[noDataValueSrc] =
8900 : static_cast<unsigned char>(noDataValueRef);
8901 :
8902 1 : return pTranslationTable;
8903 : }
8904 : }
8905 : }
8906 3 : return nullptr;
8907 : }
8908 :
8909 : /************************************************************************/
8910 : /* SetFlushBlockErr() */
8911 : /************************************************************************/
8912 :
8913 : /**
8914 : * \brief Store that an error occurred while writing a dirty block.
8915 : *
8916 : * This function stores the fact that an error occurred while writing a dirty
8917 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8918 : * flushed when the block cache get full, it is not convenient/possible to
8919 : * report that a dirty block could not be written correctly. This function
8920 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8921 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8922 : * places where the user can easily match the error with the relevant dataset.
8923 : */
8924 :
8925 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8926 : {
8927 0 : eFlushBlockErr = eErr;
8928 0 : }
8929 :
8930 : /************************************************************************/
8931 : /* IncDirtyBlocks() */
8932 : /************************************************************************/
8933 :
8934 : /**
8935 : * \brief Increment/decrement the number of dirty blocks
8936 : */
8937 :
8938 544578 : void GDALRasterBand::IncDirtyBlocks(int nInc)
8939 : {
8940 544578 : if (poBandBlockCache)
8941 544806 : poBandBlockCache->IncDirtyBlocks(nInc);
8942 544575 : }
8943 :
8944 : /************************************************************************/
8945 : /* ReportError() */
8946 : /************************************************************************/
8947 :
8948 : #ifndef DOXYGEN_XML
8949 : /**
8950 : * \brief Emits an error related to a raster band.
8951 : *
8952 : * This function is a wrapper for regular CPLError(). The only difference
8953 : * with CPLError() is that it prepends the error message with the dataset
8954 : * name and the band number.
8955 : *
8956 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
8957 : * @param err_no the error number (CPLE_*) from cpl_error.h.
8958 : * @param fmt a printf() style format string. Any additional arguments
8959 : * will be treated as arguments to fill in this format in a manner
8960 : * similar to printf().
8961 : *
8962 : * @since GDAL 1.9.0
8963 : */
8964 :
8965 2452 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
8966 : const char *fmt, ...) const
8967 : {
8968 : va_list args;
8969 :
8970 2452 : va_start(args, fmt);
8971 :
8972 2452 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
8973 2452 : pszDSName = CPLGetFilename(pszDSName);
8974 2452 : if (pszDSName[0] != '\0')
8975 : {
8976 2387 : CPLError(eErrClass, err_no, "%s",
8977 4774 : CPLString()
8978 2387 : .Printf("%s, band %d: ", pszDSName, GetBand())
8979 4774 : .append(CPLString().vPrintf(fmt, args))
8980 : .c_str());
8981 : }
8982 : else
8983 : {
8984 65 : CPLErrorV(eErrClass, err_no, fmt, args);
8985 : }
8986 :
8987 2452 : va_end(args);
8988 2452 : }
8989 : #endif
8990 :
8991 : /************************************************************************/
8992 : /* GetVirtualMemAuto() */
8993 : /************************************************************************/
8994 :
8995 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
8996 : *
8997 : * Only supported on Linux and Unix systems with mmap() for now.
8998 : *
8999 : * This method allows creating a virtual memory object for a GDALRasterBand,
9000 : * that exposes the whole image data as a virtual array.
9001 : *
9002 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9003 : * specialized implementation, such as for raw files, may also directly use
9004 : * mechanisms of the operating system to create a view of the underlying file
9005 : * into virtual memory ( CPLVirtualMemFileMapNew() )
9006 : *
9007 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9008 : * offer a specialized implementation with direct file mapping, provided that
9009 : * some requirements are met :
9010 : * - for all drivers, the dataset must be backed by a "real" file in the file
9011 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9012 : * must match the native ordering of the CPU.
9013 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9014 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9015 : * the file in sequential order, and be equally spaced (which is generally the
9016 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9017 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9018 : *
9019 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
9020 : * CPLVirtualMemFree() must be called before the raster band object is
9021 : * destroyed.
9022 : *
9023 : * If p is such a pointer and base_type the type matching
9024 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9025 : * accessed with
9026 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9027 : *
9028 : * This method is the same as the C GDALGetVirtualMemAuto() function.
9029 : *
9030 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9031 : * read/write the band.
9032 : *
9033 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
9034 : * one pixel value in the buffer to the start of the next pixel value within a
9035 : * scanline.
9036 : *
9037 : * @param pnLineSpace Output parameter giving the byte offset from the start of
9038 : * one scanline in the buffer to the start of the next.
9039 : *
9040 : * @param papszOptions NULL terminated list of options.
9041 : * If a specialized implementation exists, defining
9042 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9043 : * used. On the contrary, starting with GDAL 2.2, defining
9044 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9045 : * being used (thus only allowing efficient implementations to be used). When
9046 : * requiring or falling back to the default implementation, the following
9047 : * options are available : CACHE_SIZE (in bytes, defaults to
9048 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9049 : * to FALSE)
9050 : *
9051 : * @return a virtual memory object that must be unreferenced by
9052 : * CPLVirtualMemFree(), or NULL in case of failure.
9053 : *
9054 : * @since GDAL 1.11
9055 : */
9056 :
9057 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9058 : int *pnPixelSpace,
9059 : GIntBig *pnLineSpace,
9060 : char **papszOptions)
9061 : {
9062 9 : const char *pszImpl = CSLFetchNameValueDef(
9063 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9064 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9065 8 : EQUAL(pszImpl, "FALSE"))
9066 : {
9067 1 : return nullptr;
9068 : }
9069 :
9070 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9071 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9072 8 : if (pnPixelSpace)
9073 8 : *pnPixelSpace = nPixelSpace;
9074 8 : if (pnLineSpace)
9075 8 : *pnLineSpace = nLineSpace;
9076 : const size_t nCacheSize =
9077 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9078 : const size_t nPageSizeHint =
9079 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9080 8 : const bool bSingleThreadUsage = CPLTestBool(
9081 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9082 8 : return GDALRasterBandGetVirtualMem(
9083 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9084 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9085 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9086 8 : papszOptions);
9087 : }
9088 :
9089 : /************************************************************************/
9090 : /* GDALGetVirtualMemAuto() */
9091 : /************************************************************************/
9092 :
9093 : /**
9094 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9095 : *
9096 : * @see GDALRasterBand::GetVirtualMemAuto()
9097 : */
9098 :
9099 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9100 : int *pnPixelSpace, GIntBig *pnLineSpace,
9101 : CSLConstList papszOptions)
9102 : {
9103 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9104 :
9105 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9106 :
9107 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9108 31 : const_cast<char **>(papszOptions));
9109 : }
9110 :
9111 : /************************************************************************/
9112 : /* GDALGetDataCoverageStatus() */
9113 : /************************************************************************/
9114 :
9115 : /**
9116 : * \brief Get the coverage status of a sub-window of the raster.
9117 : *
9118 : * Returns whether a sub-window of the raster contains only data, only empty
9119 : * blocks or a mix of both. This function can be used to determine quickly
9120 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9121 : * be sparse.
9122 : *
9123 : * Empty blocks are blocks that are generally not physically present in the
9124 : * file, and when read through GDAL, contain only pixels whose value is the
9125 : * nodata value when it is set, or whose value is 0 when the nodata value is
9126 : * not set.
9127 : *
9128 : * The query is done in an efficient way without reading the actual pixel
9129 : * values. If not possible, or not implemented at all by the driver,
9130 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9131 : * be returned.
9132 : *
9133 : * The values that can be returned by the function are the following,
9134 : * potentially combined with the binary or operator :
9135 : * <ul>
9136 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9137 : * GetDataCoverageStatus(). This flag should be returned together with
9138 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9139 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9140 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9141 : * the queried window. This is typically identified by the concept of missing
9142 : * block in formats that supports it.
9143 : * </li>
9144 : * </ul>
9145 : *
9146 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9147 : * should be interpreted more as hint of potential presence of data. For example
9148 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9149 : * nodata value), instead of using the missing block mechanism,
9150 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9151 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9152 : *
9153 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9154 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9155 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9156 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9157 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9158 : * the function will exit, so that you can potentially refine the requested area
9159 : * to find which particular region(s) have missing blocks.
9160 : *
9161 : * @see GDALRasterBand::GetDataCoverageStatus()
9162 : *
9163 : * @param hBand raster band
9164 : *
9165 : * @param nXOff The pixel offset to the top left corner of the region
9166 : * of the band to be queried. This would be zero to start from the left side.
9167 : *
9168 : * @param nYOff The line offset to the top left corner of the region
9169 : * of the band to be queried. This would be zero to start from the top.
9170 : *
9171 : * @param nXSize The width of the region of the band to be queried in pixels.
9172 : *
9173 : * @param nYSize The height of the region of the band to be queried in lines.
9174 : *
9175 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9176 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9177 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9178 : * as the computation of the coverage matches the mask, the computation will be
9179 : * stopped. *pdfDataPct will not be valid in that case.
9180 : *
9181 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9182 : * to the (approximate) percentage in [0,100] of pixels in the queried
9183 : * sub-window that have valid values. The implementation might not always be
9184 : * able to compute it, in which case it will be set to a negative value.
9185 : *
9186 : * @return a binary-or'ed combination of possible values
9187 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9188 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9189 : *
9190 : * @note Added in GDAL 2.2
9191 : */
9192 :
9193 26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
9194 : int nYOff, int nXSize, int nYSize,
9195 : int nMaskFlagStop, double *pdfDataPct)
9196 : {
9197 26 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
9198 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
9199 :
9200 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9201 :
9202 26 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
9203 26 : nMaskFlagStop, pdfDataPct);
9204 : }
9205 :
9206 : /************************************************************************/
9207 : /* GetDataCoverageStatus() */
9208 : /************************************************************************/
9209 :
9210 : /**
9211 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
9212 : * int nYOff,
9213 : * int nXSize,
9214 : * int nYSize,
9215 : * int nMaskFlagStop,
9216 : * double* pdfDataPct)
9217 : * \brief Get the coverage status of a sub-window of the raster.
9218 : *
9219 : * Returns whether a sub-window of the raster contains only data, only empty
9220 : * blocks or a mix of both. This function can be used to determine quickly
9221 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9222 : * be sparse.
9223 : *
9224 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9225 : * value when it is set, or whose value is 0 when the nodata value is not set.
9226 : *
9227 : * The query is done in an efficient way without reading the actual pixel
9228 : * values. If not possible, or not implemented at all by the driver,
9229 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9230 : * be returned.
9231 : *
9232 : * The values that can be returned by the function are the following,
9233 : * potentially combined with the binary or operator :
9234 : * <ul>
9235 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9236 : * GetDataCoverageStatus(). This flag should be returned together with
9237 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9238 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9239 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9240 : * the queried window. This is typically identified by the concept of missing
9241 : * block in formats that supports it.
9242 : * </li>
9243 : * </ul>
9244 : *
9245 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9246 : * should be interpreted more as hint of potential presence of data. For example
9247 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9248 : * nodata value), instead of using the missing block mechanism,
9249 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9250 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9251 : *
9252 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9253 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9254 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9255 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9256 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9257 : * the function will exit, so that you can potentially refine the requested area
9258 : * to find which particular region(s) have missing blocks.
9259 : *
9260 : * @see GDALGetDataCoverageStatus()
9261 : *
9262 : * @param nXOff The pixel offset to the top left corner of the region
9263 : * of the band to be queried. This would be zero to start from the left side.
9264 : *
9265 : * @param nYOff The line offset to the top left corner of the region
9266 : * of the band to be queried. This would be zero to start from the top.
9267 : *
9268 : * @param nXSize The width of the region of the band to be queried in pixels.
9269 : *
9270 : * @param nYSize The height of the region of the band to be queried in lines.
9271 : *
9272 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9273 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9274 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9275 : * as the computation of the coverage matches the mask, the computation will be
9276 : * stopped. *pdfDataPct will not be valid in that case.
9277 : *
9278 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9279 : * to the (approximate) percentage in [0,100] of pixels in the queried
9280 : * sub-window that have valid values. The implementation might not always be
9281 : * able to compute it, in which case it will be set to a negative value.
9282 : *
9283 : * @return a binary-or'ed combination of possible values
9284 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9285 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9286 : *
9287 : * @note Added in GDAL 2.2
9288 : */
9289 :
9290 : /**
9291 : * \brief Get the coverage status of a sub-window of the raster.
9292 : *
9293 : * Returns whether a sub-window of the raster contains only data, only empty
9294 : * blocks or a mix of both. This function can be used to determine quickly
9295 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9296 : * be sparse.
9297 : *
9298 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9299 : * value when it is set, or whose value is 0 when the nodata value is not set.
9300 : *
9301 : * The query is done in an efficient way without reading the actual pixel
9302 : * values. If not possible, or not implemented at all by the driver,
9303 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9304 : * be returned.
9305 : *
9306 : * The values that can be returned by the function are the following,
9307 : * potentially combined with the binary or operator :
9308 : * <ul>
9309 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9310 : * GetDataCoverageStatus(). This flag should be returned together with
9311 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9312 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9313 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9314 : * the queried window. This is typically identified by the concept of missing
9315 : * block in formats that supports it.
9316 : * </li>
9317 : * </ul>
9318 : *
9319 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9320 : * should be interpreted more as hint of potential presence of data. For example
9321 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9322 : * nodata value), instead of using the missing block mechanism,
9323 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9324 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9325 : *
9326 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9327 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9328 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9329 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9330 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9331 : * the function will exit, so that you can potentially refine the requested area
9332 : * to find which particular region(s) have missing blocks.
9333 : *
9334 : * @see GDALGetDataCoverageStatus()
9335 : *
9336 : * @param nXOff The pixel offset to the top left corner of the region
9337 : * of the band to be queried. This would be zero to start from the left side.
9338 : *
9339 : * @param nYOff The line offset to the top left corner of the region
9340 : * of the band to be queried. This would be zero to start from the top.
9341 : *
9342 : * @param nXSize The width of the region of the band to be queried in pixels.
9343 : *
9344 : * @param nYSize The height of the region of the band to be queried in lines.
9345 : *
9346 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9347 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9348 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9349 : * as the computation of the coverage matches the mask, the computation will be
9350 : * stopped. *pdfDataPct will not be valid in that case.
9351 : *
9352 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9353 : * to the (approximate) percentage in [0,100] of pixels in the queried
9354 : * sub-window that have valid values. The implementation might not always be
9355 : * able to compute it, in which case it will be set to a negative value.
9356 : *
9357 : * @return a binary-or'ed combination of possible values
9358 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9359 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9360 : *
9361 : * @note Added in GDAL 2.2
9362 : */
9363 :
9364 4558 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9365 : int nYSize, int nMaskFlagStop,
9366 : double *pdfDataPct)
9367 : {
9368 4558 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9369 4558 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9370 4558 : nYOff + nYSize > nRasterYSize)
9371 : {
9372 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9373 0 : if (pdfDataPct)
9374 0 : *pdfDataPct = 0.0;
9375 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9376 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
9377 : }
9378 4558 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9379 4558 : pdfDataPct);
9380 : }
9381 :
9382 : /************************************************************************/
9383 : /* IGetDataCoverageStatus() */
9384 : /************************************************************************/
9385 :
9386 636 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9387 : int /*nXSize*/, int /*nYSize*/,
9388 : int /*nMaskFlagStop*/,
9389 : double *pdfDataPct)
9390 : {
9391 636 : if (pdfDataPct != nullptr)
9392 0 : *pdfDataPct = 100.0;
9393 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9394 636 : GDAL_DATA_COVERAGE_STATUS_DATA;
9395 : }
9396 :
9397 : //! @cond Doxygen_Suppress
9398 : /************************************************************************/
9399 : /* EnterReadWrite() */
9400 : /************************************************************************/
9401 :
9402 7034320 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9403 : {
9404 7034320 : if (poDS != nullptr)
9405 6278620 : return poDS->EnterReadWrite(eRWFlag);
9406 755700 : return FALSE;
9407 : }
9408 :
9409 : /************************************************************************/
9410 : /* LeaveReadWrite() */
9411 : /************************************************************************/
9412 :
9413 651851 : void GDALRasterBand::LeaveReadWrite()
9414 : {
9415 651851 : if (poDS != nullptr)
9416 651839 : poDS->LeaveReadWrite();
9417 651843 : }
9418 :
9419 : /************************************************************************/
9420 : /* InitRWLock() */
9421 : /************************************************************************/
9422 :
9423 3660600 : void GDALRasterBand::InitRWLock()
9424 : {
9425 3660600 : if (poDS != nullptr)
9426 3660190 : poDS->InitRWLock();
9427 3660600 : }
9428 :
9429 : //! @endcond
9430 :
9431 : // clang-format off
9432 :
9433 : /**
9434 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9435 : * \brief Set metadata.
9436 : *
9437 : * CAUTION: depending on the format, older values of the updated information
9438 : * might still be found in the file in a "ghost" state, even if no longer
9439 : * accessible through the GDAL API. This is for example the case of the GTiff
9440 : * format (this is not a exhaustive list)
9441 : *
9442 : * The C function GDALSetMetadata() does the same thing as this method.
9443 : *
9444 : * @param papszMetadata the metadata in name=value string list format to
9445 : * apply.
9446 : * @param pszDomain the domain of interest. Use "" or NULL for the default
9447 : * domain.
9448 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9449 : * metadata has been accepted, but is likely not maintained persistently
9450 : * by the underlying object between sessions.
9451 : */
9452 :
9453 : /**
9454 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9455 : * \brief Set single metadata item.
9456 : *
9457 : * CAUTION: depending on the format, older values of the updated information
9458 : * might still be found in the file in a "ghost" state, even if no longer
9459 : * accessible through the GDAL API. This is for example the case of the GTiff
9460 : * format (this is not a exhaustive list)
9461 : *
9462 : * The C function GDALSetMetadataItem() does the same thing as this method.
9463 : *
9464 : * @param pszName the key for the metadata item to fetch.
9465 : * @param pszValue the value to assign to the key.
9466 : * @param pszDomain the domain to set within, use NULL for the default domain.
9467 : *
9468 : * @return CE_None on success, or an error code on failure.
9469 : */
9470 :
9471 : // clang-format on
9472 :
9473 : //! @cond Doxygen_Suppress
9474 : /************************************************************************/
9475 : /* EnablePixelTypeSignedByteWarning() */
9476 : /************************************************************************/
9477 :
9478 27164 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9479 : {
9480 27164 : m_bEnablePixelTypeSignedByteWarning = b;
9481 27164 : }
9482 :
9483 8422 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9484 : {
9485 8422 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9486 8422 : }
9487 :
9488 : //! @endcond
9489 :
9490 : /************************************************************************/
9491 : /* GetMetadataItem() */
9492 : /************************************************************************/
9493 :
9494 61720 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9495 : const char *pszDomain)
9496 : {
9497 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9498 61720 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9499 37233 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9500 28285 : EQUAL(pszName, "PIXELTYPE"))
9501 : {
9502 2 : CPLError(CE_Warning, CPLE_AppDefined,
9503 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9504 : "used to signal signed 8-bit raster. Change your code to "
9505 : "test for the new GDT_Int8 data type instead.");
9506 : }
9507 61720 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9508 : }
9509 :
9510 : /************************************************************************/
9511 : /* GDALMDArrayFromRasterBand */
9512 : /************************************************************************/
9513 :
9514 : class GDALMDArrayFromRasterBand final : public GDALMDArray
9515 : {
9516 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9517 :
9518 : GDALDataset *m_poDS;
9519 : GDALRasterBand *m_poBand;
9520 : GDALExtendedDataType m_dt;
9521 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9522 : std::string m_osUnit;
9523 : std::vector<GByte> m_pabyNoData{};
9524 : std::shared_ptr<GDALMDArray> m_varX{};
9525 : std::shared_ptr<GDALMDArray> m_varY{};
9526 : std::string m_osFilename{};
9527 :
9528 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9529 : const size_t *count, const GInt64 *arrayStep,
9530 : const GPtrDiff_t *bufferStride,
9531 : const GDALExtendedDataType &bufferDataType,
9532 : void *pBuffer) const;
9533 :
9534 : protected:
9535 23 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9536 46 : : GDALAbstractMDArray(std::string(),
9537 46 : std::string(poDS->GetDescription()) +
9538 : CPLSPrintf(" band %d", poBand->GetBand())),
9539 46 : GDALMDArray(std::string(),
9540 46 : std::string(poDS->GetDescription()) +
9541 : CPLSPrintf(" band %d", poBand->GetBand())),
9542 : m_poDS(poDS), m_poBand(poBand),
9543 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9544 115 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9545 : {
9546 23 : m_poDS->Reference();
9547 :
9548 23 : int bHasNoData = false;
9549 23 : if (m_poBand->GetRasterDataType() == GDT_Int64)
9550 : {
9551 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9552 0 : if (bHasNoData)
9553 : {
9554 0 : m_pabyNoData.resize(m_dt.GetSize());
9555 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9556 : m_dt.GetNumericDataType(), 0, 1);
9557 : }
9558 : }
9559 23 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9560 : {
9561 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9562 0 : if (bHasNoData)
9563 : {
9564 0 : m_pabyNoData.resize(m_dt.GetSize());
9565 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9566 : m_dt.GetNumericDataType(), 0, 1);
9567 : }
9568 : }
9569 : else
9570 : {
9571 23 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9572 23 : if (bHasNoData)
9573 : {
9574 1 : m_pabyNoData.resize(m_dt.GetSize());
9575 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9576 : m_dt.GetNumericDataType(), 0, 1);
9577 : }
9578 : }
9579 :
9580 23 : const int nXSize = poBand->GetXSize();
9581 23 : const int nYSize = poBand->GetYSize();
9582 :
9583 23 : auto poSRS = m_poDS->GetSpatialRef();
9584 46 : std::string osTypeY;
9585 46 : std::string osTypeX;
9586 46 : std::string osDirectionY;
9587 46 : std::string osDirectionX;
9588 23 : if (poSRS && poSRS->GetAxesCount() == 2)
9589 : {
9590 21 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9591 21 : OGRAxisOrientation eOrientation1 = OAO_Other;
9592 21 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
9593 21 : OGRAxisOrientation eOrientation2 = OAO_Other;
9594 21 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
9595 21 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9596 : {
9597 5 : if (mapping == std::vector<int>{1, 2})
9598 : {
9599 5 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9600 5 : osDirectionY = "NORTH";
9601 5 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9602 5 : osDirectionX = "EAST";
9603 : }
9604 : }
9605 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9606 : {
9607 16 : if (mapping == std::vector<int>{2, 1})
9608 : {
9609 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9610 16 : osDirectionY = "NORTH";
9611 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9612 16 : osDirectionX = "EAST";
9613 : }
9614 : }
9615 : }
9616 :
9617 115 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9618 : "/", "Y", osTypeY, osDirectionY, nYSize),
9619 46 : std::make_shared<GDALDimensionWeakIndexingVar>(
9620 69 : "/", "X", osTypeX, osDirectionX, nXSize)};
9621 :
9622 : double adfGeoTransform[6];
9623 23 : if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
9624 23 : adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
9625 : {
9626 44 : m_varX = GDALMDArrayRegularlySpaced::Create(
9627 22 : "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
9628 22 : 0.5);
9629 22 : m_dims[1]->SetIndexingVariable(m_varX);
9630 :
9631 44 : m_varY = GDALMDArrayRegularlySpaced::Create(
9632 22 : "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
9633 22 : 0.5);
9634 22 : m_dims[0]->SetIndexingVariable(m_varY);
9635 : }
9636 23 : }
9637 :
9638 31 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9639 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9640 : const GDALExtendedDataType &bufferDataType,
9641 : void *pDstBuffer) const override
9642 : {
9643 31 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9644 31 : bufferDataType, pDstBuffer);
9645 : }
9646 :
9647 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9648 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9649 : const GDALExtendedDataType &bufferDataType,
9650 : const void *pSrcBuffer) override
9651 : {
9652 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9653 : bufferStride, bufferDataType,
9654 1 : const_cast<void *>(pSrcBuffer));
9655 : }
9656 :
9657 : public:
9658 46 : ~GDALMDArrayFromRasterBand()
9659 23 : {
9660 23 : m_poDS->ReleaseRef();
9661 46 : }
9662 :
9663 23 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9664 : GDALRasterBand *poBand)
9665 : {
9666 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9667 46 : new GDALMDArrayFromRasterBand(poDS, poBand)));
9668 23 : array->SetSelf(array);
9669 46 : return array;
9670 : }
9671 :
9672 2 : bool IsWritable() const override
9673 : {
9674 2 : return m_poDS->GetAccess() == GA_Update;
9675 : }
9676 :
9677 97 : const std::string &GetFilename() const override
9678 : {
9679 97 : return m_osFilename;
9680 : }
9681 :
9682 : const std::vector<std::shared_ptr<GDALDimension>> &
9683 299 : GetDimensions() const override
9684 : {
9685 299 : return m_dims;
9686 : }
9687 :
9688 138 : const GDALExtendedDataType &GetDataType() const override
9689 : {
9690 138 : return m_dt;
9691 : }
9692 :
9693 3 : const std::string &GetUnit() const override
9694 : {
9695 3 : return m_osUnit;
9696 : }
9697 :
9698 29 : const void *GetRawNoDataValue() const override
9699 : {
9700 29 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9701 : }
9702 :
9703 2 : double GetOffset(bool *pbHasOffset,
9704 : GDALDataType *peStorageType) const override
9705 : {
9706 2 : int bHasOffset = false;
9707 2 : double dfRes = m_poBand->GetOffset(&bHasOffset);
9708 2 : if (pbHasOffset)
9709 2 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9710 2 : if (peStorageType)
9711 1 : *peStorageType = GDT_Unknown;
9712 2 : return dfRes;
9713 : }
9714 :
9715 2 : double GetScale(bool *pbHasScale,
9716 : GDALDataType *peStorageType) const override
9717 : {
9718 2 : int bHasScale = false;
9719 2 : double dfRes = m_poBand->GetScale(&bHasScale);
9720 2 : if (pbHasScale)
9721 2 : *pbHasScale = CPL_TO_BOOL(bHasScale);
9722 2 : if (peStorageType)
9723 1 : *peStorageType = GDT_Unknown;
9724 2 : return dfRes;
9725 : }
9726 :
9727 84 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9728 : {
9729 84 : auto poSrcSRS = m_poDS->GetSpatialRef();
9730 84 : if (!poSrcSRS)
9731 2 : return nullptr;
9732 164 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9733 :
9734 164 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9735 82 : constexpr int iYDim = 0;
9736 82 : constexpr int iXDim = 1;
9737 246 : for (auto &m : axisMapping)
9738 : {
9739 164 : if (m == 1)
9740 82 : m = iXDim + 1;
9741 82 : else if (m == 2)
9742 82 : m = iYDim + 1;
9743 : else
9744 0 : m = 0;
9745 : }
9746 82 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9747 82 : return poSRS;
9748 : }
9749 :
9750 29 : std::vector<GUInt64> GetBlockSize() const override
9751 : {
9752 29 : int nBlockXSize = 0;
9753 29 : int nBlockYSize = 0;
9754 29 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9755 29 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9756 29 : static_cast<GUInt64>(nBlockXSize)};
9757 : }
9758 :
9759 : class MDIAsAttribute : public GDALAttribute
9760 : {
9761 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9762 : const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
9763 : std::string m_osValue;
9764 :
9765 : public:
9766 2 : MDIAsAttribute(const std::string &name, const std::string &value)
9767 2 : : GDALAbstractMDArray(std::string(), name),
9768 4 : GDALAttribute(std::string(), name), m_osValue(value)
9769 : {
9770 2 : }
9771 :
9772 : const std::vector<std::shared_ptr<GDALDimension>> &
9773 3 : GetDimensions() const override
9774 : {
9775 3 : return m_dims;
9776 : }
9777 :
9778 2 : const GDALExtendedDataType &GetDataType() const override
9779 : {
9780 2 : return m_dt;
9781 : }
9782 :
9783 1 : bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
9784 : const GPtrDiff_t *,
9785 : const GDALExtendedDataType &bufferDataType,
9786 : void *pDstBuffer) const override
9787 : {
9788 1 : const char *pszStr = m_osValue.c_str();
9789 1 : GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
9790 : bufferDataType);
9791 1 : return true;
9792 : }
9793 : };
9794 :
9795 : std::vector<std::shared_ptr<GDALAttribute>>
9796 14 : GetAttributes(CSLConstList) const override
9797 : {
9798 14 : std::vector<std::shared_ptr<GDALAttribute>> res;
9799 14 : auto papszMD = m_poBand->GetMetadata();
9800 16 : for (auto iter = papszMD; iter && iter[0]; ++iter)
9801 : {
9802 2 : char *pszKey = nullptr;
9803 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9804 2 : if (pszKey && pszValue)
9805 : {
9806 : res.emplace_back(
9807 2 : std::make_shared<MDIAsAttribute>(pszKey, pszValue));
9808 : }
9809 2 : CPLFree(pszKey);
9810 : }
9811 14 : return res;
9812 : }
9813 : };
9814 :
9815 : /************************************************************************/
9816 : /* ReadWrite() */
9817 : /************************************************************************/
9818 :
9819 32 : bool GDALMDArrayFromRasterBand::ReadWrite(
9820 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
9821 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9822 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
9823 : {
9824 32 : constexpr size_t iDimX = 1;
9825 32 : constexpr size_t iDimY = 0;
9826 32 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
9827 : arrayStartIdx, count, arrayStep, bufferStride,
9828 32 : bufferDataType, pBuffer);
9829 : }
9830 :
9831 : /************************************************************************/
9832 : /* GDALMDRasterIOFromBand() */
9833 : /************************************************************************/
9834 :
9835 65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
9836 : size_t iDimX, size_t iDimY,
9837 : const GUInt64 *arrayStartIdx, const size_t *count,
9838 : const GInt64 *arrayStep,
9839 : const GPtrDiff_t *bufferStride,
9840 : const GDALExtendedDataType &bufferDataType,
9841 : void *pBuffer)
9842 : {
9843 65 : const auto eDT(bufferDataType.GetNumericDataType());
9844 65 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
9845 65 : const int nX =
9846 65 : arrayStep[iDimX] > 0
9847 65 : ? static_cast<int>(arrayStartIdx[iDimX])
9848 2 : : static_cast<int>(arrayStartIdx[iDimX] -
9849 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
9850 65 : const int nY =
9851 65 : arrayStep[iDimY] > 0
9852 65 : ? static_cast<int>(arrayStartIdx[iDimY])
9853 2 : : static_cast<int>(arrayStartIdx[iDimY] -
9854 2 : (count[iDimY] - 1) * -arrayStep[iDimY]);
9855 65 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
9856 65 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
9857 65 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
9858 65 : int nStrideXSign = 1;
9859 65 : if (arrayStep[iDimX] < 0)
9860 : {
9861 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
9862 2 : nStrideXSign = -1;
9863 : }
9864 65 : int nStrideYSign = 1;
9865 65 : if (arrayStep[iDimY] < 0)
9866 : {
9867 2 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
9868 2 : nStrideYSign = -1;
9869 : }
9870 :
9871 130 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
9872 65 : static_cast<int>(count[iDimX]),
9873 65 : static_cast<int>(count[iDimY]), eDT,
9874 : static_cast<GSpacing>(
9875 65 : nStrideXSign * bufferStride[iDimX] * nDTSize),
9876 : static_cast<GSpacing>(
9877 65 : nStrideYSign * bufferStride[iDimY] * nDTSize),
9878 65 : nullptr) == CE_None;
9879 : }
9880 :
9881 : /************************************************************************/
9882 : /* AsMDArray() */
9883 : /************************************************************************/
9884 :
9885 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
9886 : *
9887 : * The band must be linked to a GDALDataset. If this dataset is not already
9888 : * marked as shared, it will be, so that the returned array holds a reference
9889 : * to it.
9890 : *
9891 : * If the dataset has a geotransform attached, the X and Y dimensions of the
9892 : * returned array will have an associated indexing variable.
9893 : *
9894 : * This is the same as the C function GDALRasterBandAsMDArray().
9895 : *
9896 : * The "reverse" method is GDALMDArray::AsClassicDataset().
9897 : *
9898 : * @return a new array, or nullptr.
9899 : *
9900 : * @since GDAL 3.1
9901 : */
9902 23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
9903 : {
9904 23 : if (!poDS)
9905 : {
9906 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
9907 0 : return nullptr;
9908 : }
9909 23 : if (!poDS->GetShared())
9910 : {
9911 23 : poDS->MarkAsShared();
9912 : }
9913 : return GDALMDArrayFromRasterBand::Create(
9914 23 : poDS, const_cast<GDALRasterBand *>(this));
9915 : }
9916 :
9917 : /************************************************************************/
9918 : /* InterpolateAtPoint() */
9919 : /************************************************************************/
9920 :
9921 : /**
9922 : * \brief Interpolates the value between pixels using a resampling algorithm,
9923 : * taking pixel/line coordinates as input.
9924 : *
9925 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
9926 : * @param dfLine line coordinate as a double, where interpolation should be done.
9927 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
9928 : * @param pdfRealValue pointer to real part of interpolated value
9929 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
9930 : *
9931 : * @return CE_None on success, or an error code on failure.
9932 : * @since GDAL 3.10
9933 : */
9934 :
9935 137 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
9936 : GDALRIOResampleAlg eInterpolation,
9937 : double *pdfRealValue,
9938 : double *pdfImagValue) const
9939 : {
9940 137 : if (eInterpolation != GRIORA_NearestNeighbour &&
9941 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
9942 : eInterpolation != GRIORA_CubicSpline)
9943 : {
9944 2 : CPLError(CE_Failure, CPLE_AppDefined,
9945 : "Only nearest, bilinear, cubic and cubicspline interpolation "
9946 : "methods "
9947 : "allowed");
9948 :
9949 2 : return CE_Failure;
9950 : }
9951 :
9952 135 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
9953 135 : if (!m_poPointsCache)
9954 55 : m_poPointsCache = new GDALDoublePointsCache();
9955 :
9956 : const bool res =
9957 135 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
9958 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
9959 :
9960 135 : return res ? CE_None : CE_Failure;
9961 : }
9962 :
9963 : /************************************************************************/
9964 : /* GDALRasterInterpolateAtPoint() */
9965 : /************************************************************************/
9966 :
9967 : /**
9968 : * \brief Interpolates the value between pixels using
9969 : * a resampling algorithm
9970 : *
9971 : * @see GDALRasterBand::InterpolateAtPoint()
9972 : * @since GDAL 3.10
9973 : */
9974 :
9975 114 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
9976 : double dfLine,
9977 : GDALRIOResampleAlg eInterpolation,
9978 : double *pdfRealValue, double *pdfImagValue)
9979 : {
9980 114 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
9981 :
9982 114 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9983 114 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
9984 114 : pdfRealValue, pdfImagValue);
9985 : }
9986 :
9987 : /************************************************************************/
9988 : /* InterpolateAtGeolocation() */
9989 : /************************************************************************/
9990 :
9991 : /**
9992 : * \brief Interpolates the value between pixels using a resampling algorithm,
9993 : * taking georeferenced coordinates as input.
9994 : *
9995 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
9996 : * must be in the "natural" SRS of the dataset, that is the one returned by
9997 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
9998 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
9999 : * array (generally WGS 84) if there is a geolocation array.
10000 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10001 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10002 : * be a easting, and dfGeolocY a northing.
10003 : *
10004 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10005 : * expressed in that CRS, and that tuple must be conformant with the
10006 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10007 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10008 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10009 : * before calling this method, and in that case, dfGeolocX must be a longitude
10010 : * or an easting value, and dfGeolocX a latitude or a northing value.
10011 : *
10012 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
10013 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
10014 : * it for details on how that transformation is done.
10015 : *
10016 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
10017 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10018 : * where interpolation should be done.
10019 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
10020 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10021 : * where interpolation should be done.
10022 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
10023 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10024 : * @param pdfRealValue pointer to real part of interpolated value
10025 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10026 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
10027 : *
10028 : * @return CE_None on success, or an error code on failure.
10029 : * @since GDAL 3.11
10030 : */
10031 :
10032 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
10033 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
10034 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
10035 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
10036 : {
10037 : double dfPixel;
10038 : double dfLine;
10039 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
10040 : &dfLine,
10041 15 : papszTransformerOptions) != CE_None)
10042 : {
10043 1 : return CE_Failure;
10044 : }
10045 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
10046 14 : pdfImagValue);
10047 : }
10048 :
10049 : /************************************************************************/
10050 : /* GDALRasterInterpolateAtGeolocation() */
10051 : /************************************************************************/
10052 :
10053 : /**
10054 : * \brief Interpolates the value between pixels using a resampling algorithm,
10055 : * taking georeferenced coordinates as input.
10056 : *
10057 : * @see GDALRasterBand::InterpolateAtGeolocation()
10058 : * @since GDAL 3.11
10059 : */
10060 :
10061 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
10062 : double dfGeolocX, double dfGeolocY,
10063 : OGRSpatialReferenceH hSRS,
10064 : GDALRIOResampleAlg eInterpolation,
10065 : double *pdfRealValue,
10066 : double *pdfImagValue,
10067 : CSLConstList papszTransformerOptions)
10068 : {
10069 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
10070 :
10071 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10072 15 : return poBand->InterpolateAtGeolocation(
10073 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
10074 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
10075 : }
|