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 1340590 : GDALRasterBand::GDALRasterBand()
51 : : GDALRasterBand(
52 1340590 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
53 : {
54 1340500 : }
55 :
56 : /** Constructor. Applications should never create GDALRasterBands directly.
57 : * @param bForceCachedIOIn Whether cached IO should be forced.
58 : */
59 1611450 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
60 1611450 : : bForceCachedIO(bForceCachedIOIn)
61 :
62 : {
63 1611280 : }
64 :
65 : /************************************************************************/
66 : /* ~GDALRasterBand() */
67 : /************************************************************************/
68 :
69 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
70 : instead destroy the GDALDataset. */
71 :
72 1611450 : GDALRasterBand::~GDALRasterBand()
73 :
74 : {
75 1611460 : if (poDS && poDS->IsMarkedSuppressOnClose())
76 : {
77 516 : if (poBandBlockCache)
78 452 : poBandBlockCache->DisableDirtyBlockWriting();
79 : }
80 1611450 : GDALRasterBand::FlushCache(true);
81 :
82 1611460 : delete poBandBlockCache;
83 :
84 1611460 : if (static_cast<GIntBig>(nBlockReads) >
85 1611460 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
86 216 : nBand == 1 && poDS != nullptr)
87 : {
88 312 : CPLDebug(
89 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
90 156 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
91 156 : poDS->GetDescription());
92 : }
93 :
94 1611460 : InvalidateMaskBand();
95 1611450 : nBand = -nBand;
96 :
97 1611450 : delete m_poPointsCache;
98 1611450 : }
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 4288500 : 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 4288500 : if (psExtraArg == nullptr)
331 : {
332 3799700 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
333 3799700 : psExtraArg = &sExtraArg;
334 : }
335 488805 : 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 4288500 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
344 : nBufYSize);
345 :
346 4291640 : 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 4291640 : 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 4291640 : if (eRWFlag == GF_Write)
370 : {
371 361643 : 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 361643 : 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 4291660 : if (nPixelSpace == 0)
391 : {
392 3995770 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
393 : }
394 :
395 4289330 : if (nLineSpace == 0)
396 : {
397 3988720 : nLineSpace = nPixelSpace * nBufXSize;
398 : }
399 :
400 : /* -------------------------------------------------------------------- */
401 : /* Do some validation of parameters. */
402 : /* -------------------------------------------------------------------- */
403 4289330 : 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 4289320 : 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 4289320 : 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 4289320 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
434 :
435 : CPLErr eErr;
436 4284780 : 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 4290990 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
443 4284760 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
444 :
445 4291020 : if (bCallLeaveReadWrite)
446 599281 : LeaveReadWrite();
447 :
448 4283900 : 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 3402240 : 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 3402240 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
472 :
473 3402240 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
474 :
475 3396890 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
476 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
477 3397540 : 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 38770 : 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 38770 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
500 :
501 38770 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
502 :
503 38770 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
504 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
505 38768 : 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 646 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1080 :
1081 : {
1082 : /* -------------------------------------------------------------------- */
1083 : /* Validate arguments. */
1084 : /* -------------------------------------------------------------------- */
1085 646 : CPLAssert(pImage != nullptr);
1086 :
1087 646 : if (!InitBlockInfo())
1088 0 : return CE_Failure;
1089 :
1090 646 : 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 646 : 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 646 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1115 646 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1116 646 : if (bCallLeaveReadWrite)
1117 4 : LeaveReadWrite();
1118 646 : 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 69 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1132 : void *pData)
1133 :
1134 : {
1135 69 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1136 :
1137 69 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1138 69 : 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 536181 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1309 : const char *pszCaller) const
1310 : {
1311 536181 : 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 536177 : 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 50145 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1349 : int *pnXValid, int *pnYValid) const
1350 : {
1351 100289 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1352 100287 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1353 100284 : nYBlockOff < 0 || nBlockYSize == 0 ||
1354 50142 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1355 : {
1356 5 : return CE_Failure;
1357 : }
1358 :
1359 50140 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1360 50140 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1361 :
1362 50140 : *pnXValid = nBlockXSize;
1363 50140 : *pnYValid = nBlockYSize;
1364 :
1365 50140 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1366 : {
1367 48756 : *pnXValid = nRasterXSize - nXPixelOff;
1368 : }
1369 :
1370 50140 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1371 : {
1372 3297 : *pnYValid = nRasterYSize - nYPixelOff;
1373 : }
1374 :
1375 50140 : 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 2344 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1435 : {
1436 2344 : 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 8431420 : GDALDataType GDALRasterBand::GetRasterDataType() const
1452 :
1453 : {
1454 8431420 : 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 903205 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1468 :
1469 : {
1470 903205 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1471 :
1472 903205 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1473 903205 : 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 5211750 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1503 :
1504 : {
1505 5211750 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1506 : {
1507 13668 : ReportError(CE_Failure, CPLE_AppDefined,
1508 13668 : "Invalid block dimension : %d * %d", nBlockXSize,
1509 13668 : nBlockYSize);
1510 0 : if (pnXSize != nullptr)
1511 0 : *pnXSize = 0;
1512 0 : if (pnYSize != nullptr)
1513 0 : *pnYSize = 0;
1514 : }
1515 : else
1516 : {
1517 5198080 : if (pnXSize != nullptr)
1518 5202180 : *pnXSize = nBlockXSize;
1519 5198080 : if (pnYSize != nullptr)
1520 5202610 : *pnYSize = nBlockYSize;
1521 : }
1522 5198080 : }
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 40982 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1535 : int *pnYSize)
1536 :
1537 : {
1538 40982 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1539 :
1540 40982 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1541 40982 : poBand->GetBlockSize(pnXSize, pnYSize);
1542 : }
1543 :
1544 : /************************************************************************/
1545 : /* InitBlockInfo() */
1546 : /************************************************************************/
1547 :
1548 : //! @cond Doxygen_Suppress
1549 3340480 : int GDALRasterBand::InitBlockInfo()
1550 :
1551 : {
1552 3340480 : if (poBandBlockCache != nullptr)
1553 3302260 : 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 38226 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1558 : {
1559 4 : ReportError(CE_Failure, CPLE_AppDefined,
1560 : "Invalid block dimension : %d * %d", nBlockXSize,
1561 : nBlockYSize);
1562 0 : return FALSE;
1563 : }
1564 :
1565 38222 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1566 : {
1567 6 : ReportError(CE_Failure, CPLE_AppDefined,
1568 : "Invalid raster dimension : %d * %d", nRasterXSize,
1569 : nRasterYSize);
1570 0 : return FALSE;
1571 : }
1572 :
1573 38216 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1574 38224 : 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 38224 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1597 38224 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1598 :
1599 : const char *pszBlockStrategy =
1600 38224 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1601 38228 : bool bUseArray = true;
1602 38228 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1603 : {
1604 38188 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1605 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1606 : {
1607 38169 : GUIntBig nBlockCount =
1608 38169 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1609 38169 : if (poDS != nullptr)
1610 37974 : nBlockCount *= poDS->GetRasterCount();
1611 38169 : 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 38188 : }
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 38228 : if (bUseArray)
1626 38157 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1627 : else
1628 : {
1629 71 : if (nBand == 1)
1630 26 : CPLDebug("GDAL", "Use hashset band block cache");
1631 71 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1632 : }
1633 38226 : if (poBandBlockCache == nullptr)
1634 0 : return FALSE;
1635 38226 : 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 5098820 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1657 :
1658 : {
1659 5211740 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1660 112922 : poBandBlockCache)
1661 2446 : poBandBlockCache->DisableDirtyBlockWriting();
1662 :
1663 5098090 : CPLErr eGlobalErr = eFlushBlockErr;
1664 :
1665 5098090 : 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 5098090 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1674 4932400 : return eGlobalErr;
1675 :
1676 165684 : 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 131 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1690 :
1691 : {
1692 131 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1693 :
1694 131 : 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 29624 : 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 29624 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1794 29624 : 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 29624 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1807 : {
1808 29624 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1809 29624 : 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 2302 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1825 : int bWriteDirtyBlock)
1826 :
1827 : {
1828 2302 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1829 0 : return (CE_Failure);
1830 :
1831 : /* -------------------------------------------------------------------- */
1832 : /* Validate the request */
1833 : /* -------------------------------------------------------------------- */
1834 2302 : 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 2302 : 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 2302 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1855 2302 : 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 10328000 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1883 : int nYBlockOff)
1884 :
1885 : {
1886 10328000 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1887 70766 : return nullptr;
1888 :
1889 : /* -------------------------------------------------------------------- */
1890 : /* Validate the request */
1891 : /* -------------------------------------------------------------------- */
1892 10257200 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1893 : {
1894 21 : 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 10257200 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1903 : {
1904 0 : 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 10257200 : 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 10125100 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1950 : int nYBlockOff,
1951 : int bJustInitialize)
1952 :
1953 : {
1954 : /* -------------------------------------------------------------------- */
1955 : /* Try and fetch from cache. */
1956 : /* -------------------------------------------------------------------- */
1957 10125100 : 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 10125200 : if (poBlock == nullptr)
1965 : {
1966 3163330 : if (!InitBlockInfo())
1967 0 : return (nullptr);
1968 :
1969 : /* --------------------------------------------------------------------
1970 : */
1971 : /* Validate the request */
1972 : /* --------------------------------------------------------------------
1973 : */
1974 3163330 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1975 : {
1976 7 : 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 3163330 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1985 : {
1986 5 : 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 3163320 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1995 3163320 : if (poBlock == nullptr)
1996 0 : return nullptr;
1997 :
1998 3163320 : 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 3163330 : if (poDS)
2013 3162590 : poDS->TemporarilyDropReadWriteLock();
2014 : /* allocate data space */
2015 3163330 : CPLErr eErr = poBlock->Internalize();
2016 3163350 : if (poDS)
2017 3162610 : poDS->ReacquireReadWriteLock();
2018 3163340 : if (eErr != CE_None)
2019 : {
2020 0 : poBlock->DropLock();
2021 0 : delete poBlock;
2022 0 : return nullptr;
2023 : }
2024 :
2025 3163340 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2026 : {
2027 0 : poBlock->DropLock();
2028 0 : delete poBlock;
2029 0 : return nullptr;
2030 : }
2031 :
2032 3163330 : if (!bJustInitialize)
2033 : {
2034 2807260 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2035 2807260 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2036 2807270 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2037 2807280 : if (bCallLeaveReadWrite)
2038 129950 : LeaveReadWrite();
2039 2807270 : if (eErr != CE_None)
2040 : {
2041 1152 : poBlock->DropLock();
2042 1152 : FlushBlock(nXBlockOff, nYBlockOff);
2043 1152 : ReportError(CE_Failure, CPLE_AppDefined,
2044 : "IReadBlock failed at X offset %d, Y offset %d%s",
2045 : nXBlockOff, nYBlockOff,
2046 1152 : (nErrorCounter != CPLGetErrorCounter())
2047 1150 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2048 : : "");
2049 1152 : return nullptr;
2050 : }
2051 :
2052 2806120 : nBlockReads++;
2053 2806120 : if (static_cast<GIntBig>(nBlockReads) ==
2054 2806120 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2055 216 : 1 &&
2056 216 : nBand == 1 && poDS != nullptr)
2057 : {
2058 156 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2059 156 : poDS->GetDescription());
2060 : }
2061 : }
2062 : }
2063 :
2064 10124100 : 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 169562 : 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 169562 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2103 : {
2104 6 : return CE_Failure;
2105 : }
2106 :
2107 : // Make sure block parameters are set.
2108 169556 : if (!InitBlockInfo())
2109 0 : return CE_Failure;
2110 :
2111 : // Allocate the source block.
2112 169556 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2113 169556 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2114 169556 : auto blockByteSize = blockSize * elementSize;
2115 : unsigned char *srcBlock =
2116 169556 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2117 169556 : 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 169556 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2128 169556 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2129 : elementSize, blockSize);
2130 :
2131 169556 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2132 :
2133 : // Write block to block cache
2134 651159 : for (int j = 0; j < nBlocksPerColumn; ++j)
2135 : {
2136 1257540 : for (int i = 0; i < nBlocksPerRow; ++i)
2137 : {
2138 775936 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2139 775936 : 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 775936 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2148 775936 : destBlock->MarkDirty();
2149 775936 : destBlock->DropLock();
2150 : }
2151 : }
2152 :
2153 169556 : if (bCallLeaveReadWrite)
2154 168981 : LeaveReadWrite();
2155 :
2156 : // Free up the source block
2157 169556 : VSIFree(srcBlock);
2158 :
2159 169556 : 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 169504 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2172 : double dfImaginaryValue)
2173 : {
2174 169504 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2175 :
2176 169504 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2177 169504 : 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 3000 : GDALAccess GDALRasterBand::GetAccess()
2193 :
2194 : {
2195 3000 : 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 2352 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2209 :
2210 : {
2211 2352 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2212 :
2213 2352 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2214 2352 : 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 294 : char **GDALRasterBand::GetCategoryNames()
2239 :
2240 : {
2241 294 : 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 183 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2255 :
2256 : {
2257 183 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2258 :
2259 183 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2260 183 : 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 31580 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2343 :
2344 : {
2345 31580 : if (pbSuccess != nullptr)
2346 31580 : *pbSuccess = FALSE;
2347 :
2348 31580 : 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 414194 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2362 : int *pbSuccess)
2363 :
2364 : {
2365 414194 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2366 :
2367 414194 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2368 414194 : 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 122 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2524 : bool *pbCannotBeExactlyRepresented)
2525 : {
2526 122 : if (pbCannotBeExactlyRepresented)
2527 122 : *pbCannotBeExactlyRepresented = false;
2528 122 : 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 117 : 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 116 : 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 106 : char *endptr = nullptr;
2590 106 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2591 212 : if (endptr == pszNoData + strlen(pszNoData) &&
2592 106 : GDALIsValueExactAs(dfVal, eDataType))
2593 : {
2594 105 : 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 825 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2669 : double dfValue)
2670 :
2671 : {
2672 825 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2673 :
2674 825 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2675 825 : 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 53 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2861 :
2862 : {
2863 53 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2864 :
2865 53 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2866 53 : 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 512 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2888 :
2889 : {
2890 512 : const char *pszValue = nullptr;
2891 :
2892 512 : 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 466 : if (pbSuccess != nullptr)
2901 462 : *pbSuccess = FALSE;
2902 :
2903 466 : switch (eDataType)
2904 : {
2905 317 : case GDT_Byte:
2906 : {
2907 317 : EnablePixelTypeSignedByteWarning(false);
2908 : const char *pszPixelType =
2909 317 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2910 317 : EnablePixelTypeSignedByteWarning(true);
2911 317 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2912 0 : return 127;
2913 :
2914 317 : return 255;
2915 : }
2916 :
2917 1 : case GDT_Int8:
2918 1 : return 127;
2919 :
2920 20 : case GDT_UInt16:
2921 20 : 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 280 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2970 :
2971 : {
2972 280 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2973 :
2974 280 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2975 280 : 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 520 : double GDALRasterBand::GetMinimum(int *pbSuccess)
2997 :
2998 : {
2999 520 : const char *pszValue = nullptr;
3000 :
3001 520 : 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 469 : if (pbSuccess != nullptr)
3010 465 : *pbSuccess = FALSE;
3011 :
3012 469 : switch (eDataType)
3013 : {
3014 320 : case GDT_Byte:
3015 : {
3016 320 : EnablePixelTypeSignedByteWarning(false);
3017 : const char *pszPixelType =
3018 320 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3019 320 : EnablePixelTypeSignedByteWarning(true);
3020 320 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3021 0 : return -128;
3022 :
3023 320 : return 0;
3024 : }
3025 :
3026 1 : case GDT_Int8:
3027 1 : return -128;
3028 : break;
3029 :
3030 20 : case GDT_UInt16:
3031 20 : 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 290 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3080 :
3081 : {
3082 290 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3083 :
3084 290 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3085 290 : 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 149 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
3105 :
3106 : {
3107 149 : 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 5402 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3122 :
3123 : {
3124 5402 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3125 :
3126 5402 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3127 5402 : 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 1815 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3168 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3169 :
3170 : {
3171 1815 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3172 :
3173 1815 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3174 1815 : 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 231 : GDALColorTable *GDALRasterBand::GetColorTable()
3194 :
3195 : {
3196 231 : 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 1882 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3210 :
3211 : {
3212 1882 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3213 :
3214 1882 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3215 1882 : 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 251 : int GDALRasterBand::HasArbitraryOverviews()
3291 :
3292 : {
3293 251 : return FALSE;
3294 : }
3295 :
3296 : /************************************************************************/
3297 : /* GDALHasArbitraryOverviews() */
3298 : /************************************************************************/
3299 :
3300 : /**
3301 : * \brief Check for arbitrary overviews.
3302 : *
3303 : * @see GDALRasterBand::HasArbitraryOverviews()
3304 : */
3305 :
3306 173 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3307 :
3308 : {
3309 173 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3310 :
3311 173 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3312 173 : 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 1065390 : int GDALRasterBand::GetOverviewCount()
3328 :
3329 : {
3330 1721890 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3331 656499 : poDS->AreOverviewsEnabled())
3332 656499 : return poDS->oOvManager.GetOverviewCount(nBand);
3333 :
3334 408893 : 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 3267 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3348 :
3349 : {
3350 3267 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3351 :
3352 3267 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3353 3267 : 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 826 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3371 :
3372 : {
3373 1597 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3374 771 : poDS->AreOverviewsEnabled())
3375 771 : 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 5646 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3391 :
3392 : {
3393 5646 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3394 :
3395 5646 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3396 5646 : 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 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3464 : int nDesiredSamples)
3465 :
3466 : {
3467 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3468 :
3469 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3470 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3471 0 : 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 2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3487 :
3488 : {
3489 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3490 :
3491 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3492 2000 : return GDALRasterBand::ToHandle(
3493 4000 : 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 460 : double GDALRasterBand::GetOffset(int *pbSuccess)
3572 :
3573 : {
3574 460 : if (pbSuccess != nullptr)
3575 351 : *pbSuccess = FALSE;
3576 :
3577 460 : 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 368 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3591 :
3592 : {
3593 368 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3594 :
3595 368 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3596 368 : 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 75 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3640 : double dfNewOffset)
3641 :
3642 : {
3643 75 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3644 :
3645 75 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3646 75 : 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 460 : double GDALRasterBand::GetScale(int *pbSuccess)
3678 :
3679 : {
3680 460 : if (pbSuccess != nullptr)
3681 351 : *pbSuccess = FALSE;
3682 :
3683 460 : 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 366 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3697 :
3698 : {
3699 366 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3700 :
3701 366 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3702 366 : 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 76 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3747 :
3748 : {
3749 76 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3750 :
3751 76 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3752 76 : 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 183 : const char *GDALRasterBand::GetUnitType()
3773 :
3774 : {
3775 183 : return "";
3776 : }
3777 :
3778 : /************************************************************************/
3779 : /* GDALGetRasterUnitType() */
3780 : /************************************************************************/
3781 :
3782 : /**
3783 : * \brief Return raster unit type.
3784 : *
3785 : * @see GDALRasterBand::GetUnitType()
3786 : */
3787 :
3788 1412 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3789 :
3790 : {
3791 1412 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3792 :
3793 1412 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3794 1412 : 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 75 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3842 : const char *pszNewValue)
3843 :
3844 : {
3845 75 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3846 :
3847 75 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3848 75 : 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 7949630 : int GDALRasterBand::GetXSize() const
3864 :
3865 : {
3866 7949630 : return nRasterXSize;
3867 : }
3868 :
3869 : /************************************************************************/
3870 : /* GDALGetRasterBandXSize() */
3871 : /************************************************************************/
3872 :
3873 : /**
3874 : * \brief Fetch XSize of raster.
3875 : *
3876 : * @see GDALRasterBand::GetXSize()
3877 : */
3878 :
3879 57379 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3880 :
3881 : {
3882 57379 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3883 :
3884 57379 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3885 57379 : 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 4250390 : int GDALRasterBand::GetYSize() const
3901 :
3902 : {
3903 4250390 : return nRasterYSize;
3904 : }
3905 :
3906 : /************************************************************************/
3907 : /* GDALGetRasterBandYSize() */
3908 : /************************************************************************/
3909 :
3910 : /**
3911 : * \brief Fetch YSize of raster.
3912 : *
3913 : * @see GDALRasterBand::GetYSize()
3914 : */
3915 :
3916 56244 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3917 :
3918 : {
3919 56244 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3920 :
3921 56244 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3922 56244 : 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 150411 : int GDALRasterBand::GetBand() const
3943 :
3944 : {
3945 150411 : return nBand;
3946 : }
3947 :
3948 : /************************************************************************/
3949 : /* GDALGetBandNumber() */
3950 : /************************************************************************/
3951 :
3952 : /**
3953 : * \brief Fetch the band number.
3954 : *
3955 : * @see GDALRasterBand::GetBand()
3956 : */
3957 :
3958 202 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3959 :
3960 : {
3961 202 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3962 :
3963 202 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3964 202 : 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 4550510 : GDALDataset *GDALRasterBand::GetDataset() const
3984 :
3985 : {
3986 4550510 : 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 440 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4000 :
4001 : {
4002 440 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4003 :
4004 440 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4005 440 : return GDALDataset::ToHandle(poBand->GetDataset());
4006 : }
4007 :
4008 : /************************************************************************/
4009 : /* ComputeFloat16NoDataValue() */
4010 : /************************************************************************/
4011 :
4012 2057 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4013 : double dfNoDataValue,
4014 : int &bGotNoDataValue,
4015 : GFloat16 &fNoDataValue,
4016 : bool &bGotFloat16NoDataValue)
4017 : {
4018 2057 : 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 2057 : }
4029 :
4030 : /************************************************************************/
4031 : /* ComputeFloatNoDataValue() */
4032 : /************************************************************************/
4033 :
4034 2057 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4035 : double dfNoDataValue,
4036 : int &bGotNoDataValue,
4037 : float &fNoDataValue,
4038 : bool &bGotFloatNoDataValue)
4039 : {
4040 2057 : if (eDataType == GDT_Float32 && bGotNoDataValue)
4041 : {
4042 84 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4043 84 : if (GDALIsValueInRange<float>(dfNoDataValue))
4044 : {
4045 84 : fNoDataValue = static_cast<float>(dfNoDataValue);
4046 84 : bGotFloatNoDataValue = true;
4047 84 : bGotNoDataValue = false;
4048 : }
4049 : }
4050 2057 : }
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 2057 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4076 2057 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4077 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4078 2057 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4079 : {
4080 2057 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4081 2057 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4082 :
4083 2057 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4084 2057 : fNoDataValue, bGotFloatNoDataValue);
4085 :
4086 2057 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4087 2057 : hfNoDataValue, bGotFloat16NoDataValue);
4088 2057 : }
4089 : };
4090 :
4091 : /************************************************************************/
4092 : /* ARE_REAL_EQUAL() */
4093 : /************************************************************************/
4094 :
4095 0 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4096 : {
4097 : using std::abs;
4098 0 : return dfVal1 == dfVal2 || /* Should cover infinity */
4099 0 : abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4100 0 : abs(dfVal1 + dfVal2) * ulp;
4101 : }
4102 :
4103 : /************************************************************************/
4104 : /* GetHistogram() */
4105 : /************************************************************************/
4106 :
4107 : /**
4108 : * \brief Compute raster histogram.
4109 : *
4110 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4111 : *
4112 : * For example to compute a simple 256 entry histogram of eight bit data,
4113 : * the following would be suitable. The unusual bounds are to ensure that
4114 : * bucket boundaries don't fall right on integer values causing possible errors
4115 : * due to rounding after scaling.
4116 : \code{.cpp}
4117 : GUIntBig anHistogram[256];
4118 :
4119 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4120 : GDALDummyProgress, nullptr );
4121 : \endcode
4122 : *
4123 : * Note that setting bApproxOK will generally result in a subsampling of the
4124 : * file, and will utilize overviews if available. It should generally
4125 : * produce a representative histogram for the data that is suitable for use
4126 : * in generating histogram based luts for instance. Generally bApproxOK is
4127 : * much faster than an exactly computed histogram.
4128 : *
4129 : * This method is the same as the C functions GDALGetRasterHistogram() and
4130 : * GDALGetRasterHistogramEx().
4131 : *
4132 : * @param dfMin the lower bound of the histogram.
4133 : * @param dfMax the upper bound of the histogram.
4134 : * @param nBuckets the number of buckets in panHistogram.
4135 : * @param panHistogram array into which the histogram totals are placed.
4136 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4137 : * mapped into panHistogram[0], and values above will be mapped into
4138 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4139 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4140 : * @param pfnProgress function to report progress to completion.
4141 : * @param pProgressData application data to pass to pfnProgress.
4142 : *
4143 : * @return CE_None on success, or CE_Failure if something goes wrong.
4144 : */
4145 :
4146 40 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4147 : GUIntBig *panHistogram,
4148 : int bIncludeOutOfRange, int bApproxOK,
4149 : GDALProgressFunc pfnProgress,
4150 : void *pProgressData)
4151 :
4152 : {
4153 40 : CPLAssert(nullptr != panHistogram);
4154 :
4155 40 : if (pfnProgress == nullptr)
4156 27 : pfnProgress = GDALDummyProgress;
4157 :
4158 : /* -------------------------------------------------------------------- */
4159 : /* If we have overviews, use them for the histogram. */
4160 : /* -------------------------------------------------------------------- */
4161 40 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4162 : {
4163 : // FIXME: should we use the most reduced overview here or use some
4164 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4165 : // does?
4166 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4167 :
4168 0 : if (poBestOverview != this)
4169 : {
4170 0 : return poBestOverview->GetHistogram(
4171 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4172 0 : bApproxOK, pfnProgress, pProgressData);
4173 : }
4174 : }
4175 :
4176 : /* -------------------------------------------------------------------- */
4177 : /* Read actual data and build histogram. */
4178 : /* -------------------------------------------------------------------- */
4179 40 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4180 : {
4181 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4182 0 : return CE_Failure;
4183 : }
4184 :
4185 : // Written this way to deal with NaN
4186 40 : if (!(dfMax > dfMin))
4187 : {
4188 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4189 : "dfMax should be strictly greater than dfMin");
4190 5 : return CE_Failure;
4191 : }
4192 :
4193 : GDALRasterIOExtraArg sExtraArg;
4194 35 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4195 :
4196 35 : const double dfScale = nBuckets / (dfMax - dfMin);
4197 35 : if (dfScale == 0 || !std::isfinite(dfScale))
4198 : {
4199 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4200 : "dfMin and dfMax should be finite values such that "
4201 : "nBuckets / (dfMax - dfMin) is non-zero");
4202 5 : return CE_Failure;
4203 : }
4204 30 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4205 :
4206 30 : GDALNoDataValues sNoDataValues(this, eDataType);
4207 30 : GDALRasterBand *poMaskBand = nullptr;
4208 30 : if (!sNoDataValues.bGotNoDataValue)
4209 : {
4210 29 : const int l_nMaskFlags = GetMaskFlags();
4211 30 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
4212 1 : GetColorInterpretation() != GCI_AlphaBand)
4213 : {
4214 1 : poMaskBand = GetMaskBand();
4215 : }
4216 : }
4217 :
4218 30 : bool bSignedByte = false;
4219 30 : if (eDataType == GDT_Byte)
4220 : {
4221 23 : EnablePixelTypeSignedByteWarning(false);
4222 : const char *pszPixelType =
4223 23 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4224 23 : EnablePixelTypeSignedByteWarning(true);
4225 23 : bSignedByte =
4226 23 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4227 : }
4228 :
4229 30 : if (bApproxOK && HasArbitraryOverviews())
4230 : {
4231 : /* --------------------------------------------------------------------
4232 : */
4233 : /* Figure out how much the image should be reduced to get an */
4234 : /* approximate value. */
4235 : /* --------------------------------------------------------------------
4236 : */
4237 : const double dfReduction =
4238 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4239 : GDALSTAT_APPROX_NUMSAMPLES);
4240 :
4241 0 : int nXReduced = nRasterXSize;
4242 0 : int nYReduced = nRasterYSize;
4243 0 : if (dfReduction > 1.0)
4244 : {
4245 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4246 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4247 :
4248 : // Catch the case of huge resizing ratios here
4249 0 : if (nXReduced == 0)
4250 0 : nXReduced = 1;
4251 0 : if (nYReduced == 0)
4252 0 : nYReduced = 1;
4253 : }
4254 :
4255 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4256 : nXReduced, nYReduced);
4257 0 : if (!pData)
4258 0 : return CE_Failure;
4259 :
4260 : const CPLErr eErr =
4261 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4262 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4263 0 : if (eErr != CE_None)
4264 : {
4265 0 : CPLFree(pData);
4266 0 : return eErr;
4267 : }
4268 :
4269 0 : GByte *pabyMaskData = nullptr;
4270 0 : if (poMaskBand)
4271 : {
4272 : pabyMaskData =
4273 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4274 0 : if (!pabyMaskData)
4275 : {
4276 0 : CPLFree(pData);
4277 0 : return CE_Failure;
4278 : }
4279 :
4280 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4281 : pabyMaskData, nXReduced, nYReduced,
4282 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
4283 : {
4284 0 : CPLFree(pData);
4285 0 : CPLFree(pabyMaskData);
4286 0 : return CE_Failure;
4287 : }
4288 : }
4289 :
4290 : // This isn't the fastest way to do this, but is easier for now.
4291 0 : for (int iY = 0; iY < nYReduced; iY++)
4292 : {
4293 0 : for (int iX = 0; iX < nXReduced; iX++)
4294 : {
4295 0 : const int iOffset = iX + iY * nXReduced;
4296 0 : double dfValue = 0.0;
4297 :
4298 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4299 0 : continue;
4300 :
4301 0 : switch (eDataType)
4302 : {
4303 0 : case GDT_Byte:
4304 : {
4305 0 : if (bSignedByte)
4306 0 : dfValue =
4307 0 : static_cast<signed char *>(pData)[iOffset];
4308 : else
4309 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4310 0 : break;
4311 : }
4312 0 : case GDT_Int8:
4313 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4314 0 : break;
4315 0 : case GDT_UInt16:
4316 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4317 0 : break;
4318 0 : case GDT_Int16:
4319 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4320 0 : break;
4321 0 : case GDT_UInt32:
4322 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4323 0 : break;
4324 0 : case GDT_Int32:
4325 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4326 0 : break;
4327 0 : case GDT_UInt64:
4328 0 : dfValue = static_cast<double>(
4329 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4330 0 : break;
4331 0 : case GDT_Int64:
4332 0 : dfValue = static_cast<double>(
4333 0 : static_cast<GInt64 *>(pData)[iOffset]);
4334 0 : break;
4335 0 : case GDT_Float16:
4336 : {
4337 : using namespace std;
4338 0 : const GFloat16 hfValue =
4339 0 : static_cast<GFloat16 *>(pData)[iOffset];
4340 0 : if (isnan(hfValue) ||
4341 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4342 0 : ARE_REAL_EQUAL(hfValue,
4343 : sNoDataValues.hfNoDataValue)))
4344 0 : continue;
4345 0 : dfValue = hfValue;
4346 0 : break;
4347 : }
4348 0 : case GDT_Float32:
4349 : {
4350 0 : const float fValue =
4351 0 : static_cast<float *>(pData)[iOffset];
4352 0 : if (std::isnan(fValue) ||
4353 0 : (sNoDataValues.bGotFloatNoDataValue &&
4354 0 : ARE_REAL_EQUAL(fValue,
4355 : sNoDataValues.fNoDataValue)))
4356 0 : continue;
4357 0 : dfValue = fValue;
4358 0 : break;
4359 : }
4360 0 : case GDT_Float64:
4361 0 : dfValue = static_cast<double *>(pData)[iOffset];
4362 0 : if (std::isnan(dfValue))
4363 0 : continue;
4364 0 : break;
4365 0 : case GDT_CInt16:
4366 : {
4367 0 : const double dfReal =
4368 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4369 0 : const double dfImag =
4370 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4371 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4372 0 : continue;
4373 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4374 : }
4375 0 : break;
4376 0 : case GDT_CInt32:
4377 : {
4378 0 : const double dfReal =
4379 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4380 0 : const double dfImag =
4381 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4382 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4383 0 : continue;
4384 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4385 : }
4386 0 : break;
4387 0 : case GDT_CFloat16:
4388 : {
4389 : const double dfReal =
4390 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4391 : const double dfImag =
4392 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4393 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4394 0 : continue;
4395 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4396 0 : break;
4397 : }
4398 0 : case GDT_CFloat32:
4399 : {
4400 0 : const double dfReal =
4401 0 : static_cast<float *>(pData)[iOffset * 2];
4402 0 : const double dfImag =
4403 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
4404 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4405 0 : continue;
4406 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4407 0 : break;
4408 : }
4409 0 : case GDT_CFloat64:
4410 : {
4411 0 : const double dfReal =
4412 0 : static_cast<double *>(pData)[iOffset * 2];
4413 0 : const double dfImag =
4414 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4415 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4416 0 : continue;
4417 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4418 0 : break;
4419 : }
4420 0 : case GDT_Unknown:
4421 : case GDT_TypeCount:
4422 0 : CPLAssert(false);
4423 : }
4424 :
4425 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4426 0 : sNoDataValues.bGotNoDataValue &&
4427 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4428 0 : continue;
4429 :
4430 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4431 : // finite, the result of the multiplication cannot be NaN
4432 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4433 :
4434 0 : if (dfIndex < 0)
4435 : {
4436 0 : if (bIncludeOutOfRange)
4437 0 : panHistogram[0]++;
4438 : }
4439 0 : else if (dfIndex >= nBuckets)
4440 : {
4441 0 : if (bIncludeOutOfRange)
4442 0 : ++panHistogram[nBuckets - 1];
4443 : }
4444 : else
4445 : {
4446 0 : ++panHistogram[static_cast<int>(dfIndex)];
4447 : }
4448 : }
4449 : }
4450 :
4451 0 : CPLFree(pData);
4452 0 : CPLFree(pabyMaskData);
4453 : }
4454 : else // No arbitrary overviews.
4455 : {
4456 30 : if (!InitBlockInfo())
4457 0 : return CE_Failure;
4458 :
4459 : /* --------------------------------------------------------------------
4460 : */
4461 : /* Figure out the ratio of blocks we will read to get an */
4462 : /* approximate value. */
4463 : /* --------------------------------------------------------------------
4464 : */
4465 :
4466 30 : int nSampleRate = 1;
4467 30 : if (bApproxOK)
4468 : {
4469 8 : nSampleRate = static_cast<int>(std::max(
4470 16 : 1.0,
4471 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4472 : // We want to avoid probing only the first column of blocks for
4473 : // a square shaped raster, because it is not unlikely that it may
4474 : // be padding only (#6378).
4475 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4476 1 : nSampleRate += 1;
4477 : }
4478 :
4479 30 : GByte *pabyMaskData = nullptr;
4480 30 : if (poMaskBand)
4481 : {
4482 : pabyMaskData = static_cast<GByte *>(
4483 1 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4484 1 : if (!pabyMaskData)
4485 : {
4486 0 : return CE_Failure;
4487 : }
4488 : }
4489 :
4490 : /* --------------------------------------------------------------------
4491 : */
4492 : /* Read the blocks, and add to histogram. */
4493 : /* --------------------------------------------------------------------
4494 : */
4495 30 : for (GIntBig iSampleBlock = 0;
4496 150 : iSampleBlock <
4497 150 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4498 120 : iSampleBlock += nSampleRate)
4499 : {
4500 120 : if (!pfnProgress(
4501 120 : static_cast<double>(iSampleBlock) /
4502 120 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4503 : "Compute Histogram", pProgressData))
4504 : {
4505 0 : CPLFree(pabyMaskData);
4506 0 : return CE_Failure;
4507 : }
4508 :
4509 120 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4510 120 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4511 :
4512 120 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4513 120 : if (poBlock == nullptr)
4514 : {
4515 0 : CPLFree(pabyMaskData);
4516 0 : return CE_Failure;
4517 : }
4518 :
4519 120 : void *pData = poBlock->GetDataRef();
4520 :
4521 120 : int nXCheck = 0, nYCheck = 0;
4522 120 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4523 :
4524 121 : if (poMaskBand &&
4525 1 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4526 1 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4527 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4528 1 : 0, nBlockXSize, nullptr) != CE_None)
4529 : {
4530 0 : CPLFree(pabyMaskData);
4531 0 : poBlock->DropLock();
4532 0 : return CE_Failure;
4533 : }
4534 :
4535 : // this is a special case for a common situation.
4536 120 : if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4537 86 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4538 83 : nXCheck == nBlockXSize && nBuckets == 256)
4539 : {
4540 83 : const GPtrDiff_t nPixels =
4541 83 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4542 83 : GByte *pabyData = static_cast<GByte *>(pData);
4543 :
4544 72137 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4545 : {
4546 72054 : if (pabyMaskData && pabyMaskData[i] == 0)
4547 0 : continue;
4548 72054 : if (!(sNoDataValues.bGotNoDataValue &&
4549 512 : (pabyData[i] ==
4550 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4551 : {
4552 71798 : panHistogram[pabyData[i]]++;
4553 : }
4554 : }
4555 :
4556 83 : poBlock->DropLock();
4557 83 : continue; // To next sample block.
4558 : }
4559 :
4560 : // This isn't the fastest way to do this, but is easier for now.
4561 253 : for (int iY = 0; iY < nYCheck; iY++)
4562 : {
4563 36385 : for (int iX = 0; iX < nXCheck; iX++)
4564 : {
4565 36169 : const GPtrDiff_t iOffset =
4566 36169 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4567 :
4568 36169 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4569 1 : continue;
4570 :
4571 36168 : double dfValue = 0.0;
4572 :
4573 36168 : switch (eDataType)
4574 : {
4575 19716 : case GDT_Byte:
4576 : {
4577 19716 : if (bSignedByte)
4578 0 : dfValue =
4579 0 : static_cast<signed char *>(pData)[iOffset];
4580 : else
4581 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4582 19716 : break;
4583 : }
4584 0 : case GDT_Int8:
4585 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4586 0 : break;
4587 16384 : case GDT_UInt16:
4588 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4589 16384 : break;
4590 2 : case GDT_Int16:
4591 2 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4592 2 : break;
4593 0 : case GDT_UInt32:
4594 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4595 0 : break;
4596 60 : case GDT_Int32:
4597 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4598 60 : break;
4599 0 : case GDT_UInt64:
4600 0 : dfValue = static_cast<double>(
4601 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4602 0 : break;
4603 0 : case GDT_Int64:
4604 0 : dfValue = static_cast<double>(
4605 0 : static_cast<GInt64 *>(pData)[iOffset]);
4606 0 : break;
4607 0 : case GDT_Float16:
4608 : {
4609 : using namespace std;
4610 0 : const GFloat16 hfValue =
4611 0 : static_cast<GFloat16 *>(pData)[iOffset];
4612 0 : if (isnan(hfValue) ||
4613 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4614 0 : ARE_REAL_EQUAL(hfValue,
4615 : sNoDataValues.hfNoDataValue)))
4616 0 : continue;
4617 0 : dfValue = hfValue;
4618 0 : break;
4619 : }
4620 4 : case GDT_Float32:
4621 : {
4622 4 : const float fValue =
4623 4 : static_cast<float *>(pData)[iOffset];
4624 8 : if (std::isnan(fValue) ||
4625 8 : (sNoDataValues.bGotFloatNoDataValue &&
4626 4 : ARE_REAL_EQUAL(fValue,
4627 : sNoDataValues.fNoDataValue)))
4628 1 : continue;
4629 3 : dfValue = fValue;
4630 3 : break;
4631 : }
4632 2 : case GDT_Float64:
4633 2 : dfValue = static_cast<double *>(pData)[iOffset];
4634 2 : if (std::isnan(dfValue))
4635 0 : continue;
4636 2 : break;
4637 0 : case GDT_CInt16:
4638 : {
4639 0 : double dfReal =
4640 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4641 0 : double dfImag =
4642 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4643 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4644 0 : break;
4645 : }
4646 0 : case GDT_CInt32:
4647 : {
4648 0 : double dfReal =
4649 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4650 0 : double dfImag =
4651 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4652 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4653 0 : break;
4654 : }
4655 0 : case GDT_CFloat16:
4656 : {
4657 : double dfReal =
4658 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4659 : double dfImag =
4660 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4661 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4662 0 : continue;
4663 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4664 0 : break;
4665 : }
4666 0 : case GDT_CFloat32:
4667 : {
4668 0 : double dfReal =
4669 0 : static_cast<float *>(pData)[iOffset * 2];
4670 0 : double dfImag =
4671 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
4672 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4673 0 : continue;
4674 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4675 0 : break;
4676 : }
4677 0 : case GDT_CFloat64:
4678 : {
4679 0 : double dfReal =
4680 0 : static_cast<double *>(pData)[iOffset * 2];
4681 0 : double dfImag =
4682 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4683 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4684 0 : continue;
4685 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4686 0 : break;
4687 : }
4688 0 : case GDT_Unknown:
4689 : case GDT_TypeCount:
4690 0 : CPLAssert(false);
4691 : CPLFree(pabyMaskData);
4692 : return CE_Failure;
4693 : }
4694 :
4695 36167 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4696 72334 : sNoDataValues.bGotNoDataValue &&
4697 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4698 0 : continue;
4699 :
4700 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4701 : // and finite, the result of the multiplication cannot be
4702 : // NaN
4703 36167 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4704 :
4705 36167 : if (dfIndex < 0)
4706 : {
4707 1 : if (bIncludeOutOfRange)
4708 1 : panHistogram[0]++;
4709 : }
4710 36166 : else if (dfIndex >= nBuckets)
4711 : {
4712 7 : if (bIncludeOutOfRange)
4713 4 : ++panHistogram[nBuckets - 1];
4714 : }
4715 : else
4716 : {
4717 36159 : ++panHistogram[static_cast<int>(dfIndex)];
4718 : }
4719 : }
4720 : }
4721 :
4722 37 : poBlock->DropLock();
4723 : }
4724 :
4725 30 : CPLFree(pabyMaskData);
4726 : }
4727 :
4728 30 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4729 :
4730 30 : return CE_None;
4731 : }
4732 :
4733 : /************************************************************************/
4734 : /* GDALGetRasterHistogram() */
4735 : /************************************************************************/
4736 :
4737 : /**
4738 : * \brief Compute raster histogram.
4739 : *
4740 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4741 : * exceeding 2 billion.
4742 : *
4743 : * @see GDALRasterBand::GetHistogram()
4744 : * @see GDALGetRasterHistogramEx()
4745 : */
4746 :
4747 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4748 : double dfMax, int nBuckets,
4749 : int *panHistogram,
4750 : int bIncludeOutOfRange, int bApproxOK,
4751 : GDALProgressFunc pfnProgress,
4752 : void *pProgressData)
4753 :
4754 : {
4755 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4756 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4757 :
4758 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4759 :
4760 : GUIntBig *panHistogramTemp =
4761 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4762 0 : if (panHistogramTemp == nullptr)
4763 : {
4764 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4765 : "Out of memory in GDALGetRasterHistogram().");
4766 0 : return CE_Failure;
4767 : }
4768 :
4769 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4770 : bIncludeOutOfRange, bApproxOK,
4771 0 : pfnProgress, pProgressData);
4772 :
4773 0 : if (eErr == CE_None)
4774 : {
4775 0 : for (int i = 0; i < nBuckets; i++)
4776 : {
4777 0 : if (panHistogramTemp[i] > INT_MAX)
4778 : {
4779 0 : CPLError(CE_Warning, CPLE_AppDefined,
4780 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4781 : " exceeds maximum 32 bit value",
4782 0 : i, panHistogramTemp[i]);
4783 0 : panHistogram[i] = INT_MAX;
4784 : }
4785 : else
4786 : {
4787 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4788 : }
4789 : }
4790 : }
4791 :
4792 0 : CPLFree(panHistogramTemp);
4793 :
4794 0 : return eErr;
4795 : }
4796 :
4797 : /************************************************************************/
4798 : /* GDALGetRasterHistogramEx() */
4799 : /************************************************************************/
4800 :
4801 : /**
4802 : * \brief Compute raster histogram.
4803 : *
4804 : * @see GDALRasterBand::GetHistogram()
4805 : *
4806 : * @since GDAL 2.0
4807 : */
4808 :
4809 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4810 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4811 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4812 : GDALProgressFunc pfnProgress, void *pProgressData)
4813 :
4814 : {
4815 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4816 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4817 :
4818 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4819 :
4820 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4821 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4822 26 : pProgressData);
4823 : }
4824 :
4825 : /************************************************************************/
4826 : /* GetDefaultHistogram() */
4827 : /************************************************************************/
4828 :
4829 : /**
4830 : * \brief Fetch default raster histogram.
4831 : *
4832 : * The default method in GDALRasterBand will compute a default histogram. This
4833 : * method is overridden by derived classes (such as GDALPamRasterBand,
4834 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4835 : * stored histogram.
4836 : *
4837 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4838 : * GDALGetDefaultHistogramEx().
4839 : *
4840 : * @param pdfMin pointer to double value that will contain the lower bound of
4841 : * the histogram.
4842 : * @param pdfMax pointer to double value that will contain the upper bound of
4843 : * the histogram.
4844 : * @param pnBuckets pointer to int value that will contain the number of buckets
4845 : * in *ppanHistogram.
4846 : * @param ppanHistogram pointer to array into which the histogram totals are
4847 : * placed. To be freed with VSIFree
4848 : * @param bForce TRUE to force the computation. If FALSE and no default
4849 : * histogram is available, the method will return CE_Warning
4850 : * @param pfnProgress function to report progress to completion.
4851 : * @param pProgressData application data to pass to pfnProgress.
4852 : *
4853 : * @return CE_None on success, CE_Failure if something goes wrong, or
4854 : * CE_Warning if no default histogram is available.
4855 : */
4856 :
4857 22 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4858 : int *pnBuckets,
4859 : GUIntBig **ppanHistogram, int bForce,
4860 : GDALProgressFunc pfnProgress,
4861 : void *pProgressData)
4862 :
4863 : {
4864 22 : CPLAssert(nullptr != pnBuckets);
4865 22 : CPLAssert(nullptr != ppanHistogram);
4866 22 : CPLAssert(nullptr != pdfMin);
4867 22 : CPLAssert(nullptr != pdfMax);
4868 :
4869 22 : *pnBuckets = 0;
4870 22 : *ppanHistogram = nullptr;
4871 :
4872 22 : if (!bForce)
4873 5 : return CE_Warning;
4874 :
4875 17 : const int nBuckets = 256;
4876 :
4877 17 : bool bSignedByte = false;
4878 17 : if (eDataType == GDT_Byte)
4879 : {
4880 17 : EnablePixelTypeSignedByteWarning(false);
4881 : const char *pszPixelType =
4882 17 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4883 17 : EnablePixelTypeSignedByteWarning(true);
4884 17 : bSignedByte =
4885 17 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4886 : }
4887 :
4888 17 : if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4889 : {
4890 17 : *pdfMin = -0.5;
4891 17 : *pdfMax = 255.5;
4892 : }
4893 : else
4894 : {
4895 :
4896 : const CPLErr eErr =
4897 0 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4898 0 : const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4899 0 : *pdfMin -= dfHalfBucket;
4900 0 : *pdfMax += dfHalfBucket;
4901 :
4902 0 : if (eErr != CE_None)
4903 0 : return eErr;
4904 : }
4905 :
4906 17 : *ppanHistogram =
4907 17 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4908 17 : if (*ppanHistogram == nullptr)
4909 : {
4910 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4911 : "Out of memory in InitBlockInfo().");
4912 0 : return CE_Failure;
4913 : }
4914 :
4915 17 : *pnBuckets = nBuckets;
4916 34 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4917 17 : TRUE, FALSE, pfnProgress, pProgressData);
4918 17 : if (eErr != CE_None)
4919 : {
4920 0 : *pnBuckets = 0;
4921 : }
4922 17 : return eErr;
4923 : }
4924 :
4925 : /************************************************************************/
4926 : /* GDALGetDefaultHistogram() */
4927 : /************************************************************************/
4928 :
4929 : /**
4930 : * \brief Fetch default raster histogram.
4931 : *
4932 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4933 : * exceeding 2 billion.
4934 : *
4935 : * @see GDALRasterBand::GDALGetDefaultHistogram()
4936 : * @see GDALGetRasterHistogramEx()
4937 : */
4938 :
4939 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4940 : double *pdfMin, double *pdfMax,
4941 : int *pnBuckets, int **ppanHistogram,
4942 : int bForce,
4943 : GDALProgressFunc pfnProgress,
4944 : void *pProgressData)
4945 :
4946 : {
4947 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4948 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4949 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4950 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4951 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4952 :
4953 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4954 0 : GUIntBig *panHistogramTemp = nullptr;
4955 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
4956 : &panHistogramTemp, bForce,
4957 0 : pfnProgress, pProgressData);
4958 0 : if (eErr == CE_None)
4959 : {
4960 0 : const int nBuckets = *pnBuckets;
4961 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
4962 0 : if (*ppanHistogram == nullptr)
4963 : {
4964 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4965 : "Out of memory in GDALGetDefaultHistogram().");
4966 0 : VSIFree(panHistogramTemp);
4967 0 : return CE_Failure;
4968 : }
4969 :
4970 0 : for (int i = 0; i < nBuckets; ++i)
4971 : {
4972 0 : if (panHistogramTemp[i] > INT_MAX)
4973 : {
4974 0 : CPLError(CE_Warning, CPLE_AppDefined,
4975 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4976 : " exceeds maximum 32 bit value",
4977 0 : i, panHistogramTemp[i]);
4978 0 : (*ppanHistogram)[i] = INT_MAX;
4979 : }
4980 : else
4981 : {
4982 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
4983 : }
4984 : }
4985 :
4986 0 : CPLFree(panHistogramTemp);
4987 : }
4988 : else
4989 : {
4990 0 : *ppanHistogram = nullptr;
4991 : }
4992 :
4993 0 : return eErr;
4994 : }
4995 :
4996 : /************************************************************************/
4997 : /* GDALGetDefaultHistogramEx() */
4998 : /************************************************************************/
4999 :
5000 : /**
5001 : * \brief Fetch default raster histogram.
5002 : *
5003 : * @see GDALRasterBand::GetDefaultHistogram()
5004 : *
5005 : * @since GDAL 2.0
5006 : */
5007 :
5008 : CPLErr CPL_STDCALL
5009 28 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5010 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5011 : GDALProgressFunc pfnProgress, void *pProgressData)
5012 :
5013 : {
5014 28 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5015 28 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5016 28 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5017 28 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5018 28 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5019 :
5020 28 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5021 28 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5022 28 : bForce, pfnProgress, pProgressData);
5023 : }
5024 :
5025 : /************************************************************************/
5026 : /* AdviseRead() */
5027 : /************************************************************************/
5028 :
5029 : /**
5030 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5031 : * \brief Advise driver of upcoming read requests.
5032 : *
5033 : * Some GDAL drivers operate more efficiently if they know in advance what
5034 : * set of upcoming read requests will be made. The AdviseRead() method allows
5035 : * an application to notify the driver of the region of interest,
5036 : * and at what resolution the region will be read.
5037 : *
5038 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
5039 : * accelerate access via some drivers.
5040 : *
5041 : * Depending on call paths, drivers might receive several calls to
5042 : * AdviseRead() with the same parameters.
5043 : *
5044 : * @param nXOff The pixel offset to the top left corner of the region
5045 : * of the band to be accessed. This would be zero to start from the left side.
5046 : *
5047 : * @param nYOff The line offset to the top left corner of the region
5048 : * of the band to be accessed. This would be zero to start from the top.
5049 : *
5050 : * @param nXSize The width of the region of the band to be accessed in pixels.
5051 : *
5052 : * @param nYSize The height of the region of the band to be accessed in lines.
5053 : *
5054 : * @param nBufXSize the width of the buffer image into which the desired region
5055 : * is to be read, or from which it is to be written.
5056 : *
5057 : * @param nBufYSize the height of the buffer image into which the desired
5058 : * region is to be read, or from which it is to be written.
5059 : *
5060 : * @param eBufType the type of the pixel values in the pData data buffer. The
5061 : * pixel values will automatically be translated to/from the GDALRasterBand
5062 : * data type as needed.
5063 : *
5064 : * @param papszOptions a list of name=value strings with special control
5065 : * options. Normally this is NULL.
5066 : *
5067 : * @return CE_Failure if the request is invalid and CE_None if it works or
5068 : * is ignored.
5069 : */
5070 :
5071 : /**/
5072 : /**/
5073 :
5074 113773 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5075 : int /*nYSize*/, int /*nBufXSize*/,
5076 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5077 : char ** /*papszOptions*/)
5078 : {
5079 113773 : return CE_None;
5080 : }
5081 :
5082 : /************************************************************************/
5083 : /* GDALRasterAdviseRead() */
5084 : /************************************************************************/
5085 :
5086 : /**
5087 : * \brief Advise driver of upcoming read requests.
5088 : *
5089 : * @see GDALRasterBand::AdviseRead()
5090 : */
5091 :
5092 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5093 : int nYOff, int nXSize, int nYSize,
5094 : int nBufXSize, int nBufYSize,
5095 : GDALDataType eDT,
5096 : CSLConstList papszOptions)
5097 :
5098 : {
5099 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5100 :
5101 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5102 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5103 : nBufYSize, eDT,
5104 2 : const_cast<char **>(papszOptions));
5105 : }
5106 :
5107 : /************************************************************************/
5108 : /* GetStatistics() */
5109 : /************************************************************************/
5110 :
5111 : /**
5112 : * \brief Fetch image statistics.
5113 : *
5114 : * Returns the minimum, maximum, mean and standard deviation of all
5115 : * pixel values in this band. If approximate statistics are sufficient,
5116 : * the bApproxOK flag can be set to true in which case overviews, or a
5117 : * subset of image tiles may be used in computing the statistics.
5118 : *
5119 : * If bForce is FALSE results will only be returned if it can be done
5120 : * quickly (i.e. without scanning the image, typically by using pre-existing
5121 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5122 : * returned efficiently, the method will return CE_Warning but no warning will
5123 : * be issued. This is a non-standard use of the CE_Warning return value
5124 : * to indicate "nothing done".
5125 : *
5126 : * If bForce is TRUE, and results are quickly available without scanning the
5127 : * image, they will be used. If bForce is TRUE and results are not quickly
5128 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5129 : * which will scan the image.
5130 : *
5131 : * To always force recomputation of statistics, use ComputeStatistics() instead
5132 : * of this method.
5133 : *
5134 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5135 : * will generally cache statistics in the .pam file allowing fast fetch
5136 : * after the first request.
5137 : *
5138 : * This method is the same as the C function GDALGetRasterStatistics().
5139 : *
5140 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5141 : * or a subset of all tiles.
5142 : *
5143 : * @param bForce If FALSE statistics will only be returned if it can
5144 : * be done without rescanning the image. If TRUE, statistics computation will
5145 : * be forced if pre-existing values are not quickly available.
5146 : *
5147 : * @param pdfMin Location into which to load image minimum (may be NULL).
5148 : *
5149 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5150 : *
5151 : * @param pdfMean Location into which to load image mean (may be NULL).
5152 : *
5153 : * @param pdfStdDev Location into which to load image standard deviation
5154 : * (may be NULL).
5155 : *
5156 : * @return CE_None on success, CE_Warning if no values returned,
5157 : * CE_Failure if an error occurs.
5158 : */
5159 :
5160 619 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5161 : double *pdfMax, double *pdfMean,
5162 : double *pdfStdDev)
5163 :
5164 : {
5165 : /* -------------------------------------------------------------------- */
5166 : /* Do we already have metadata items for the requested values? */
5167 : /* -------------------------------------------------------------------- */
5168 1238 : if ((pdfMin == nullptr ||
5169 619 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5170 202 : (pdfMax == nullptr ||
5171 202 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5172 1440 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5173 202 : (pdfStdDev == nullptr ||
5174 202 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5175 : {
5176 202 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5177 : {
5178 195 : if (pdfMin != nullptr)
5179 195 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5180 195 : if (pdfMax != nullptr)
5181 195 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5182 195 : if (pdfMean != nullptr)
5183 195 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5184 195 : if (pdfStdDev != nullptr)
5185 195 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5186 :
5187 195 : return CE_None;
5188 : }
5189 : }
5190 :
5191 : /* -------------------------------------------------------------------- */
5192 : /* Does the driver already know the min/max? */
5193 : /* -------------------------------------------------------------------- */
5194 424 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5195 : {
5196 0 : int bSuccessMin = FALSE;
5197 0 : int bSuccessMax = FALSE;
5198 :
5199 0 : const double dfMin = GetMinimum(&bSuccessMin);
5200 0 : const double dfMax = GetMaximum(&bSuccessMax);
5201 :
5202 0 : if (bSuccessMin && bSuccessMax)
5203 : {
5204 0 : if (pdfMin != nullptr)
5205 0 : *pdfMin = dfMin;
5206 0 : if (pdfMax != nullptr)
5207 0 : *pdfMax = dfMax;
5208 0 : return CE_None;
5209 : }
5210 : }
5211 :
5212 : /* -------------------------------------------------------------------- */
5213 : /* Either return without results, or force computation. */
5214 : /* -------------------------------------------------------------------- */
5215 424 : if (!bForce)
5216 169 : return CE_Warning;
5217 : else
5218 255 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5219 255 : GDALDummyProgress, nullptr);
5220 : }
5221 :
5222 : /************************************************************************/
5223 : /* GDALGetRasterStatistics() */
5224 : /************************************************************************/
5225 :
5226 : /**
5227 : * \brief Fetch image statistics.
5228 : *
5229 : * @see GDALRasterBand::GetStatistics()
5230 : */
5231 :
5232 268 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5233 : int bForce, double *pdfMin,
5234 : double *pdfMax, double *pdfMean,
5235 : double *pdfStdDev)
5236 :
5237 : {
5238 268 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5239 :
5240 268 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5241 268 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5242 268 : pdfStdDev);
5243 : }
5244 :
5245 : /************************************************************************/
5246 : /* GDALUInt128 */
5247 : /************************************************************************/
5248 :
5249 : #ifdef HAVE_UINT128_T
5250 : class GDALUInt128
5251 : {
5252 : __uint128_t val;
5253 :
5254 639 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5255 : {
5256 639 : }
5257 :
5258 : public:
5259 426 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5260 : {
5261 : // Evaluates to just a single mul on x86_64
5262 426 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5263 : }
5264 :
5265 213 : GDALUInt128 operator-(const GDALUInt128 &other) const
5266 : {
5267 213 : return GDALUInt128(val - other.val);
5268 : }
5269 :
5270 204 : operator double() const
5271 : {
5272 204 : return static_cast<double>(val);
5273 : }
5274 : };
5275 : #else
5276 :
5277 : #if defined(_MSC_VER) && defined(_M_X64)
5278 : #include <intrin.h>
5279 : #endif
5280 :
5281 : class GDALUInt128
5282 : {
5283 : GUIntBig low, high;
5284 :
5285 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5286 : {
5287 : }
5288 :
5289 : public:
5290 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5291 : {
5292 : #if defined(_MSC_VER) && defined(_M_X64)
5293 : GUIntBig highRes;
5294 : GUIntBig lowRes = _umul128(first, second, &highRes);
5295 : return GDALUInt128(lowRes, highRes);
5296 : #else
5297 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5298 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5299 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5300 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5301 : GUIntBig highRes = 0;
5302 : const GUIntBig firstLowSecondHigh =
5303 : static_cast<GUIntBig>(firstLow) * secondHigh;
5304 : const GUIntBig firstHighSecondLow =
5305 : static_cast<GUIntBig>(firstHigh) * secondLow;
5306 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5307 : if (middleTerm < firstLowSecondHigh) // check for overflow
5308 : highRes += static_cast<GUIntBig>(1) << 32;
5309 : const GUIntBig firstLowSecondLow =
5310 : static_cast<GUIntBig>(firstLow) * secondLow;
5311 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5312 : if (lowRes < firstLowSecondLow) // check for overflow
5313 : highRes++;
5314 : highRes +=
5315 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5316 : return GDALUInt128(lowRes, highRes);
5317 : #endif
5318 : }
5319 :
5320 : GDALUInt128 operator-(const GDALUInt128 &other) const
5321 : {
5322 : GUIntBig highRes = high - other.high;
5323 : GUIntBig lowRes = low - other.low;
5324 : if (lowRes > low) // check for underflow
5325 : --highRes;
5326 : return GDALUInt128(lowRes, highRes);
5327 : }
5328 :
5329 : operator double() const
5330 : {
5331 : const double twoPow64 = 18446744073709551616.0;
5332 : return high * twoPow64 + low;
5333 : }
5334 : };
5335 : #endif
5336 :
5337 : /************************************************************************/
5338 : /* ComputeStatisticsInternal() */
5339 : /************************************************************************/
5340 :
5341 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5342 : // not needed.
5343 : #define static_cast_for_coverity_scan static_cast
5344 :
5345 : // The rationale for below optimizations is detailed in statistics.txt
5346 :
5347 : // Use with T = GByte or GUInt16 only !
5348 : template <class T, bool COMPUTE_OTHER_STATS>
5349 : struct ComputeStatisticsInternalGeneric
5350 : {
5351 206 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5352 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5353 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5354 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5355 : {
5356 : static_assert(std::is_same<T, GByte>::value ||
5357 : std::is_same<T, GUInt16>::value,
5358 : "bad type for T");
5359 206 : if (bHasNoData)
5360 : {
5361 : // General case
5362 386 : for (int iY = 0; iY < nYCheck; iY++)
5363 : {
5364 81751 : for (int iX = 0; iX < nXCheck; iX++)
5365 : {
5366 81468 : const GPtrDiff_t iOffset =
5367 81468 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5368 81468 : const GUInt32 nValue = pData[iOffset];
5369 81468 : if (nValue == nNoDataValue)
5370 175 : continue;
5371 81293 : if (nValue < nMin)
5372 26 : nMin = nValue;
5373 81293 : if (nValue > nMax)
5374 57 : nMax = nValue;
5375 : if constexpr (COMPUTE_OTHER_STATS)
5376 : {
5377 79657 : nValidCount++;
5378 79657 : nSum += nValue;
5379 79657 : nSumSquare +=
5380 79657 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5381 79657 : nValue;
5382 : }
5383 : }
5384 : }
5385 : if constexpr (COMPUTE_OTHER_STATS)
5386 : {
5387 20 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5388 : }
5389 : }
5390 113 : else if (nMin == std::numeric_limits<T>::lowest() &&
5391 10 : nMax == std::numeric_limits<T>::max())
5392 : {
5393 : if constexpr (COMPUTE_OTHER_STATS)
5394 : {
5395 : // Optimization when there is no nodata and we know we have already
5396 : // reached the min and max
5397 208 : for (int iY = 0; iY < nYCheck; iY++)
5398 : {
5399 : int iX;
5400 1002 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5401 : {
5402 800 : const GPtrDiff_t iOffset =
5403 800 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5404 800 : const GUIntBig nValue = pData[iOffset];
5405 800 : const GUIntBig nValue2 = pData[iOffset + 1];
5406 800 : const GUIntBig nValue3 = pData[iOffset + 2];
5407 800 : const GUIntBig nValue4 = pData[iOffset + 3];
5408 800 : nSum += nValue;
5409 800 : nSumSquare += nValue * nValue;
5410 800 : nSum += nValue2;
5411 800 : nSumSquare += nValue2 * nValue2;
5412 800 : nSum += nValue3;
5413 800 : nSumSquare += nValue3 * nValue3;
5414 800 : nSum += nValue4;
5415 800 : nSumSquare += nValue4 * nValue4;
5416 : }
5417 207 : for (; iX < nXCheck; ++iX)
5418 : {
5419 5 : const GPtrDiff_t iOffset =
5420 5 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5421 5 : const GUIntBig nValue = pData[iOffset];
5422 5 : nSum += nValue;
5423 5 : nSumSquare += nValue * nValue;
5424 : }
5425 : }
5426 6 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5427 6 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5428 : }
5429 : }
5430 : else
5431 : {
5432 3430 : for (int iY = 0; iY < nYCheck; iY++)
5433 : {
5434 : int iX;
5435 643294 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5436 : {
5437 639961 : const GPtrDiff_t iOffset =
5438 639961 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5439 639961 : const GUInt32 nValue = pData[iOffset];
5440 639961 : const GUInt32 nValue2 = pData[iOffset + 1];
5441 639961 : if (nValue < nValue2)
5442 : {
5443 2320 : if (nValue < nMin)
5444 48 : nMin = nValue;
5445 2320 : if (nValue2 > nMax)
5446 116 : nMax = nValue2;
5447 : }
5448 : else
5449 : {
5450 637641 : if (nValue2 < nMin)
5451 65 : nMin = nValue2;
5452 637641 : if (nValue > nMax)
5453 214 : nMax = nValue;
5454 : }
5455 : if constexpr (COMPUTE_OTHER_STATS)
5456 : {
5457 632911 : nSum += nValue;
5458 632911 : nSumSquare +=
5459 632911 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5460 632911 : nValue;
5461 632911 : nSum += nValue2;
5462 632911 : nSumSquare +=
5463 632911 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5464 632911 : nValue2;
5465 : }
5466 : }
5467 3333 : if (iX < nXCheck)
5468 : {
5469 17 : const GPtrDiff_t iOffset =
5470 17 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5471 17 : const GUInt32 nValue = pData[iOffset];
5472 17 : if (nValue < nMin)
5473 12 : nMin = nValue;
5474 17 : if (nValue > nMax)
5475 13 : nMax = nValue;
5476 : if (COMPUTE_OTHER_STATS)
5477 : {
5478 9 : nSum += nValue;
5479 9 : nSumSquare +=
5480 9 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5481 9 : nValue;
5482 : }
5483 : }
5484 : }
5485 : if constexpr (COMPUTE_OTHER_STATS)
5486 : {
5487 44 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5488 44 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5489 : }
5490 : }
5491 206 : }
5492 : };
5493 :
5494 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5495 : // using 64bit accumulators in internal loops. This also slightly helps in
5496 : // 64bit mode.
5497 : template <bool COMPUTE_OTHER_STATS>
5498 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5499 : {
5500 13497 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5501 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5502 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5503 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5504 : {
5505 13497 : int nOuterLoops = nXCheck / 65536;
5506 13497 : if (nXCheck % 65536)
5507 13497 : nOuterLoops++;
5508 :
5509 13497 : if (bHasNoData)
5510 : {
5511 : // General case
5512 23475 : for (int iY = 0; iY < nYCheck; iY++)
5513 : {
5514 12901 : int iX = 0;
5515 25802 : for (int k = 0; k < nOuterLoops; k++)
5516 : {
5517 12901 : int iMax = iX + 65536;
5518 12901 : if (iMax > nXCheck)
5519 12901 : iMax = nXCheck;
5520 12901 : GUInt32 nSum32bit = 0;
5521 12901 : GUInt32 nSumSquare32bit = 0;
5522 12901 : GUInt32 nValidCount32bit = 0;
5523 12901 : GUInt32 nSampleCount32bit = 0;
5524 20707168 : for (; iX < iMax; iX++)
5525 : {
5526 20694316 : const GPtrDiff_t iOffset =
5527 20694316 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5528 20694316 : const GUInt32 nValue = pData[iOffset];
5529 :
5530 20694316 : nSampleCount32bit++;
5531 20694316 : if (nValue == nNoDataValue)
5532 20353458 : continue;
5533 340803 : if (nValue < nMin)
5534 357 : nMin = nValue;
5535 340803 : if (nValue > nMax)
5536 813 : nMax = nValue;
5537 : if constexpr (COMPUTE_OTHER_STATS)
5538 : {
5539 17058 : nValidCount32bit++;
5540 17058 : nSum32bit += nValue;
5541 17058 : nSumSquare32bit += nValue * nValue;
5542 : }
5543 : }
5544 : if constexpr (COMPUTE_OTHER_STATS)
5545 : {
5546 652 : nSampleCount += nSampleCount32bit;
5547 652 : nValidCount += nValidCount32bit;
5548 652 : nSum += nSum32bit;
5549 652 : nSumSquare += nSumSquare32bit;
5550 : }
5551 : }
5552 : }
5553 : }
5554 2923 : else if (nMin == 0 && nMax == 255)
5555 : {
5556 : if constexpr (COMPUTE_OTHER_STATS)
5557 : {
5558 : // Optimization when there is no nodata and we know we have already
5559 : // reached the min and max
5560 2644 : for (int iY = 0; iY < nYCheck; iY++)
5561 : {
5562 2617 : int iX = 0;
5563 5234 : for (int k = 0; k < nOuterLoops; k++)
5564 : {
5565 2617 : int iMax = iX + 65536;
5566 2617 : if (iMax > nXCheck)
5567 2617 : iMax = nXCheck;
5568 2617 : GUInt32 nSum32bit = 0;
5569 2617 : GUInt32 nSumSquare32bit = 0;
5570 176297 : for (; iX + 3 < iMax; iX += 4)
5571 : {
5572 173680 : const GPtrDiff_t iOffset =
5573 173680 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5574 173680 : const GUInt32 nValue = pData[iOffset];
5575 173680 : const GUInt32 nValue2 = pData[iOffset + 1];
5576 173680 : const GUInt32 nValue3 = pData[iOffset + 2];
5577 173680 : const GUInt32 nValue4 = pData[iOffset + 3];
5578 173680 : nSum32bit += nValue;
5579 173680 : nSumSquare32bit += nValue * nValue;
5580 173680 : nSum32bit += nValue2;
5581 173680 : nSumSquare32bit += nValue2 * nValue2;
5582 173680 : nSum32bit += nValue3;
5583 173680 : nSumSquare32bit += nValue3 * nValue3;
5584 173680 : nSum32bit += nValue4;
5585 173680 : nSumSquare32bit += nValue4 * nValue4;
5586 : }
5587 2617 : nSum += nSum32bit;
5588 2617 : nSumSquare += nSumSquare32bit;
5589 : }
5590 2620 : for (; iX < nXCheck; ++iX)
5591 : {
5592 3 : const GPtrDiff_t iOffset =
5593 3 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5594 3 : const GUIntBig nValue = pData[iOffset];
5595 3 : nSum += nValue;
5596 3 : nSumSquare += nValue * nValue;
5597 : }
5598 : }
5599 27 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5600 27 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5601 27 : }
5602 : }
5603 : else
5604 : {
5605 7451 : for (int iY = 0; iY < nYCheck; iY++)
5606 : {
5607 4555 : int iX = 0;
5608 9110 : for (int k = 0; k < nOuterLoops; k++)
5609 : {
5610 4555 : int iMax = iX + 65536;
5611 4555 : if (iMax > nXCheck)
5612 4555 : iMax = nXCheck;
5613 4555 : GUInt32 nSum32bit = 0;
5614 4555 : GUInt32 nSumSquare32bit = 0;
5615 159064 : for (; iX + 1 < iMax; iX += 2)
5616 : {
5617 154509 : const GPtrDiff_t iOffset =
5618 154509 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5619 154509 : const GUInt32 nValue = pData[iOffset];
5620 154509 : const GUInt32 nValue2 = pData[iOffset + 1];
5621 154509 : if (nValue < nValue2)
5622 : {
5623 8047 : if (nValue < nMin)
5624 230 : nMin = nValue;
5625 8047 : if (nValue2 > nMax)
5626 219 : nMax = nValue2;
5627 : }
5628 : else
5629 : {
5630 146462 : if (nValue2 < nMin)
5631 274 : nMin = nValue2;
5632 146462 : if (nValue > nMax)
5633 775 : nMax = nValue;
5634 : }
5635 : if constexpr (COMPUTE_OTHER_STATS)
5636 : {
5637 132489 : nSum32bit += nValue;
5638 132489 : nSumSquare32bit += nValue * nValue;
5639 132489 : nSum32bit += nValue2;
5640 132489 : nSumSquare32bit += nValue2 * nValue2;
5641 : }
5642 : }
5643 : if constexpr (COMPUTE_OTHER_STATS)
5644 : {
5645 1609 : nSum += nSum32bit;
5646 1609 : nSumSquare += nSumSquare32bit;
5647 : }
5648 : }
5649 4555 : if (iX < nXCheck)
5650 : {
5651 1400 : const GPtrDiff_t iOffset =
5652 1400 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5653 1400 : const GUInt32 nValue = pData[iOffset];
5654 1400 : if (nValue < nMin)
5655 50 : nMin = nValue;
5656 1400 : if (nValue > nMax)
5657 62 : nMax = nValue;
5658 : if constexpr (COMPUTE_OTHER_STATS)
5659 : {
5660 312 : nSum += nValue;
5661 312 : nSumSquare +=
5662 312 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5663 312 : nValue;
5664 : }
5665 : }
5666 : }
5667 : if constexpr (COMPUTE_OTHER_STATS)
5668 : {
5669 908 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5670 908 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5671 : }
5672 : }
5673 13497 : }
5674 : };
5675 :
5676 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5677 : {
5678 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5679 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5680 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5681 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5682 : {
5683 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5684 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5685 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5686 : }
5687 : };
5688 :
5689 : #if (defined(__x86_64__) || defined(_M_X64)) && \
5690 : (defined(__GNUC__) || defined(_MSC_VER))
5691 :
5692 : #include "gdal_avx2_emulation.hpp"
5693 :
5694 : #define ZERO256 GDALmm256_setzero_si256()
5695 :
5696 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5697 : static void
5698 20930 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5699 : // assumed to be aligned on 256 bits
5700 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5701 : GUIntBig &nSum, GUIntBig &nSumSquare,
5702 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5703 : {
5704 : // 32-byte alignment may not be enforced by linker, so do it at hand
5705 : GByte
5706 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5707 20930 : GByte *paby32ByteAligned =
5708 : aby32ByteUnaligned +
5709 20930 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5710 20930 : GByte *pabyMin = paby32ByteAligned;
5711 20930 : GByte *pabyMax = paby32ByteAligned + 32;
5712 20930 : GUInt32 *panSum =
5713 : COMPUTE_OTHER_STATS
5714 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5715 : : nullptr;
5716 20930 : GUInt32 *panSumSquare =
5717 : COMPUTE_OTHER_STATS
5718 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5719 : : nullptr;
5720 :
5721 20930 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5722 :
5723 20930 : GPtrDiff_t i = 0;
5724 : // Make sure that sumSquare can fit on uint32
5725 : // * 8 since we can hold 8 sums per vector register
5726 20930 : const int nMaxIterationsPerInnerLoop =
5727 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5728 20930 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5729 20930 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5730 20930 : nOuterLoops++;
5731 :
5732 : GDALm256i ymm_min =
5733 20930 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5734 20930 : GDALm256i ymm_max = ymm_min;
5735 20930 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5736 :
5737 41860 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5738 : {
5739 20930 : const auto iMax =
5740 20930 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5741 :
5742 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5743 20930 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5744 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5745 20930 : ZERO256; // holds 8 uint32 sums
5746 705499 : for (; i + 31 < iMax; i += 32)
5747 : {
5748 684569 : const GDALm256i ymm = GDALmm256_load_si256(
5749 684569 : reinterpret_cast<const GDALm256i *>(pData + i));
5750 : if (COMPUTE_MIN)
5751 : {
5752 226732 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5753 : }
5754 : if (COMPUTE_MAX)
5755 : {
5756 593628 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5757 : }
5758 :
5759 : if constexpr (COMPUTE_OTHER_STATS)
5760 : {
5761 : // Extract even-8bit values
5762 : const GDALm256i ymm_even =
5763 493495 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5764 : // Compute square of those 16 values as 32 bit result
5765 : // and add adjacent pairs
5766 : const GDALm256i ymm_even_square =
5767 493495 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5768 : // Add to the sumsquare accumulator
5769 : ymm_sumsquare =
5770 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5771 :
5772 : // Extract odd-8bit values
5773 493495 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5774 : const GDALm256i ymm_odd_square =
5775 493495 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5776 : ymm_sumsquare =
5777 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5778 :
5779 : // Now compute the sums
5780 493495 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5781 : GDALmm256_sad_epu8(ymm, ZERO256));
5782 : }
5783 : }
5784 :
5785 : if constexpr (COMPUTE_OTHER_STATS)
5786 : {
5787 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5788 : ymm_sum);
5789 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5790 : ymm_sumsquare);
5791 :
5792 10649 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5793 10649 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5794 10649 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5795 10649 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5796 : panSumSquare[7];
5797 : }
5798 : }
5799 :
5800 : if constexpr (COMPUTE_MIN)
5801 : {
5802 8056 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5803 : }
5804 : if constexpr (COMPUTE_MAX)
5805 : {
5806 16933 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5807 : }
5808 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5809 : {
5810 576279 : for (int j = 0; j < 32; j++)
5811 : {
5812 : if constexpr (COMPUTE_MIN)
5813 : {
5814 257792 : if (pabyMin[j] < nMin)
5815 1245 : nMin = pabyMin[j];
5816 : }
5817 : if constexpr (COMPUTE_MAX)
5818 : {
5819 541856 : if (pabyMax[j] > nMax)
5820 1793 : nMax = pabyMax[j];
5821 : }
5822 : }
5823 : }
5824 :
5825 227580 : for (; i < nBlockPixels; i++)
5826 : {
5827 206650 : const GUInt32 nValue = pData[i];
5828 : if constexpr (COMPUTE_MIN)
5829 : {
5830 81974 : if (nValue < nMin)
5831 1 : nMin = nValue;
5832 : }
5833 : if constexpr (COMPUTE_MAX)
5834 : {
5835 203875 : if (nValue > nMax)
5836 1149 : nMax = nValue;
5837 : }
5838 : if constexpr (COMPUTE_OTHER_STATS)
5839 : {
5840 77195 : nSum += nValue;
5841 77195 : nSumSquare +=
5842 77195 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5843 : }
5844 : }
5845 :
5846 : if constexpr (COMPUTE_OTHER_STATS)
5847 : {
5848 10649 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5849 10649 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5850 : }
5851 20930 : }
5852 :
5853 : // SSE2/AVX2 optimization for GByte case
5854 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5855 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5856 : // there are strictly equivalent to 2 parallel SSE2 streams.
5857 : template <bool COMPUTE_OTHER_STATS>
5858 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5859 : {
5860 29961 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5861 : // assumed to be aligned on 256 bits
5862 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5863 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5864 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5865 : GUIntBig &nValidCount)
5866 : {
5867 29961 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5868 29961 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5869 11574 : nMin <= nMax)
5870 : {
5871 : // 32-byte alignment may not be enforced by linker, so do it at hand
5872 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5873 1459 : GByte *paby32ByteAligned =
5874 : aby32ByteUnaligned +
5875 1459 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5876 1459 : GByte *pabyMin = paby32ByteAligned;
5877 1459 : GByte *pabyMax = paby32ByteAligned + 32;
5878 1459 : GUInt32 *panSum =
5879 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5880 1459 : GUInt32 *panSumSquare =
5881 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5882 :
5883 1459 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5884 :
5885 1459 : GPtrDiff_t i = 0;
5886 : // Make sure that sumSquare can fit on uint32
5887 : // * 8 since we can hold 8 sums per vector register
5888 1459 : const int nMaxIterationsPerInnerLoop =
5889 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5890 1459 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5891 1459 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5892 1459 : nOuterLoops++;
5893 :
5894 : const GDALm256i ymm_nodata =
5895 1459 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5896 : // any non noData value in [min,max] would do.
5897 : const GDALm256i ymm_neutral =
5898 1459 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5899 1459 : GDALm256i ymm_min = ymm_neutral;
5900 1459 : GDALm256i ymm_max = ymm_neutral;
5901 : [[maybe_unused]] const auto ymm_mask_8bits =
5902 1459 : GDALmm256_set1_epi16(0xFF);
5903 :
5904 1459 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5905 1459 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5906 1459 : const bool bComputeMinMax =
5907 1459 : nMin > nMinThreshold || nMax < nMaxThreshold;
5908 :
5909 2918 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5910 : {
5911 1459 : const auto iMax =
5912 1459 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5913 :
5914 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5915 1459 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5916 : // holds 8 uint32 sums
5917 1459 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5918 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5919 1459 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5920 1459 : const auto iInit = i;
5921 14435 : for (; i + 31 < iMax; i += 32)
5922 : {
5923 12976 : const GDALm256i ymm = GDALmm256_load_si256(
5924 12976 : reinterpret_cast<const GDALm256i *>(pData + i));
5925 :
5926 : // Check which values are nodata
5927 : const GDALm256i ymm_eq_nodata =
5928 12976 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5929 : if constexpr (COMPUTE_OTHER_STATS)
5930 : {
5931 : // Count how many values are nodata (due to cmpeq
5932 : // putting 255 when condition is met, this will actually
5933 : // be 255 times the number of nodata value, spread in 4
5934 : // 64 bits words). We can use add_epi32 as the counter
5935 : // will not overflow uint32
5936 4634 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5937 : ymm_count_nodata_mul_255,
5938 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5939 : }
5940 : // Replace all nodata values by zero for the purpose of sum
5941 : // and sumquare.
5942 : const GDALm256i ymm_nodata_by_zero =
5943 12976 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5944 12976 : if (bComputeMinMax)
5945 : {
5946 : // Replace all nodata values by a neutral value for the
5947 : // purpose of min and max.
5948 : const GDALm256i ymm_nodata_by_neutral =
5949 8591 : GDALmm256_or_si256(
5950 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5951 : ymm_nodata_by_zero);
5952 :
5953 : ymm_min =
5954 8591 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5955 : ymm_max =
5956 8591 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
5957 : }
5958 :
5959 : if constexpr (COMPUTE_OTHER_STATS)
5960 : {
5961 : // Extract even-8bit values
5962 4634 : const GDALm256i ymm_even = GDALmm256_and_si256(
5963 : ymm_nodata_by_zero, ymm_mask_8bits);
5964 : // Compute square of those 16 values as 32 bit result
5965 : // and add adjacent pairs
5966 : const GDALm256i ymm_even_square =
5967 4634 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5968 : // Add to the sumsquare accumulator
5969 : ymm_sumsquare =
5970 4634 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5971 :
5972 : // Extract odd-8bit values
5973 : const GDALm256i ymm_odd =
5974 4634 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
5975 : const GDALm256i ymm_odd_square =
5976 4634 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5977 : ymm_sumsquare =
5978 4634 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5979 :
5980 : // Now compute the sums
5981 4634 : ymm_sum = GDALmm256_add_epi32(
5982 : ymm_sum,
5983 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
5984 : }
5985 : }
5986 :
5987 : if constexpr (COMPUTE_OTHER_STATS)
5988 : {
5989 153 : GUInt32 *panCoutNoDataMul255 = panSum;
5990 153 : GDALmm256_store_si256(
5991 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
5992 : ymm_count_nodata_mul_255);
5993 :
5994 153 : nSampleCount += (i - iInit);
5995 :
5996 153 : nValidCount +=
5997 153 : (i - iInit) -
5998 153 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
5999 153 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6000 : 255;
6001 :
6002 153 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6003 : ymm_sum);
6004 153 : GDALmm256_store_si256(
6005 : reinterpret_cast<GDALm256i *>(panSumSquare),
6006 : ymm_sumsquare);
6007 153 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6008 153 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6009 153 : panSumSquare[1] + panSumSquare[2] +
6010 153 : panSumSquare[3] + panSumSquare[4] +
6011 153 : panSumSquare[5] + panSumSquare[6] +
6012 : panSumSquare[7];
6013 : }
6014 : }
6015 :
6016 1459 : if (bComputeMinMax)
6017 : {
6018 1428 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6019 : ymm_min);
6020 1428 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6021 : ymm_max);
6022 47124 : for (int j = 0; j < 32; j++)
6023 : {
6024 45696 : if (pabyMin[j] < nMin)
6025 40 : nMin = pabyMin[j];
6026 45696 : if (pabyMax[j] > nMax)
6027 159 : nMax = pabyMax[j];
6028 : }
6029 : }
6030 :
6031 : if constexpr (COMPUTE_OTHER_STATS)
6032 : {
6033 153 : nSampleCount += nBlockPixels - i;
6034 : }
6035 33905 : for (; i < nBlockPixels; i++)
6036 : {
6037 32446 : const GUInt32 nValue = pData[i];
6038 32446 : if (nValue == nNoDataValue)
6039 24923 : continue;
6040 7523 : if (nValue < nMin)
6041 1 : nMin = nValue;
6042 7523 : if (nValue > nMax)
6043 13 : nMax = nValue;
6044 : if constexpr (COMPUTE_OTHER_STATS)
6045 : {
6046 3590 : nValidCount++;
6047 3590 : nSum += nValue;
6048 3590 : nSumSquare +=
6049 3590 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6050 3590 : nValue;
6051 : }
6052 1459 : }
6053 : }
6054 28502 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6055 : {
6056 14974 : if (nMin > 0)
6057 : {
6058 2100 : if (nMax < 255)
6059 : {
6060 : ComputeStatisticsByteNoNodata<true, true,
6061 1570 : COMPUTE_OTHER_STATS>(
6062 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6063 : nSampleCount, nValidCount);
6064 : }
6065 : else
6066 : {
6067 : ComputeStatisticsByteNoNodata<true, false,
6068 530 : COMPUTE_OTHER_STATS>(
6069 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6070 : nSampleCount, nValidCount);
6071 : }
6072 : }
6073 : else
6074 : {
6075 12874 : if (nMax < 255)
6076 : {
6077 : ComputeStatisticsByteNoNodata<false, true,
6078 9407 : COMPUTE_OTHER_STATS>(
6079 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6080 : nSampleCount, nValidCount);
6081 : }
6082 : else
6083 : {
6084 : ComputeStatisticsByteNoNodata<false, false,
6085 3467 : COMPUTE_OTHER_STATS>(
6086 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6087 : nSampleCount, nValidCount);
6088 : }
6089 : }
6090 : }
6091 12274 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6092 31 : (nBlockXSize % 32) == 0)
6093 : {
6094 5987 : for (int iY = 0; iY < nYCheck; iY++)
6095 : {
6096 5956 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6097 5956 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6098 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6099 31 : }
6100 : }
6101 : else
6102 : {
6103 13497 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6104 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6105 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6106 : }
6107 29959 : }
6108 : };
6109 :
6110 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6111 400 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6112 : GUIntBig i)
6113 : {
6114 400 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6115 400 : }
6116 :
6117 : // AVX2/SSE2 optimization for GUInt16 case
6118 : template <bool COMPUTE_OTHER_STATS>
6119 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6120 : {
6121 1624 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
6122 : // assumed to be aligned on 128 bits
6123 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6124 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6125 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6126 : GUIntBig &nValidCount)
6127 : {
6128 1624 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6129 1624 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6130 : {
6131 1418 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6132 :
6133 1418 : GPtrDiff_t i = 0;
6134 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6135 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6136 : // Furthermore the shift is also needed to use madd_epi16
6137 1418 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6138 1418 : GDALm256i ymm_min = GDALmm256_load_si256(
6139 1418 : reinterpret_cast<const GDALm256i *>(pData + i));
6140 1418 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6141 1418 : GDALm256i ymm_max = ymm_min;
6142 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6143 1418 : ZERO256; // holds 4 uint64 sums
6144 :
6145 : // Make sure that sum can fit on uint32
6146 : // * 8 since we can hold 8 sums per vector register
6147 1418 : const int nMaxIterationsPerInnerLoop =
6148 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6149 1418 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6150 1418 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6151 1418 : nOuterLoops++;
6152 :
6153 1418 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6154 : [[maybe_unused]] const auto ymm_mask_16bits =
6155 1418 : GDALmm256_set1_epi32(0xFFFF);
6156 : [[maybe_unused]] const auto ymm_mask_32bits =
6157 1418 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6158 :
6159 1418 : GUIntBig nSumThis = 0;
6160 2860 : for (int k = 0; k < nOuterLoops; k++)
6161 : {
6162 1442 : const auto iMax =
6163 1442 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6164 :
6165 : [[maybe_unused]] GDALm256i ymm_sum =
6166 1442 : ZERO256; // holds 8 uint32 sums
6167 959774 : for (; i + 15 < iMax; i += 16)
6168 : {
6169 958332 : const GDALm256i ymm = GDALmm256_load_si256(
6170 958332 : reinterpret_cast<const GDALm256i *>(pData + i));
6171 : const GDALm256i ymm_shifted =
6172 958332 : GDALmm256_add_epi16(ymm, ymm_m32768);
6173 958332 : if (bComputeMinMax)
6174 : {
6175 949313 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6176 949313 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6177 : }
6178 :
6179 : if constexpr (COMPUTE_OTHER_STATS)
6180 : {
6181 : // Note: the int32 range can overflow for (0-32768)^2 +
6182 : // (0-32768)^2 = 0x80000000, but as we know the result
6183 : // is positive, this is OK as we interpret is a uint32.
6184 : const GDALm256i ymm_square =
6185 95410 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6186 95410 : ymm_sumsquare = GDALmm256_add_epi64(
6187 : ymm_sumsquare,
6188 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6189 95410 : ymm_sumsquare = GDALmm256_add_epi64(
6190 : ymm_sumsquare,
6191 : GDALmm256_srli_epi64(ymm_square, 32));
6192 :
6193 : // Now compute the sums
6194 95410 : ymm_sum = GDALmm256_add_epi32(
6195 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6196 95410 : ymm_sum = GDALmm256_add_epi32(
6197 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6198 : }
6199 : }
6200 :
6201 : if constexpr (COMPUTE_OTHER_STATS)
6202 : {
6203 : GUInt32 anSum[8];
6204 400 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6205 : ymm_sum);
6206 400 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6207 400 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6208 400 : anSum[6] + anSum[7];
6209 : }
6210 : }
6211 :
6212 1418 : if (bComputeMinMax)
6213 : {
6214 : GUInt16 anMin[16];
6215 : GUInt16 anMax[16];
6216 :
6217 : // Unshift the result
6218 1377 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6219 1377 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6220 1377 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6221 : ymm_min);
6222 1377 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6223 : ymm_max);
6224 23409 : for (int j = 0; j < 16; j++)
6225 : {
6226 22032 : if (anMin[j] < nMin)
6227 342 : nMin = anMin[j];
6228 22032 : if (anMax[j] > nMax)
6229 481 : nMax = anMax[j];
6230 : }
6231 : }
6232 :
6233 : if constexpr (COMPUTE_OTHER_STATS)
6234 : {
6235 : GUIntBig anSumSquare[4];
6236 400 : GDALmm256_storeu_si256(
6237 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6238 400 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6239 : anSumSquare[3];
6240 :
6241 : // Unshift the sum of squares
6242 400 : UnshiftSumSquare(nSumSquare, nSumThis,
6243 : static_cast<GUIntBig>(i));
6244 :
6245 400 : nSum += nSumThis;
6246 :
6247 722 : for (; i < nBlockPixels; i++)
6248 : {
6249 322 : const GUInt32 nValue = pData[i];
6250 322 : if (nValue < nMin)
6251 1 : nMin = nValue;
6252 322 : if (nValue > nMax)
6253 1 : nMax = nValue;
6254 322 : nSum += nValue;
6255 322 : nSumSquare +=
6256 322 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6257 322 : nValue;
6258 : }
6259 :
6260 400 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6261 400 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6262 1418 : }
6263 : }
6264 : else
6265 : {
6266 206 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6267 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6268 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6269 : }
6270 1624 : }
6271 : };
6272 :
6273 : #endif
6274 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6275 : // defined(_MSC_VER))
6276 :
6277 : /************************************************************************/
6278 : /* GetPixelValue() */
6279 : /************************************************************************/
6280 :
6281 23187600 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6282 : const void *pData, GPtrDiff_t iOffset,
6283 : const GDALNoDataValues &sNoDataValues,
6284 : bool &bValid)
6285 : {
6286 23187600 : bValid = true;
6287 23187600 : double dfValue = 0;
6288 23187600 : switch (eDataType)
6289 : {
6290 1413680 : case GDT_Byte:
6291 : {
6292 1413680 : if (bSignedByte)
6293 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6294 : else
6295 1413490 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6296 1413680 : break;
6297 : }
6298 10409 : case GDT_Int8:
6299 10409 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6300 10409 : break;
6301 4000 : case GDT_UInt16:
6302 4000 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6303 4000 : break;
6304 60192 : case GDT_Int16:
6305 60192 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6306 60192 : break;
6307 27600 : case GDT_UInt32:
6308 27600 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6309 27600 : break;
6310 455610 : case GDT_Int32:
6311 455610 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6312 455610 : break;
6313 2602 : case GDT_UInt64:
6314 2602 : dfValue = static_cast<double>(
6315 2602 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6316 2602 : break;
6317 7402 : case GDT_Int64:
6318 7402 : dfValue = static_cast<double>(
6319 7402 : static_cast<const std::int64_t *>(pData)[iOffset]);
6320 7402 : break;
6321 0 : case GDT_Float16:
6322 : {
6323 : using namespace std;
6324 0 : const GFloat16 hfValue =
6325 0 : static_cast<const GFloat16 *>(pData)[iOffset];
6326 0 : if (isnan(hfValue) ||
6327 0 : (sNoDataValues.bGotFloat16NoDataValue &&
6328 0 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6329 : {
6330 0 : bValid = false;
6331 0 : return 0.0;
6332 : }
6333 0 : dfValue = hfValue;
6334 0 : return dfValue;
6335 : }
6336 17502100 : case GDT_Float32:
6337 : {
6338 17502100 : const float fValue = static_cast<const float *>(pData)[iOffset];
6339 34977300 : if (std::isnan(fValue) ||
6340 30705200 : (sNoDataValues.bGotFloatNoDataValue &&
6341 13230000 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6342 : {
6343 121752 : bValid = false;
6344 121752 : return 0.0;
6345 : }
6346 17380400 : dfValue = fValue;
6347 17380400 : return dfValue;
6348 : }
6349 3686870 : case GDT_Float64:
6350 3686870 : dfValue = static_cast<const double *>(pData)[iOffset];
6351 3686870 : if (std::isnan(dfValue))
6352 : {
6353 52 : bValid = false;
6354 52 : return 0.0;
6355 : }
6356 3686820 : break;
6357 2692 : case GDT_CInt16:
6358 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6359 2692 : break;
6360 2692 : case GDT_CInt32:
6361 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6362 2692 : break;
6363 0 : case GDT_CFloat16:
6364 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6365 0 : if (std::isnan(dfValue))
6366 : {
6367 0 : bValid = false;
6368 0 : return 0.0;
6369 : }
6370 0 : break;
6371 5812 : case GDT_CFloat32:
6372 5812 : dfValue = static_cast<const float *>(pData)[iOffset * 2];
6373 5812 : if (std::isnan(dfValue))
6374 : {
6375 0 : bValid = false;
6376 0 : return 0.0;
6377 : }
6378 5812 : break;
6379 5892 : case GDT_CFloat64:
6380 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6381 5892 : if (std::isnan(dfValue))
6382 : {
6383 0 : bValid = false;
6384 0 : return 0.0;
6385 : }
6386 5892 : break;
6387 0 : case GDT_Unknown:
6388 : case GDT_TypeCount:
6389 0 : CPLAssert(false);
6390 : break;
6391 : }
6392 :
6393 9424400 : if (sNoDataValues.bGotNoDataValue &&
6394 3738990 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6395 : {
6396 3346220 : bValid = false;
6397 3346220 : return 0.0;
6398 : }
6399 2339180 : return dfValue;
6400 : }
6401 :
6402 : /************************************************************************/
6403 : /* SetValidPercent() */
6404 : /************************************************************************/
6405 :
6406 : //! @cond Doxygen_Suppress
6407 : /**
6408 : * \brief Set percentage of valid (not nodata) pixels.
6409 : *
6410 : * Stores the percentage of valid pixels in the metadata item
6411 : * STATISTICS_VALID_PERCENT
6412 : *
6413 : * @param nSampleCount Number of sampled pixels.
6414 : *
6415 : * @param nValidCount Number of valid pixels.
6416 : */
6417 :
6418 481 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6419 : GUIntBig nValidCount)
6420 : {
6421 481 : if (nValidCount == 0)
6422 : {
6423 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6424 : }
6425 469 : else if (nValidCount == nSampleCount)
6426 : {
6427 424 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6428 : }
6429 : else /* nValidCount < nSampleCount */
6430 : {
6431 45 : char szValue[128] = {0};
6432 :
6433 : /* percentage is only an indicator: limit precision */
6434 45 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6435 45 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6436 :
6437 45 : if (EQUAL(szValue, "100"))
6438 : {
6439 : /* don't set 100 percent valid
6440 : * because some of the sampled pixels were nodata */
6441 0 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6442 : }
6443 : else
6444 : {
6445 45 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6446 : }
6447 : }
6448 481 : }
6449 :
6450 : //! @endcond
6451 :
6452 : /************************************************************************/
6453 : /* ComputeStatistics() */
6454 : /************************************************************************/
6455 :
6456 : /**
6457 : * \brief Compute image statistics.
6458 : *
6459 : * Returns the minimum, maximum, mean and standard deviation of all
6460 : * pixel values in this band. If approximate statistics are sufficient,
6461 : * the bApproxOK flag can be set to true in which case overviews, or a
6462 : * subset of image tiles may be used in computing the statistics.
6463 : *
6464 : * Once computed, the statistics will generally be "set" back on the
6465 : * raster band using SetStatistics().
6466 : *
6467 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6468 : *
6469 : * This method is the same as the C function GDALComputeRasterStatistics().
6470 : *
6471 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6472 : * or a subset of all tiles.
6473 : *
6474 : * @param pdfMin Location into which to load image minimum (may be NULL).
6475 : *
6476 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6477 : *
6478 : * @param pdfMean Location into which to load image mean (may be NULL).
6479 : *
6480 : * @param pdfStdDev Location into which to load image standard deviation
6481 : * (may be NULL).
6482 : *
6483 : * @param pfnProgress a function to call to report progress, or NULL.
6484 : *
6485 : * @param pProgressData application data to pass to the progress function.
6486 : *
6487 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6488 : * is terminated by the user.
6489 : */
6490 :
6491 464 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6492 : double *pdfMax, double *pdfMean,
6493 : double *pdfStdDev,
6494 : GDALProgressFunc pfnProgress,
6495 : void *pProgressData)
6496 :
6497 : {
6498 464 : if (pfnProgress == nullptr)
6499 169 : pfnProgress = GDALDummyProgress;
6500 :
6501 : /* -------------------------------------------------------------------- */
6502 : /* If we have overview bands, use them for statistics. */
6503 : /* -------------------------------------------------------------------- */
6504 464 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6505 : {
6506 : GDALRasterBand *poBand =
6507 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6508 :
6509 3 : if (poBand != this)
6510 : {
6511 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6512 : pdfMean, pdfStdDev,
6513 3 : pfnProgress, pProgressData);
6514 3 : if (eErr == CE_None)
6515 : {
6516 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6517 : {
6518 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6519 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6520 : }
6521 :
6522 : /* transfer metadata from overview band to this */
6523 : const char *pszPercentValid =
6524 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6525 :
6526 3 : if (pszPercentValid != nullptr)
6527 : {
6528 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6529 3 : pszPercentValid);
6530 : }
6531 : }
6532 3 : return eErr;
6533 : }
6534 : }
6535 :
6536 461 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6537 : {
6538 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6539 0 : return CE_Failure;
6540 : }
6541 :
6542 : /* -------------------------------------------------------------------- */
6543 : /* Read actual data and compute statistics. */
6544 : /* -------------------------------------------------------------------- */
6545 : // Using Welford algorithm:
6546 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6547 : // to compute standard deviation in a more numerically robust way than
6548 : // the difference of the sum of square values with the square of the sum.
6549 : // dfMean and dfM2 are updated at each sample.
6550 : // dfM2 is the sum of square of differences to the current mean.
6551 461 : double dfMin = std::numeric_limits<double>::infinity();
6552 461 : double dfMax = -std::numeric_limits<double>::infinity();
6553 461 : double dfMean = 0.0;
6554 461 : double dfM2 = 0.0;
6555 :
6556 : GDALRasterIOExtraArg sExtraArg;
6557 461 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6558 :
6559 461 : GDALNoDataValues sNoDataValues(this, eDataType);
6560 461 : GDALRasterBand *poMaskBand = nullptr;
6561 461 : if (!sNoDataValues.bGotNoDataValue)
6562 : {
6563 434 : const int l_nMaskFlags = GetMaskFlags();
6564 450 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
6565 16 : GetColorInterpretation() != GCI_AlphaBand)
6566 : {
6567 16 : poMaskBand = GetMaskBand();
6568 : }
6569 : }
6570 :
6571 461 : bool bSignedByte = false;
6572 461 : if (eDataType == GDT_Byte)
6573 : {
6574 199 : EnablePixelTypeSignedByteWarning(false);
6575 : const char *pszPixelType =
6576 199 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6577 199 : EnablePixelTypeSignedByteWarning(true);
6578 199 : bSignedByte =
6579 199 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6580 : }
6581 :
6582 461 : GUIntBig nSampleCount = 0;
6583 461 : GUIntBig nValidCount = 0;
6584 :
6585 461 : if (bApproxOK && HasArbitraryOverviews())
6586 : {
6587 : /* --------------------------------------------------------------------
6588 : */
6589 : /* Figure out how much the image should be reduced to get an */
6590 : /* approximate value. */
6591 : /* --------------------------------------------------------------------
6592 : */
6593 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6594 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6595 :
6596 0 : int nXReduced = nRasterXSize;
6597 0 : int nYReduced = nRasterYSize;
6598 0 : if (dfReduction > 1.0)
6599 : {
6600 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6601 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6602 :
6603 : // Catch the case of huge resizing ratios here
6604 0 : if (nXReduced == 0)
6605 0 : nXReduced = 1;
6606 0 : if (nYReduced == 0)
6607 0 : nYReduced = 1;
6608 : }
6609 :
6610 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
6611 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6612 :
6613 : const CPLErr eErr =
6614 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6615 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6616 0 : if (eErr != CE_None)
6617 : {
6618 0 : CPLFree(pData);
6619 0 : return eErr;
6620 : }
6621 :
6622 0 : GByte *pabyMaskData = nullptr;
6623 0 : if (poMaskBand)
6624 : {
6625 : pabyMaskData =
6626 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6627 0 : if (!pabyMaskData)
6628 : {
6629 0 : CPLFree(pData);
6630 0 : return CE_Failure;
6631 : }
6632 :
6633 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6634 : pabyMaskData, nXReduced, nYReduced,
6635 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
6636 : {
6637 0 : CPLFree(pData);
6638 0 : CPLFree(pabyMaskData);
6639 0 : return CE_Failure;
6640 : }
6641 : }
6642 :
6643 : /* this isn't the fastest way to do this, but is easier for now */
6644 0 : for (int iY = 0; iY < nYReduced; iY++)
6645 : {
6646 0 : for (int iX = 0; iX < nXReduced; iX++)
6647 : {
6648 0 : const int iOffset = iX + iY * nXReduced;
6649 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6650 0 : continue;
6651 :
6652 0 : bool bValid = true;
6653 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
6654 0 : iOffset, sNoDataValues, bValid);
6655 0 : if (!bValid)
6656 0 : continue;
6657 :
6658 0 : dfMin = std::min(dfMin, dfValue);
6659 0 : dfMax = std::max(dfMax, dfValue);
6660 :
6661 0 : nValidCount++;
6662 0 : if (dfMin == dfMax)
6663 : {
6664 0 : if (nValidCount == 1)
6665 0 : dfMean = dfMin;
6666 : }
6667 : else
6668 : {
6669 0 : const double dfDelta = dfValue - dfMean;
6670 0 : dfMean += dfDelta / nValidCount;
6671 0 : dfM2 += dfDelta * (dfValue - dfMean);
6672 : }
6673 : }
6674 : }
6675 :
6676 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6677 :
6678 0 : CPLFree(pData);
6679 0 : CPLFree(pabyMaskData);
6680 : }
6681 :
6682 : else // No arbitrary overviews.
6683 : {
6684 461 : if (!InitBlockInfo())
6685 0 : return CE_Failure;
6686 :
6687 : /* --------------------------------------------------------------------
6688 : */
6689 : /* Figure out the ratio of blocks we will read to get an */
6690 : /* approximate value. */
6691 : /* --------------------------------------------------------------------
6692 : */
6693 461 : int nSampleRate = 1;
6694 461 : if (bApproxOK)
6695 : {
6696 42 : nSampleRate = static_cast<int>(std::max(
6697 84 : 1.0,
6698 42 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6699 : // We want to avoid probing only the first column of blocks for
6700 : // a square shaped raster, because it is not unlikely that it may
6701 : // be padding only (#6378)
6702 42 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6703 1 : nSampleRate += 1;
6704 : }
6705 461 : if (nSampleRate == 1)
6706 427 : bApproxOK = false;
6707 :
6708 : // Particular case for GDT_Byte that only use integral types for all
6709 : // intermediate computations. Only possible if the number of pixels
6710 : // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6711 : // can fit on a uint64. Should be 99.99999% of cases.
6712 : // For GUInt16, this limits to raster of 4 giga pixels
6713 461 : if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6714 184 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6715 184 : nSampleRate <
6716 184 : GUINTBIG_MAX / (255U * 255U) /
6717 184 : (static_cast<GUInt64>(nBlockXSize) *
6718 184 : static_cast<GUInt64>(nBlockYSize))) ||
6719 277 : (eDataType == GDT_UInt16 &&
6720 29 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6721 29 : nSampleRate <
6722 29 : GUINTBIG_MAX / (65535U * 65535U) /
6723 29 : (static_cast<GUInt64>(nBlockXSize) *
6724 29 : static_cast<GUInt64>(nBlockYSize))))
6725 : {
6726 213 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6727 213 : GUInt32 nMin = nMaxValueType;
6728 213 : GUInt32 nMax = 0;
6729 213 : GUIntBig nSum = 0;
6730 213 : GUIntBig nSumSquare = 0;
6731 : // If no valid nodata, map to invalid value (256 for Byte)
6732 213 : const GUInt32 nNoDataValue =
6733 236 : (sNoDataValues.bGotNoDataValue &&
6734 23 : sNoDataValues.dfNoDataValue >= 0 &&
6735 23 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
6736 23 : fabs(sNoDataValues.dfNoDataValue -
6737 23 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
6738 : 1e-10)) < 1e-10)
6739 236 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
6740 : : nMaxValueType + 1;
6741 :
6742 213 : for (GIntBig iSampleBlock = 0;
6743 12737 : iSampleBlock <
6744 12737 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6745 12524 : iSampleBlock += nSampleRate)
6746 : {
6747 12524 : const int iYBlock =
6748 12524 : static_cast<int>(iSampleBlock / nBlocksPerRow);
6749 12524 : const int iXBlock =
6750 12524 : static_cast<int>(iSampleBlock % nBlocksPerRow);
6751 :
6752 : GDALRasterBlock *const poBlock =
6753 12524 : GetLockedBlockRef(iXBlock, iYBlock);
6754 12526 : if (poBlock == nullptr)
6755 0 : return CE_Failure;
6756 :
6757 12526 : void *const pData = poBlock->GetDataRef();
6758 :
6759 12526 : int nXCheck = 0, nYCheck = 0;
6760 12526 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6761 :
6762 12525 : if (eDataType == GDT_Byte)
6763 : {
6764 : ComputeStatisticsInternal<
6765 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
6766 12055 : f(nXCheck, nBlockXSize, nYCheck,
6767 : static_cast<const GByte *>(pData),
6768 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6769 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6770 : }
6771 : else
6772 : {
6773 : ComputeStatisticsInternal<
6774 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6775 470 : f(nXCheck, nBlockXSize, nYCheck,
6776 : static_cast<const GUInt16 *>(pData),
6777 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6778 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6779 : }
6780 :
6781 12525 : poBlock->DropLock();
6782 :
6783 12525 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
6784 12526 : (static_cast<double>(nBlocksPerRow) *
6785 12526 : nBlocksPerColumn),
6786 : "Compute Statistics", pProgressData))
6787 : {
6788 1 : ReportError(CE_Failure, CPLE_UserInterrupt,
6789 : "User terminated");
6790 0 : return CE_Failure;
6791 : }
6792 : }
6793 :
6794 213 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6795 : {
6796 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6797 0 : return CE_Failure;
6798 : }
6799 :
6800 : /* --------------------------------------------------------------------
6801 : */
6802 : /* Save computed information. */
6803 : /* --------------------------------------------------------------------
6804 : */
6805 213 : if (nValidCount)
6806 204 : dfMean = static_cast<double>(nSum) / nValidCount;
6807 :
6808 : // To avoid potential precision issues when doing the difference,
6809 : // we need to do that computation on 128 bit rather than casting
6810 : // to double
6811 : const GDALUInt128 nTmpForStdDev(
6812 213 : GDALUInt128::Mul(nSumSquare, nValidCount) -
6813 426 : GDALUInt128::Mul(nSum, nSum));
6814 : const double dfStdDev =
6815 213 : nValidCount > 0
6816 213 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6817 213 : : 0.0;
6818 :
6819 213 : if (nValidCount > 0)
6820 : {
6821 204 : if (bApproxOK)
6822 : {
6823 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6824 : }
6825 180 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6826 : {
6827 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6828 : }
6829 204 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
6830 : }
6831 :
6832 213 : SetValidPercent(nSampleCount, nValidCount);
6833 :
6834 : /* --------------------------------------------------------------------
6835 : */
6836 : /* Record results. */
6837 : /* --------------------------------------------------------------------
6838 : */
6839 213 : if (pdfMin != nullptr)
6840 210 : *pdfMin = nValidCount ? nMin : 0;
6841 213 : if (pdfMax != nullptr)
6842 210 : *pdfMax = nValidCount ? nMax : 0;
6843 :
6844 213 : if (pdfMean != nullptr)
6845 206 : *pdfMean = dfMean;
6846 :
6847 213 : if (pdfStdDev != nullptr)
6848 206 : *pdfStdDev = dfStdDev;
6849 :
6850 213 : if (nValidCount > 0)
6851 204 : return CE_None;
6852 :
6853 9 : ReportError(CE_Failure, CPLE_AppDefined,
6854 : "Failed to compute statistics, no valid pixels found "
6855 : "in sampling.");
6856 9 : return CE_Failure;
6857 : }
6858 :
6859 248 : GByte *pabyMaskData = nullptr;
6860 248 : if (poMaskBand)
6861 : {
6862 : pabyMaskData = static_cast<GByte *>(
6863 16 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6864 16 : if (!pabyMaskData)
6865 : {
6866 0 : return CE_Failure;
6867 : }
6868 : }
6869 :
6870 248 : for (GIntBig iSampleBlock = 0;
6871 5869 : iSampleBlock <
6872 5869 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6873 5621 : iSampleBlock += nSampleRate)
6874 : {
6875 5621 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6876 5621 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6877 :
6878 : GDALRasterBlock *const poBlock =
6879 5621 : GetLockedBlockRef(iXBlock, iYBlock);
6880 5621 : if (poBlock == nullptr)
6881 : {
6882 0 : CPLFree(pabyMaskData);
6883 0 : return CE_Failure;
6884 : }
6885 :
6886 5621 : void *const pData = poBlock->GetDataRef();
6887 :
6888 5621 : int nXCheck = 0, nYCheck = 0;
6889 5621 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6890 :
6891 5722 : if (poMaskBand &&
6892 101 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6893 101 : iYBlock * nBlockYSize, nXCheck, nYCheck,
6894 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6895 101 : 0, nBlockXSize, nullptr) != CE_None)
6896 : {
6897 0 : CPLFree(pabyMaskData);
6898 0 : poBlock->DropLock();
6899 0 : return CE_Failure;
6900 : }
6901 :
6902 : // This isn't the fastest way to do this, but is easier for now.
6903 11426 : for (int iY = 0; iY < nYCheck; iY++)
6904 : {
6905 4364850 : for (int iX = 0; iX < nXCheck; iX++)
6906 : {
6907 4359040 : const GPtrDiff_t iOffset =
6908 4359040 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6909 4359040 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6910 111827 : continue;
6911 :
6912 4349170 : bool bValid = true;
6913 : double dfValue =
6914 4349170 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6915 4349170 : sNoDataValues, bValid);
6916 :
6917 4349170 : if (!bValid)
6918 101956 : continue;
6919 :
6920 4247220 : dfMin = std::min(dfMin, dfValue);
6921 4247220 : dfMax = std::max(dfMax, dfValue);
6922 :
6923 4247220 : nValidCount++;
6924 4247220 : if (dfMin == dfMax)
6925 : {
6926 2173320 : if (nValidCount == 1)
6927 247 : dfMean = dfMin;
6928 : }
6929 : else
6930 : {
6931 2073900 : const double dfDelta = dfValue - dfMean;
6932 2073900 : dfMean += dfDelta / nValidCount;
6933 2073900 : dfM2 += dfDelta * (dfValue - dfMean);
6934 : }
6935 : }
6936 : }
6937 :
6938 5621 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6939 :
6940 5621 : poBlock->DropLock();
6941 :
6942 5621 : if (!pfnProgress(
6943 5621 : static_cast<double>(iSampleBlock) /
6944 5621 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6945 : "Compute Statistics", pProgressData))
6946 : {
6947 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6948 0 : CPLFree(pabyMaskData);
6949 0 : return CE_Failure;
6950 : }
6951 : }
6952 :
6953 248 : CPLFree(pabyMaskData);
6954 : }
6955 :
6956 248 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6957 : {
6958 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6959 0 : return CE_Failure;
6960 : }
6961 :
6962 : /* -------------------------------------------------------------------- */
6963 : /* Save computed information. */
6964 : /* -------------------------------------------------------------------- */
6965 248 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
6966 :
6967 248 : if (nValidCount > 0)
6968 : {
6969 247 : if (bApproxOK)
6970 : {
6971 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6972 : }
6973 239 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6974 : {
6975 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6976 : }
6977 247 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6978 : }
6979 : else
6980 : {
6981 1 : dfMin = 0.0;
6982 1 : dfMax = 0.0;
6983 : }
6984 :
6985 248 : SetValidPercent(nSampleCount, nValidCount);
6986 :
6987 : /* -------------------------------------------------------------------- */
6988 : /* Record results. */
6989 : /* -------------------------------------------------------------------- */
6990 248 : if (pdfMin != nullptr)
6991 245 : *pdfMin = dfMin;
6992 248 : if (pdfMax != nullptr)
6993 245 : *pdfMax = dfMax;
6994 :
6995 248 : if (pdfMean != nullptr)
6996 243 : *pdfMean = dfMean;
6997 :
6998 248 : if (pdfStdDev != nullptr)
6999 243 : *pdfStdDev = dfStdDev;
7000 :
7001 248 : if (nValidCount > 0)
7002 247 : return CE_None;
7003 :
7004 1 : ReportError(
7005 : CE_Failure, CPLE_AppDefined,
7006 : "Failed to compute statistics, no valid pixels found in sampling.");
7007 1 : return CE_Failure;
7008 : }
7009 :
7010 : /************************************************************************/
7011 : /* GDALComputeRasterStatistics() */
7012 : /************************************************************************/
7013 :
7014 : /**
7015 : * \brief Compute image statistics.
7016 : *
7017 : * @see GDALRasterBand::ComputeStatistics()
7018 : */
7019 :
7020 154 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7021 : int bApproxOK, double *pdfMin,
7022 : double *pdfMax, double *pdfMean,
7023 : double *pdfStdDev,
7024 : GDALProgressFunc pfnProgress,
7025 : void *pProgressData)
7026 :
7027 : {
7028 154 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7029 :
7030 154 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7031 :
7032 154 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7033 154 : pdfStdDev, pfnProgress, pProgressData);
7034 : }
7035 :
7036 : /************************************************************************/
7037 : /* SetStatistics() */
7038 : /************************************************************************/
7039 :
7040 : /**
7041 : * \brief Set statistics on band.
7042 : *
7043 : * This method can be used to store min/max/mean/standard deviation
7044 : * statistics on a raster band.
7045 : *
7046 : * The default implementation stores them as metadata, and will only work
7047 : * on formats that can save arbitrary metadata. This method cannot detect
7048 : * whether metadata will be properly saved and so may return CE_None even
7049 : * if the statistics will never be saved.
7050 : *
7051 : * This method is the same as the C function GDALSetRasterStatistics().
7052 : *
7053 : * @param dfMin minimum pixel value.
7054 : *
7055 : * @param dfMax maximum pixel value.
7056 : *
7057 : * @param dfMean mean (average) of all pixel values.
7058 : *
7059 : * @param dfStdDev Standard deviation of all pixel values.
7060 : *
7061 : * @return CE_None on success or CE_Failure on failure.
7062 : */
7063 :
7064 479 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7065 : double dfStdDev)
7066 :
7067 : {
7068 479 : char szValue[128] = {0};
7069 :
7070 479 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7071 479 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
7072 :
7073 479 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7074 479 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7075 :
7076 479 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7077 479 : SetMetadataItem("STATISTICS_MEAN", szValue);
7078 :
7079 479 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7080 479 : SetMetadataItem("STATISTICS_STDDEV", szValue);
7081 :
7082 479 : return CE_None;
7083 : }
7084 :
7085 : /************************************************************************/
7086 : /* GDALSetRasterStatistics() */
7087 : /************************************************************************/
7088 :
7089 : /**
7090 : * \brief Set statistics on band.
7091 : *
7092 : * @see GDALRasterBand::SetStatistics()
7093 : */
7094 :
7095 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7096 : double dfMax, double dfMean,
7097 : double dfStdDev)
7098 :
7099 : {
7100 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7101 :
7102 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7103 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7104 : }
7105 :
7106 : /************************************************************************/
7107 : /* ComputeRasterMinMax() */
7108 : /************************************************************************/
7109 :
7110 : template <class T, bool HAS_NODATA>
7111 120175 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7112 : T *pMax)
7113 : {
7114 120175 : T min0 = *pMin;
7115 120175 : T max0 = *pMax;
7116 120175 : T min1 = *pMin;
7117 120175 : T max1 = *pMax;
7118 : size_t i;
7119 214453 : for (i = 0; i + 1 < nElts; i += 2)
7120 : {
7121 81892 : if (!HAS_NODATA || buffer[i] != nodataValue)
7122 : {
7123 94278 : min0 = std::min(min0, buffer[i]);
7124 94278 : max0 = std::max(max0, buffer[i]);
7125 : }
7126 81892 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7127 : {
7128 94278 : min1 = std::min(min1, buffer[i + 1]);
7129 94278 : max1 = std::max(max1, buffer[i + 1]);
7130 : }
7131 : }
7132 120175 : T min = std::min(min0, min1);
7133 120175 : T max = std::max(max0, max1);
7134 120175 : if (i < nElts)
7135 : {
7136 118460 : if (!HAS_NODATA || buffer[i] != nodataValue)
7137 : {
7138 118480 : min = std::min(min, buffer[i]);
7139 118480 : max = std::max(max, buffer[i]);
7140 : }
7141 : }
7142 120175 : *pMin = min;
7143 120175 : *pMax = max;
7144 120175 : }
7145 :
7146 : template <GDALDataType eDataType, bool bSignedByte>
7147 : static void
7148 11300 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7149 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7150 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
7151 : {
7152 11300 : double dfLocalMin = dfMin;
7153 11300 : double dfLocalMax = dfMax;
7154 :
7155 40711 : for (int iY = 0; iY < nYCheck; iY++)
7156 : {
7157 18962027 : for (int iX = 0; iX < nXCheck; iX++)
7158 : {
7159 18932631 : const GPtrDiff_t iOffset =
7160 18932631 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7161 18932631 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7162 3460310 : continue;
7163 18838390 : bool bValid = true;
7164 18838390 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7165 : iOffset, sNoDataValues, bValid);
7166 18838390 : if (!bValid)
7167 3366069 : continue;
7168 :
7169 15472282 : dfLocalMin = std::min(dfLocalMin, dfValue);
7170 15472282 : dfLocalMax = std::max(dfLocalMax, dfValue);
7171 : }
7172 : }
7173 :
7174 11300 : dfMin = dfLocalMin;
7175 11300 : dfMax = dfLocalMax;
7176 11300 : }
7177 :
7178 11300 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
7179 : bool bSignedByte, int nXCheck, int nYCheck,
7180 : int nBlockXSize,
7181 : const GDALNoDataValues &sNoDataValues,
7182 : const GByte *pabyMaskData, double &dfMin,
7183 : double &dfMax)
7184 : {
7185 11300 : switch (eDataType)
7186 : {
7187 0 : case GDT_Unknown:
7188 0 : CPLAssert(false);
7189 : break;
7190 672 : case GDT_Byte:
7191 672 : if (bSignedByte)
7192 : {
7193 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
7194 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7195 : pabyMaskData, dfMin, dfMax);
7196 : }
7197 : else
7198 : {
7199 669 : ComputeMinMaxGeneric<GDT_Byte, false>(
7200 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7201 : pabyMaskData, dfMin, dfMax);
7202 : }
7203 672 : break;
7204 106 : case GDT_Int8:
7205 106 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
7206 : nBlockXSize, sNoDataValues,
7207 : pabyMaskData, dfMin, dfMax);
7208 106 : break;
7209 200 : case GDT_UInt16:
7210 200 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
7211 : nBlockXSize, sNoDataValues,
7212 : pabyMaskData, dfMin, dfMax);
7213 200 : break;
7214 1 : case GDT_Int16:
7215 1 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
7216 : nBlockXSize, sNoDataValues,
7217 : pabyMaskData, dfMin, dfMax);
7218 1 : break;
7219 201 : case GDT_UInt32:
7220 201 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
7221 : nBlockXSize, sNoDataValues,
7222 : pabyMaskData, dfMin, dfMax);
7223 201 : break;
7224 1048 : case GDT_Int32:
7225 1048 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
7226 : nBlockXSize, sNoDataValues,
7227 : pabyMaskData, dfMin, dfMax);
7228 1048 : break;
7229 16 : case GDT_UInt64:
7230 16 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
7231 : nBlockXSize, sNoDataValues,
7232 : pabyMaskData, dfMin, dfMax);
7233 16 : break;
7234 28 : case GDT_Int64:
7235 28 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
7236 : nBlockXSize, sNoDataValues,
7237 : pabyMaskData, dfMin, dfMax);
7238 28 : break;
7239 0 : case GDT_Float16:
7240 0 : ComputeMinMaxGeneric<GDT_Float16, false>(
7241 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7242 : pabyMaskData, dfMin, dfMax);
7243 0 : break;
7244 5545 : case GDT_Float32:
7245 5545 : ComputeMinMaxGeneric<GDT_Float32, false>(
7246 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7247 : pabyMaskData, dfMin, dfMax);
7248 5545 : break;
7249 3373 : case GDT_Float64:
7250 3373 : ComputeMinMaxGeneric<GDT_Float64, false>(
7251 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7252 : pabyMaskData, dfMin, dfMax);
7253 3373 : break;
7254 9 : case GDT_CInt16:
7255 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
7256 : nBlockXSize, sNoDataValues,
7257 : pabyMaskData, dfMin, dfMax);
7258 9 : break;
7259 9 : case GDT_CInt32:
7260 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
7261 : nBlockXSize, sNoDataValues,
7262 : pabyMaskData, dfMin, dfMax);
7263 9 : break;
7264 0 : case GDT_CFloat16:
7265 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
7266 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7267 : pabyMaskData, dfMin, dfMax);
7268 0 : break;
7269 75 : case GDT_CFloat32:
7270 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
7271 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7272 : pabyMaskData, dfMin, dfMax);
7273 75 : break;
7274 17 : case GDT_CFloat64:
7275 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
7276 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7277 : pabyMaskData, dfMin, dfMax);
7278 17 : break;
7279 0 : case GDT_TypeCount:
7280 0 : CPLAssert(false);
7281 : break;
7282 : }
7283 11300 : }
7284 :
7285 720 : static bool ComputeMinMaxGenericIterBlocks(
7286 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
7287 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
7288 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
7289 : double &dfMin, double &dfMax)
7290 :
7291 : {
7292 720 : GByte *pabyMaskData = nullptr;
7293 : int nBlockXSize, nBlockYSize;
7294 720 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7295 :
7296 720 : if (poMaskBand)
7297 : {
7298 : pabyMaskData =
7299 40 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7300 40 : if (!pabyMaskData)
7301 : {
7302 0 : return false;
7303 : }
7304 : }
7305 :
7306 12020 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7307 11300 : iSampleBlock += nSampleRate)
7308 : {
7309 11300 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7310 11300 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7311 :
7312 11300 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7313 11300 : if (poBlock == nullptr)
7314 : {
7315 0 : CPLFree(pabyMaskData);
7316 0 : return false;
7317 : }
7318 :
7319 11300 : void *const pData = poBlock->GetDataRef();
7320 :
7321 11300 : int nXCheck = 0, nYCheck = 0;
7322 11300 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7323 :
7324 12171 : if (poMaskBand &&
7325 871 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7326 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7327 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7328 : nBlockXSize, nullptr) != CE_None)
7329 : {
7330 0 : poBlock->DropLock();
7331 0 : CPLFree(pabyMaskData);
7332 0 : return false;
7333 : }
7334 :
7335 11300 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7336 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
7337 : dfMax);
7338 :
7339 11300 : poBlock->DropLock();
7340 : }
7341 :
7342 720 : CPLFree(pabyMaskData);
7343 720 : return true;
7344 : }
7345 :
7346 : /**
7347 : * \brief Compute the min/max values for a band.
7348 : *
7349 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7350 : * be trusted. If it doesn't work, a subsample of blocks will be read to
7351 : * get an approximate min/max. If the band has a nodata value it will
7352 : * be excluded from the minimum and maximum.
7353 : *
7354 : * If bApprox is FALSE, then all pixels will be read and used to compute
7355 : * an exact range.
7356 : *
7357 : * This method is the same as the C function GDALComputeRasterMinMax().
7358 : *
7359 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7360 : * FALSE.
7361 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7362 : * maximum (adfMinMax[1]) are returned.
7363 : *
7364 : * @return CE_None on success or CE_Failure on failure.
7365 : */
7366 :
7367 1559 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7368 : {
7369 : /* -------------------------------------------------------------------- */
7370 : /* Does the driver already know the min/max? */
7371 : /* -------------------------------------------------------------------- */
7372 1559 : if (bApproxOK)
7373 : {
7374 23 : int bSuccessMin = FALSE;
7375 23 : int bSuccessMax = FALSE;
7376 :
7377 23 : double dfMin = GetMinimum(&bSuccessMin);
7378 23 : double dfMax = GetMaximum(&bSuccessMax);
7379 :
7380 23 : if (bSuccessMin && bSuccessMax)
7381 : {
7382 1 : adfMinMax[0] = dfMin;
7383 1 : adfMinMax[1] = dfMax;
7384 1 : return CE_None;
7385 : }
7386 : }
7387 :
7388 : /* -------------------------------------------------------------------- */
7389 : /* If we have overview bands, use them for min/max. */
7390 : /* -------------------------------------------------------------------- */
7391 : // cppcheck-suppress knownConditionTrueFalse
7392 1558 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7393 : {
7394 : GDALRasterBand *poBand =
7395 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7396 :
7397 0 : if (poBand != this)
7398 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7399 : }
7400 :
7401 : /* -------------------------------------------------------------------- */
7402 : /* Read actual data and compute minimum and maximum. */
7403 : /* -------------------------------------------------------------------- */
7404 1558 : GDALNoDataValues sNoDataValues(this, eDataType);
7405 1558 : GDALRasterBand *poMaskBand = nullptr;
7406 1558 : if (!sNoDataValues.bGotNoDataValue)
7407 : {
7408 1313 : const int l_nMaskFlags = GetMaskFlags();
7409 1353 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7410 40 : GetColorInterpretation() != GCI_AlphaBand)
7411 : {
7412 40 : poMaskBand = GetMaskBand();
7413 : }
7414 : }
7415 :
7416 1558 : bool bSignedByte = false;
7417 1558 : if (eDataType == GDT_Byte)
7418 : {
7419 630 : EnablePixelTypeSignedByteWarning(false);
7420 : const char *pszPixelType =
7421 630 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7422 630 : EnablePixelTypeSignedByteWarning(true);
7423 630 : bSignedByte =
7424 630 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7425 : }
7426 :
7427 : GDALRasterIOExtraArg sExtraArg;
7428 1558 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7429 :
7430 3116 : GUInt32 nMin = (eDataType == GDT_Byte)
7431 1558 : ? 255
7432 : : 65535; // used for GByte & GUInt16 cases
7433 1558 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
7434 1558 : GInt16 nMinInt16 =
7435 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
7436 1558 : GInt16 nMaxInt16 =
7437 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
7438 1558 : double dfMin =
7439 : std::numeric_limits<double>::infinity(); // used for generic code path
7440 1558 : double dfMax =
7441 : -std::numeric_limits<double>::infinity(); // used for generic code path
7442 1558 : const bool bUseOptimizedPath =
7443 2477 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7444 919 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7445 :
7446 : const auto ComputeMinMaxForBlock =
7447 20447 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
7448 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
7449 240537 : int nYCheck)
7450 : {
7451 20447 : if (eDataType == GDT_Byte && !bSignedByte)
7452 : {
7453 : const bool bHasNoData =
7454 11561 : sNoDataValues.bGotNoDataValue &&
7455 29466 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
7456 11561 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
7457 11561 : sNoDataValues.dfNoDataValue;
7458 17905 : const GUInt32 nNoDataValue =
7459 17905 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
7460 : : 0;
7461 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7462 : ComputeStatisticsInternal<GByte,
7463 : /* COMPUTE_OTHER_STATS = */ false>::
7464 17905 : f(nXCheck, nBufferWidth, nYCheck,
7465 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7466 17905 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7467 : }
7468 2542 : else if (eDataType == GDT_UInt16)
7469 : {
7470 : const bool bHasNoData =
7471 83 : sNoDataValues.bGotNoDataValue &&
7472 1237 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
7473 83 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
7474 83 : sNoDataValues.dfNoDataValue;
7475 1154 : const GUInt32 nNoDataValue =
7476 1154 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
7477 : : 0;
7478 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7479 : ComputeStatisticsInternal<GUInt16,
7480 : /* COMPUTE_OTHER_STATS = */ false>::
7481 1154 : f(nXCheck, nBufferWidth, nYCheck,
7482 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7483 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7484 : }
7485 1388 : else if (eDataType == GDT_Int16)
7486 : {
7487 : const bool bHasNoData =
7488 1214 : sNoDataValues.bGotNoDataValue &&
7489 2602 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
7490 1214 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
7491 1214 : sNoDataValues.dfNoDataValue;
7492 1388 : if (bHasNoData)
7493 : {
7494 1214 : const int16_t nNoDataValue =
7495 1214 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
7496 120117 : for (int iY = 0; iY < nYCheck; iY++)
7497 : {
7498 118903 : ComputeMinMax<int16_t, true>(
7499 118903 : static_cast<const int16_t *>(pData) +
7500 118903 : static_cast<size_t>(iY) * nBufferWidth,
7501 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7502 : }
7503 : }
7504 : else
7505 : {
7506 1446 : for (int iY = 0; iY < nYCheck; iY++)
7507 : {
7508 1272 : ComputeMinMax<int16_t, false>(
7509 1272 : static_cast<const int16_t *>(pData) +
7510 1272 : static_cast<size_t>(iY) * nBufferWidth,
7511 : nXCheck, 0, &nMinInt16, &nMaxInt16);
7512 : }
7513 : }
7514 : }
7515 20447 : };
7516 :
7517 1558 : if (bApproxOK && HasArbitraryOverviews())
7518 : {
7519 : /* --------------------------------------------------------------------
7520 : */
7521 : /* Figure out how much the image should be reduced to get an */
7522 : /* approximate value. */
7523 : /* --------------------------------------------------------------------
7524 : */
7525 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7526 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7527 :
7528 0 : int nXReduced = nRasterXSize;
7529 0 : int nYReduced = nRasterYSize;
7530 0 : if (dfReduction > 1.0)
7531 : {
7532 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7533 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7534 :
7535 : // Catch the case of huge resizing ratios here
7536 0 : if (nXReduced == 0)
7537 0 : nXReduced = 1;
7538 0 : if (nYReduced == 0)
7539 0 : nYReduced = 1;
7540 : }
7541 :
7542 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
7543 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7544 :
7545 : const CPLErr eErr =
7546 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7547 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7548 0 : if (eErr != CE_None)
7549 : {
7550 0 : CPLFree(pData);
7551 0 : return eErr;
7552 : }
7553 :
7554 0 : GByte *pabyMaskData = nullptr;
7555 0 : if (poMaskBand)
7556 : {
7557 : pabyMaskData =
7558 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7559 0 : if (!pabyMaskData)
7560 : {
7561 0 : CPLFree(pData);
7562 0 : return CE_Failure;
7563 : }
7564 :
7565 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7566 : pabyMaskData, nXReduced, nYReduced,
7567 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
7568 : {
7569 0 : CPLFree(pData);
7570 0 : CPLFree(pabyMaskData);
7571 0 : return CE_Failure;
7572 : }
7573 : }
7574 :
7575 0 : if (bUseOptimizedPath)
7576 : {
7577 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7578 : }
7579 : else
7580 : {
7581 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
7582 : nYReduced, nXReduced, sNoDataValues,
7583 : pabyMaskData, dfMin, dfMax);
7584 : }
7585 :
7586 0 : CPLFree(pData);
7587 0 : CPLFree(pabyMaskData);
7588 : }
7589 :
7590 : else // No arbitrary overviews
7591 : {
7592 1558 : if (!InitBlockInfo())
7593 0 : return CE_Failure;
7594 :
7595 : /* --------------------------------------------------------------------
7596 : */
7597 : /* Figure out the ratio of blocks we will read to get an */
7598 : /* approximate value. */
7599 : /* --------------------------------------------------------------------
7600 : */
7601 1558 : int nSampleRate = 1;
7602 :
7603 1558 : if (bApproxOK)
7604 : {
7605 22 : nSampleRate = static_cast<int>(std::max(
7606 44 : 1.0,
7607 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7608 : // We want to avoid probing only the first column of blocks for
7609 : // a square shaped raster, because it is not unlikely that it may
7610 : // be padding only (#6378).
7611 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7612 0 : nSampleRate += 1;
7613 : }
7614 :
7615 1558 : if (bUseOptimizedPath)
7616 : {
7617 838 : for (GIntBig iSampleBlock = 0;
7618 21210 : iSampleBlock <
7619 21210 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7620 20372 : iSampleBlock += nSampleRate)
7621 : {
7622 20448 : const int iYBlock =
7623 20448 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7624 20448 : const int iXBlock =
7625 20448 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7626 :
7627 20448 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7628 20448 : if (poBlock == nullptr)
7629 1 : return CE_Failure;
7630 :
7631 20447 : void *const pData = poBlock->GetDataRef();
7632 :
7633 20447 : int nXCheck = 0, nYCheck = 0;
7634 20447 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7635 :
7636 20447 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7637 :
7638 20447 : poBlock->DropLock();
7639 :
7640 20447 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7641 4023 : nMax == 255)
7642 75 : break;
7643 : }
7644 : }
7645 : else
7646 : {
7647 720 : const GIntBig nTotalBlocks =
7648 720 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7649 720 : if (!ComputeMinMaxGenericIterBlocks(
7650 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7651 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
7652 : {
7653 0 : return CE_Failure;
7654 : }
7655 : }
7656 : }
7657 :
7658 1557 : if (bUseOptimizedPath)
7659 : {
7660 837 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7661 : {
7662 735 : dfMin = nMin;
7663 735 : dfMax = nMax;
7664 : }
7665 102 : else if (eDataType == GDT_Int16)
7666 : {
7667 102 : dfMin = nMinInt16;
7668 102 : dfMax = nMaxInt16;
7669 : }
7670 : }
7671 :
7672 1557 : if (dfMin > dfMax)
7673 : {
7674 8 : adfMinMax[0] = 0;
7675 8 : adfMinMax[1] = 0;
7676 8 : ReportError(
7677 : CE_Failure, CPLE_AppDefined,
7678 : "Failed to compute min/max, no valid pixels found in sampling.");
7679 8 : return CE_Failure;
7680 : }
7681 :
7682 1549 : adfMinMax[0] = dfMin;
7683 1549 : adfMinMax[1] = dfMax;
7684 :
7685 1549 : return CE_None;
7686 : }
7687 :
7688 : /************************************************************************/
7689 : /* GDALComputeRasterMinMax() */
7690 : /************************************************************************/
7691 :
7692 : /**
7693 : * \brief Compute the min/max values for a band.
7694 : *
7695 : * @see GDALRasterBand::ComputeRasterMinMax()
7696 : *
7697 : * @note Prior to GDAL 3.6, this function returned void
7698 : */
7699 :
7700 1479 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7701 : double adfMinMax[2])
7702 :
7703 : {
7704 1479 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7705 :
7706 1479 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7707 1479 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7708 : }
7709 :
7710 : /************************************************************************/
7711 : /* ComputeRasterMinMaxLocation() */
7712 : /************************************************************************/
7713 :
7714 : /**
7715 : * \brief Compute the min/max values for a band, and their location.
7716 : *
7717 : * Pixels whose value matches the nodata value or are masked by the mask
7718 : * band are ignored.
7719 : *
7720 : * If the minimum or maximum value is hit in several locations, it is not
7721 : * specified which one will be returned.
7722 : *
7723 : * @param[out] pdfMin Pointer to the minimum value.
7724 : * @param[out] pdfMax Pointer to the maximum value.
7725 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7726 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7727 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7728 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7729 : *
7730 : * @return CE_None in case of success, CE_Warning if there are no valid values,
7731 : * CE_Failure in case of error.
7732 : *
7733 : * @since GDAL 3.11
7734 : */
7735 :
7736 8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7737 : double *pdfMax, int *pnMinX,
7738 : int *pnMinY, int *pnMaxX,
7739 : int *pnMaxY)
7740 : {
7741 8 : int nMinX = -1;
7742 8 : int nMinY = -1;
7743 8 : int nMaxX = -1;
7744 8 : int nMaxY = -1;
7745 8 : double dfMin = std::numeric_limits<double>::infinity();
7746 8 : double dfMax = -std::numeric_limits<double>::infinity();
7747 8 : if (pdfMin)
7748 5 : *pdfMin = dfMin;
7749 8 : if (pdfMax)
7750 5 : *pdfMax = dfMax;
7751 8 : if (pnMinX)
7752 6 : *pnMinX = nMinX;
7753 8 : if (pnMinY)
7754 6 : *pnMinY = nMinY;
7755 8 : if (pnMaxX)
7756 6 : *pnMaxX = nMaxX;
7757 8 : if (pnMaxY)
7758 6 : *pnMaxY = nMaxY;
7759 :
7760 8 : if (GDALDataTypeIsComplex(eDataType))
7761 : {
7762 0 : CPLError(CE_Failure, CPLE_NotSupported,
7763 : "Complex data type not supported");
7764 0 : return CE_Failure;
7765 : }
7766 :
7767 8 : if (!InitBlockInfo())
7768 0 : return CE_Failure;
7769 :
7770 8 : GDALNoDataValues sNoDataValues(this, eDataType);
7771 8 : GDALRasterBand *poMaskBand = nullptr;
7772 8 : if (!sNoDataValues.bGotNoDataValue)
7773 : {
7774 8 : const int l_nMaskFlags = GetMaskFlags();
7775 9 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7776 1 : GetColorInterpretation() != GCI_AlphaBand)
7777 : {
7778 1 : poMaskBand = GetMaskBand();
7779 : }
7780 : }
7781 :
7782 8 : bool bSignedByte = false;
7783 8 : if (eDataType == GDT_Byte)
7784 : {
7785 7 : EnablePixelTypeSignedByteWarning(false);
7786 : const char *pszPixelType =
7787 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7788 7 : EnablePixelTypeSignedByteWarning(true);
7789 7 : bSignedByte =
7790 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7791 : }
7792 :
7793 8 : GByte *pabyMaskData = nullptr;
7794 8 : if (poMaskBand)
7795 : {
7796 : pabyMaskData =
7797 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7798 1 : if (!pabyMaskData)
7799 : {
7800 0 : return CE_Failure;
7801 : }
7802 : }
7803 :
7804 8 : const GIntBig nTotalBlocks =
7805 8 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7806 8 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7807 8 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7808 16 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7809 : {
7810 11 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7811 11 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7812 :
7813 11 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7814 11 : if (poBlock == nullptr)
7815 : {
7816 0 : CPLFree(pabyMaskData);
7817 0 : return CE_Failure;
7818 : }
7819 :
7820 11 : void *const pData = poBlock->GetDataRef();
7821 :
7822 11 : int nXCheck = 0, nYCheck = 0;
7823 11 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7824 :
7825 13 : if (poMaskBand &&
7826 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7827 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7828 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7829 2 : nBlockXSize, nullptr) != CE_None)
7830 : {
7831 0 : poBlock->DropLock();
7832 0 : CPLFree(pabyMaskData);
7833 0 : return CE_Failure;
7834 : }
7835 :
7836 11 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7837 : {
7838 4 : for (int iY = 0; iY < nYCheck; ++iY)
7839 : {
7840 6 : for (int iX = 0; iX < nXCheck; ++iX)
7841 : {
7842 4 : const GPtrDiff_t iOffset =
7843 4 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7844 4 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7845 2 : continue;
7846 2 : bool bValid = true;
7847 : double dfValue =
7848 2 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
7849 : sNoDataValues, bValid);
7850 2 : if (!bValid)
7851 0 : continue;
7852 2 : if (dfValue < dfMin)
7853 : {
7854 2 : dfMin = dfValue;
7855 2 : nMinX = iXBlock * nBlockXSize + iX;
7856 2 : nMinY = iYBlock * nBlockYSize + iY;
7857 : }
7858 2 : if (dfValue > dfMax)
7859 : {
7860 1 : dfMax = dfValue;
7861 1 : nMaxX = iXBlock * nBlockXSize + iX;
7862 1 : nMaxY = iYBlock * nBlockYSize + iY;
7863 : }
7864 : }
7865 2 : }
7866 : }
7867 : else
7868 : {
7869 9 : size_t pos_min = 0;
7870 9 : size_t pos_max = 0;
7871 9 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7872 9 : if (bNeedsMin && bNeedsMax)
7873 : {
7874 10 : std::tie(pos_min, pos_max) = gdal::minmax_element(
7875 5 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7876 5 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7877 10 : sNoDataValues.dfNoDataValue);
7878 : }
7879 4 : else if (bNeedsMin)
7880 : {
7881 1 : pos_min = gdal::min_element(
7882 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7883 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7884 : sNoDataValues.dfNoDataValue);
7885 : }
7886 3 : else if (bNeedsMax)
7887 : {
7888 2 : pos_max = gdal::max_element(
7889 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7890 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7891 : sNoDataValues.dfNoDataValue);
7892 : }
7893 :
7894 9 : if (bNeedsMin)
7895 : {
7896 6 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7897 6 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7898 6 : bool bValid = true;
7899 : const double dfMinValueBlock =
7900 6 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
7901 : sNoDataValues, bValid);
7902 6 : if (bValid && dfMinValueBlock < dfMin)
7903 : {
7904 5 : dfMin = dfMinValueBlock;
7905 5 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
7906 5 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
7907 : }
7908 : }
7909 :
7910 9 : if (bNeedsMax)
7911 : {
7912 7 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7913 7 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7914 7 : bool bValid = true;
7915 : const double dfMaxValueBlock =
7916 7 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
7917 : sNoDataValues, bValid);
7918 7 : if (bValid && dfMaxValueBlock > dfMax)
7919 : {
7920 5 : dfMax = dfMaxValueBlock;
7921 5 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7922 5 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7923 : }
7924 : }
7925 : }
7926 :
7927 11 : poBlock->DropLock();
7928 :
7929 11 : if (eDataType == GDT_Byte)
7930 : {
7931 10 : if (bNeedsMin && dfMin == 0)
7932 : {
7933 1 : bNeedsMin = false;
7934 : }
7935 10 : if (bNeedsMax && dfMax == 255)
7936 : {
7937 4 : bNeedsMax = false;
7938 : }
7939 10 : if (!bNeedsMin && !bNeedsMax)
7940 : {
7941 3 : break;
7942 : }
7943 : }
7944 : }
7945 :
7946 8 : CPLFree(pabyMaskData);
7947 :
7948 8 : if (pdfMin)
7949 5 : *pdfMin = dfMin;
7950 8 : if (pdfMax)
7951 5 : *pdfMax = dfMax;
7952 8 : if (pnMinX)
7953 6 : *pnMinX = nMinX;
7954 8 : if (pnMinY)
7955 6 : *pnMinY = nMinY;
7956 8 : if (pnMaxX)
7957 6 : *pnMaxX = nMaxX;
7958 8 : if (pnMaxY)
7959 6 : *pnMaxY = nMaxY;
7960 8 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
7961 8 : : CE_None;
7962 : }
7963 :
7964 : /************************************************************************/
7965 : /* GDALComputeRasterMinMaxLocation() */
7966 : /************************************************************************/
7967 :
7968 : /**
7969 : * \brief Compute the min/max values for a band, and their location.
7970 : *
7971 : * @see GDALRasterBand::ComputeRasterMinMax()
7972 : * @since GDAL 3.11
7973 : */
7974 :
7975 6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
7976 : double *pdfMax, int *pnMinX, int *pnMinY,
7977 : int *pnMaxX, int *pnMaxY)
7978 :
7979 : {
7980 6 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
7981 :
7982 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7983 6 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
7984 6 : pnMaxX, pnMaxY);
7985 : }
7986 :
7987 : /************************************************************************/
7988 : /* SetDefaultHistogram() */
7989 : /************************************************************************/
7990 :
7991 : /* FIXME : add proper documentation */
7992 : /**
7993 : * \brief Set default histogram.
7994 : *
7995 : * This method is the same as the C function GDALSetDefaultHistogram() and
7996 : * GDALSetDefaultHistogramEx()
7997 : */
7998 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
7999 : double /* dfMax */,
8000 : int /* nBuckets */,
8001 : GUIntBig * /* panHistogram */)
8002 :
8003 : {
8004 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8005 0 : ReportError(CE_Failure, CPLE_NotSupported,
8006 : "SetDefaultHistogram() not implemented for this format.");
8007 :
8008 0 : return CE_Failure;
8009 : }
8010 :
8011 : /************************************************************************/
8012 : /* GDALSetDefaultHistogram() */
8013 : /************************************************************************/
8014 :
8015 : /**
8016 : * \brief Set default histogram.
8017 : *
8018 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8019 : * 2 billion.
8020 : *
8021 : * @see GDALRasterBand::SetDefaultHistogram()
8022 : * @see GDALSetRasterHistogramEx()
8023 : */
8024 :
8025 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8026 : double dfMax, int nBuckets,
8027 : int *panHistogram)
8028 :
8029 : {
8030 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8031 :
8032 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8033 :
8034 : GUIntBig *panHistogramTemp =
8035 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8036 0 : if (panHistogramTemp == nullptr)
8037 : {
8038 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8039 : "Out of memory in GDALSetDefaultHistogram().");
8040 0 : return CE_Failure;
8041 : }
8042 :
8043 0 : for (int i = 0; i < nBuckets; ++i)
8044 : {
8045 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8046 : }
8047 :
8048 : const CPLErr eErr =
8049 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8050 :
8051 0 : CPLFree(panHistogramTemp);
8052 :
8053 0 : return eErr;
8054 : }
8055 :
8056 : /************************************************************************/
8057 : /* GDALSetDefaultHistogramEx() */
8058 : /************************************************************************/
8059 :
8060 : /**
8061 : * \brief Set default histogram.
8062 : *
8063 : * @see GDALRasterBand::SetDefaultHistogram()
8064 : *
8065 : * @since GDAL 2.0
8066 : */
8067 :
8068 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8069 : double dfMin, double dfMax,
8070 : int nBuckets,
8071 : GUIntBig *panHistogram)
8072 :
8073 : {
8074 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8075 :
8076 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8077 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8078 : }
8079 :
8080 : /************************************************************************/
8081 : /* GetDefaultRAT() */
8082 : /************************************************************************/
8083 :
8084 : /**
8085 : * \brief Fetch default Raster Attribute Table.
8086 : *
8087 : * A RAT will be returned if there is a default one associated with the
8088 : * band, otherwise NULL is returned. The returned RAT is owned by the
8089 : * band and should not be deleted by the application.
8090 : *
8091 : * This method is the same as the C function GDALGetDefaultRAT().
8092 : *
8093 : * @return NULL, or a pointer to an internal RAT owned by the band.
8094 : */
8095 :
8096 173 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8097 :
8098 : {
8099 173 : return nullptr;
8100 : }
8101 :
8102 : /************************************************************************/
8103 : /* GDALGetDefaultRAT() */
8104 : /************************************************************************/
8105 :
8106 : /**
8107 : * \brief Fetch default Raster Attribute Table.
8108 : *
8109 : * @see GDALRasterBand::GetDefaultRAT()
8110 : */
8111 :
8112 1058 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8113 :
8114 : {
8115 1058 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8116 :
8117 1058 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8118 1058 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8119 : }
8120 :
8121 : /************************************************************************/
8122 : /* SetDefaultRAT() */
8123 : /************************************************************************/
8124 :
8125 : /**
8126 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8127 : * \brief Set default Raster Attribute Table.
8128 : *
8129 : * Associates a default RAT with the band. If not implemented for the
8130 : * format a CPLE_NotSupported error will be issued. If successful a copy
8131 : * of the RAT is made, the original remains owned by the caller.
8132 : *
8133 : * This method is the same as the C function GDALSetDefaultRAT().
8134 : *
8135 : * @param poRAT the RAT to assign to the band.
8136 : *
8137 : * @return CE_None on success or CE_Failure if unsupported or otherwise
8138 : * failing.
8139 : */
8140 :
8141 : /**/
8142 : /**/
8143 :
8144 : CPLErr
8145 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8146 : {
8147 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8148 : {
8149 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
8150 0 : ReportError(CE_Failure, CPLE_NotSupported,
8151 : "SetDefaultRAT() not implemented for this format.");
8152 0 : CPLPopErrorHandler();
8153 : }
8154 0 : return CE_Failure;
8155 : }
8156 :
8157 : /************************************************************************/
8158 : /* GDALSetDefaultRAT() */
8159 : /************************************************************************/
8160 :
8161 : /**
8162 : * \brief Set default Raster Attribute Table.
8163 : *
8164 : * @see GDALRasterBand::GDALSetDefaultRAT()
8165 : */
8166 :
8167 18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
8168 : GDALRasterAttributeTableH hRAT)
8169 :
8170 : {
8171 18 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
8172 :
8173 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8174 :
8175 18 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
8176 : }
8177 :
8178 : /************************************************************************/
8179 : /* GetMaskBand() */
8180 : /************************************************************************/
8181 :
8182 : /**
8183 : * \brief Return the mask band associated with the band.
8184 : *
8185 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8186 : * that returns one of four default implementations :
8187 : * <ul>
8188 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8189 : * </li>
8190 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8191 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8192 : * GMF_NODATA | GMF_PER_DATASET.
8193 : * </li>
8194 : * <li>If the band has a nodata value set, an instance of the new
8195 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8196 : * GMF_NODATA.
8197 : * </li>
8198 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
8199 : * to apply to this band (specific rules yet to be determined) and that is of
8200 : * type GDT_Byte then that alpha band will be returned, and the flags
8201 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8202 : * </li>
8203 : * <li>If neither of the above apply, an instance of the new
8204 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8205 : * pixels. The null flags will return GMF_ALL_VALID.
8206 : * </li>
8207 : * </ul>
8208 : *
8209 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
8210 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
8211 : *
8212 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8213 : * dataset, with the same name as the main dataset and suffixed with .msk,
8214 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8215 : * main dataset.
8216 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8217 : * level, where xx matches the band number of a band of the main dataset. The
8218 : * value of those items is a combination of the flags GMF_ALL_VALID,
8219 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8220 : * a band, then the other rules explained above will be used to generate a
8221 : * on-the-fly mask band.
8222 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8223 : *
8224 : * This method is the same as the C function GDALGetMaskBand().
8225 : *
8226 : * @return a valid mask band.
8227 : *
8228 : * @since GDAL 1.5.0
8229 : *
8230 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8231 : *
8232 : */
8233 801472 : GDALRasterBand *GDALRasterBand::GetMaskBand()
8234 :
8235 : {
8236 386636 : const auto HasNoData = [this]()
8237 : {
8238 128553 : int bHaveNoDataRaw = FALSE;
8239 128553 : bool bHaveNoData = false;
8240 128553 : if (eDataType == GDT_Int64)
8241 : {
8242 64 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
8243 64 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8244 : }
8245 128489 : else if (eDataType == GDT_UInt64)
8246 : {
8247 46 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
8248 46 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8249 : }
8250 : else
8251 : {
8252 128443 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
8253 128427 : if (bHaveNoDataRaw &&
8254 128427 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
8255 : {
8256 1000 : bHaveNoData = true;
8257 : }
8258 : }
8259 128531 : return bHaveNoData;
8260 801472 : };
8261 :
8262 801472 : if (poMask != nullptr)
8263 : {
8264 703826 : if (poMask.IsOwned())
8265 : {
8266 332795 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
8267 : {
8268 33368 : if (HasNoData())
8269 : {
8270 9 : InvalidateMaskBand();
8271 : }
8272 : }
8273 299832 : else if (auto poNoDataMaskBand =
8274 299656 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
8275 : {
8276 280 : int bHaveNoDataRaw = FALSE;
8277 280 : bool bIsSame = false;
8278 280 : if (eDataType == GDT_Int64)
8279 9 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
8280 11 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
8281 2 : bHaveNoDataRaw;
8282 271 : else if (eDataType == GDT_UInt64)
8283 9 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8284 11 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8285 2 : bHaveNoDataRaw;
8286 : else
8287 : {
8288 : const double dfNoDataValue =
8289 262 : GetNoDataValue(&bHaveNoDataRaw);
8290 261 : if (bHaveNoDataRaw)
8291 : {
8292 259 : bIsSame =
8293 258 : std::isnan(dfNoDataValue)
8294 258 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8295 233 : : poNoDataMaskBand->m_dfNoDataValue ==
8296 : dfNoDataValue;
8297 : }
8298 : }
8299 280 : if (!bIsSame)
8300 23 : InvalidateMaskBand();
8301 : }
8302 : }
8303 :
8304 706918 : if (poMask)
8305 708605 : return poMask.get();
8306 : }
8307 :
8308 : /* -------------------------------------------------------------------- */
8309 : /* Check for a mask in a .msk file. */
8310 : /* -------------------------------------------------------------------- */
8311 95288 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8312 : {
8313 46 : poMask.reset(poDS->oOvManager.GetMaskBand(nBand), false);
8314 46 : if (poMask != nullptr)
8315 : {
8316 44 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8317 44 : return poMask.get();
8318 : }
8319 : }
8320 :
8321 : /* -------------------------------------------------------------------- */
8322 : /* Check for NODATA_VALUES metadata. */
8323 : /* -------------------------------------------------------------------- */
8324 95243 : if (poDS != nullptr)
8325 : {
8326 : const char *pszGDALNoDataValues =
8327 95229 : poDS->GetMetadataItem("NODATA_VALUES");
8328 95228 : if (pszGDALNoDataValues != nullptr)
8329 : {
8330 66 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
8331 : pszGDALNoDataValues, " ", FALSE, FALSE);
8332 :
8333 : // Make sure we have as many values as bands.
8334 132 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
8335 66 : poDS->GetRasterCount() != 0)
8336 : {
8337 : // Make sure that all bands have the same data type
8338 : // This is clearly not a fundamental condition, just a
8339 : // condition to make implementation easier.
8340 66 : GDALDataType eDT = GDT_Unknown;
8341 66 : int i = 0; // Used after for.
8342 263 : for (; i < poDS->GetRasterCount(); ++i)
8343 : {
8344 197 : if (i == 0)
8345 66 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8346 131 : else if (eDT !=
8347 131 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
8348 : {
8349 0 : break;
8350 : }
8351 : }
8352 66 : if (i == poDS->GetRasterCount())
8353 : {
8354 66 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8355 : try
8356 : {
8357 66 : poMask.reset(new GDALNoDataValuesMaskBand(poDS), true);
8358 : }
8359 0 : catch (const std::bad_alloc &)
8360 : {
8361 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8362 0 : poMask.reset();
8363 : }
8364 66 : CSLDestroy(papszGDALNoDataValues);
8365 66 : return poMask.get();
8366 : }
8367 : else
8368 : {
8369 0 : ReportError(CE_Warning, CPLE_AppDefined,
8370 : "All bands should have the same type in "
8371 : "order the NODATA_VALUES metadata item "
8372 : "to be used as a mask.");
8373 : }
8374 : }
8375 : else
8376 : {
8377 0 : ReportError(
8378 : CE_Warning, CPLE_AppDefined,
8379 : "NODATA_VALUES metadata item doesn't have the same number "
8380 : "of values as the number of bands. "
8381 : "Ignoring it for mask.");
8382 : }
8383 :
8384 0 : CSLDestroy(papszGDALNoDataValues);
8385 : }
8386 : }
8387 :
8388 : /* -------------------------------------------------------------------- */
8389 : /* Check for nodata case. */
8390 : /* -------------------------------------------------------------------- */
8391 95176 : if (HasNoData())
8392 : {
8393 1022 : nMaskFlags = GMF_NODATA;
8394 : try
8395 : {
8396 1022 : poMask.reset(new GDALNoDataMaskBand(this), true);
8397 : }
8398 0 : catch (const std::bad_alloc &)
8399 : {
8400 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8401 0 : poMask.reset();
8402 : }
8403 1022 : return poMask.get();
8404 : }
8405 :
8406 : /* -------------------------------------------------------------------- */
8407 : /* Check for alpha case. */
8408 : /* -------------------------------------------------------------------- */
8409 94139 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8410 188886 : this == poDS->GetRasterBand(1) &&
8411 590 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8412 : {
8413 233 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8414 : {
8415 189 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8416 189 : poMask.reset(poDS->GetRasterBand(2), false);
8417 189 : return poMask.get();
8418 : }
8419 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8420 : {
8421 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8422 : try
8423 : {
8424 23 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(2)),
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 23 : return poMask.get();
8433 : }
8434 : }
8435 :
8436 93929 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8437 3110 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8438 188617 : this == poDS->GetRasterBand(3)) &&
8439 2414 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8440 : {
8441 1541 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8442 : {
8443 1494 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8444 1494 : poMask.reset(poDS->GetRasterBand(4), false);
8445 1494 : return poMask.get();
8446 : }
8447 47 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8448 : {
8449 35 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8450 : try
8451 : {
8452 35 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(4)),
8453 : true);
8454 : }
8455 0 : catch (const std::bad_alloc &)
8456 : {
8457 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8458 0 : poMask.reset();
8459 : }
8460 35 : return poMask.get();
8461 : }
8462 : }
8463 :
8464 : /* -------------------------------------------------------------------- */
8465 : /* Fallback to all valid case. */
8466 : /* -------------------------------------------------------------------- */
8467 92415 : nMaskFlags = GMF_ALL_VALID;
8468 : try
8469 : {
8470 92415 : poMask.reset(new GDALAllValidMaskBand(this), true);
8471 : }
8472 0 : catch (const std::bad_alloc &)
8473 : {
8474 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8475 0 : poMask.reset();
8476 : }
8477 :
8478 92415 : return poMask.get();
8479 : }
8480 :
8481 : /************************************************************************/
8482 : /* GDALGetMaskBand() */
8483 : /************************************************************************/
8484 :
8485 : /**
8486 : * \brief Return the mask band associated with the band.
8487 : *
8488 : * @see GDALRasterBand::GetMaskBand()
8489 : */
8490 :
8491 10990 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8492 :
8493 : {
8494 10990 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8495 :
8496 10990 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8497 10990 : return poBand->GetMaskBand();
8498 : }
8499 :
8500 : /************************************************************************/
8501 : /* GetMaskFlags() */
8502 : /************************************************************************/
8503 :
8504 : /**
8505 : * \brief Return the status flags of the mask band associated with the band.
8506 : *
8507 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8508 : * the following available definitions that may be extended in the future:
8509 : * <ul>
8510 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8511 : * 255. When used this will normally be the only flag set.
8512 : * </li>
8513 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8514 : * dataset.
8515 : * </li>
8516 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8517 : * and may have values other than 0 and 255.
8518 : * </li>
8519 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8520 : * nodata values. (mutually exclusive of GMF_ALPHA)
8521 : * </li>
8522 : * </ul>
8523 : *
8524 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8525 : * that returns one of four default implementations:
8526 : * <ul>
8527 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8528 : * </li>
8529 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8530 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8531 : * GMF_NODATA | GMF_PER_DATASET.
8532 : * </li>
8533 : * <li>If the band has a nodata value set, an instance of the new
8534 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8535 : * GMF_NODATA.
8536 : * </li>
8537 : * <li>If there is no nodata value, but the dataset has an alpha band that
8538 : * seems to apply to this band (specific rules yet to be determined) and that is
8539 : * of type GDT_Byte then that alpha band will be returned, and the flags
8540 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8541 : * </li>
8542 : * <li>If neither of the above apply, an instance of the new
8543 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8544 : * pixels. The null flags will return GMF_ALL_VALID.
8545 : * </li>
8546 : * </ul>
8547 : *
8548 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8549 : * dataset, with the same name as the main dataset and suffixed with .msk,
8550 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8551 : * main dataset.
8552 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8553 : * level, where xx matches the band number of a band of the main dataset. The
8554 : * value of those items is a combination of the flags GMF_ALL_VALID,
8555 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8556 : * a band, then the other rules explained above will be used to generate a
8557 : * on-the-fly mask band.
8558 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8559 : *
8560 : * This method is the same as the C function GDALGetMaskFlags().
8561 : *
8562 : * @since GDAL 1.5.0
8563 : *
8564 : * @return a valid mask band.
8565 : *
8566 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8567 : *
8568 : */
8569 150604 : int GDALRasterBand::GetMaskFlags()
8570 :
8571 : {
8572 : // If we don't have a band yet, force this now so that the masks value
8573 : // will be initialized.
8574 :
8575 150604 : if (poMask == nullptr)
8576 93936 : GetMaskBand();
8577 :
8578 150598 : return nMaskFlags;
8579 : }
8580 :
8581 : /************************************************************************/
8582 : /* GDALGetMaskFlags() */
8583 : /************************************************************************/
8584 :
8585 : /**
8586 : * \brief Return the status flags of the mask band associated with the band.
8587 : *
8588 : * @see GDALRasterBand::GetMaskFlags()
8589 : */
8590 :
8591 6651 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8592 :
8593 : {
8594 6651 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8595 :
8596 6651 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8597 6651 : return poBand->GetMaskFlags();
8598 : }
8599 :
8600 : /************************************************************************/
8601 : /* InvalidateMaskBand() */
8602 : /************************************************************************/
8603 :
8604 : //! @cond Doxygen_Suppress
8605 1611580 : void GDALRasterBand::InvalidateMaskBand()
8606 : {
8607 1611580 : poMask.reset();
8608 1611580 : nMaskFlags = 0;
8609 1611580 : }
8610 :
8611 : //! @endcond
8612 :
8613 : /************************************************************************/
8614 : /* CreateMaskBand() */
8615 : /************************************************************************/
8616 :
8617 : /**
8618 : * \brief Adds a mask band to the current band
8619 : *
8620 : * The default implementation of the CreateMaskBand() method is implemented
8621 : * based on similar rules to the .ovr handling implemented using the
8622 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8623 : * be created with the same basename as the original file, and it will have
8624 : * as many bands as the original image (or just one for GMF_PER_DATASET).
8625 : * The mask images will be deflate compressed tiled images with the same
8626 : * block size as the original image if possible.
8627 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8628 : * level, where xx matches the band number of a band of the main dataset. The
8629 : * value of those items will be the one of the nFlagsIn parameter.
8630 : *
8631 : * Note that if you got a mask band with a previous call to GetMaskBand(),
8632 : * it might be invalidated by CreateMaskBand(). So you have to call
8633 : * GetMaskBand() again.
8634 : *
8635 : * This method is the same as the C function GDALCreateMaskBand().
8636 : *
8637 : * @since GDAL 1.5.0
8638 : *
8639 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8640 : *
8641 : * @return CE_None on success or CE_Failure on an error.
8642 : *
8643 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8644 : * @see GDALDataset::CreateMaskBand()
8645 : *
8646 : */
8647 :
8648 9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8649 :
8650 : {
8651 9 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8652 : {
8653 9 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8654 9 : if (eErr != CE_None)
8655 1 : return eErr;
8656 :
8657 8 : InvalidateMaskBand();
8658 :
8659 8 : return CE_None;
8660 : }
8661 :
8662 0 : ReportError(CE_Failure, CPLE_NotSupported,
8663 : "CreateMaskBand() not supported for this band.");
8664 :
8665 0 : return CE_Failure;
8666 : }
8667 :
8668 : /************************************************************************/
8669 : /* GDALCreateMaskBand() */
8670 : /************************************************************************/
8671 :
8672 : /**
8673 : * \brief Adds a mask band to the current band
8674 : *
8675 : * @see GDALRasterBand::CreateMaskBand()
8676 : */
8677 :
8678 33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8679 :
8680 : {
8681 33 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8682 :
8683 33 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8684 33 : return poBand->CreateMaskBand(nFlags);
8685 : }
8686 :
8687 : /************************************************************************/
8688 : /* IsMaskBand() */
8689 : /************************************************************************/
8690 :
8691 : /**
8692 : * \brief Returns whether a band is a mask band.
8693 : *
8694 : * Mask band must be understood in the broad term: it can be a per-dataset
8695 : * mask band, an alpha band, or an implicit mask band.
8696 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8697 : *
8698 : * This method is the same as the C function GDALIsMaskBand().
8699 : *
8700 : * @return true if the band is a mask band.
8701 : *
8702 : * @see GDALDataset::CreateMaskBand()
8703 : *
8704 : * @since GDAL 3.5.0
8705 : *
8706 : */
8707 :
8708 439 : bool GDALRasterBand::IsMaskBand() const
8709 : {
8710 : // The GeoTIFF driver, among others, override this method to
8711 : // also handle external .msk bands.
8712 439 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8713 439 : GCI_AlphaBand;
8714 : }
8715 :
8716 : /************************************************************************/
8717 : /* GDALIsMaskBand() */
8718 : /************************************************************************/
8719 :
8720 : /**
8721 : * \brief Returns whether a band is a mask band.
8722 : *
8723 : * Mask band must be understood in the broad term: it can be a per-dataset
8724 : * mask band, an alpha band, or an implicit mask band.
8725 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8726 : *
8727 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8728 : *
8729 : * @return true if the band is a mask band.
8730 : *
8731 : * @see GDALRasterBand::IsMaskBand()
8732 : *
8733 : * @since GDAL 3.5.0
8734 : *
8735 : */
8736 :
8737 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
8738 :
8739 : {
8740 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8741 :
8742 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8743 37 : return poBand->IsMaskBand();
8744 : }
8745 :
8746 : /************************************************************************/
8747 : /* GetMaskValueRange() */
8748 : /************************************************************************/
8749 :
8750 : /**
8751 : * \brief Returns the range of values that a mask band can take.
8752 : *
8753 : * @return the range of values that a mask band can take.
8754 : *
8755 : * @since GDAL 3.5.0
8756 : *
8757 : */
8758 :
8759 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8760 : {
8761 0 : return GMVR_UNKNOWN;
8762 : }
8763 :
8764 : /************************************************************************/
8765 : /* GetIndexColorTranslationTo() */
8766 : /************************************************************************/
8767 :
8768 : /**
8769 : * \brief Compute translation table for color tables.
8770 : *
8771 : * When the raster band has a palette index, it may be useful to compute
8772 : * the "translation" of this palette to the palette of another band.
8773 : * The translation tries to do exact matching first, and then approximate
8774 : * matching if no exact matching is possible.
8775 : * This method returns a table such that table[i] = j where i is an index
8776 : * of the 'this' rasterband and j the corresponding index for the reference
8777 : * rasterband.
8778 : *
8779 : * This method is thought as internal to GDAL and is used for drivers
8780 : * like RPFTOC.
8781 : *
8782 : * The implementation only supports 1-byte palette rasterbands.
8783 : *
8784 : * @param poReferenceBand the raster band
8785 : * @param pTranslationTable an already allocated translation table (at least 256
8786 : * bytes), or NULL to let the method allocate it
8787 : * @param pApproximateMatching a pointer to a flag that is set if the matching
8788 : * is approximate. May be NULL.
8789 : *
8790 : * @return a translation table if the two bands are palette index and that they
8791 : * do not match or NULL in other cases. The table must be freed with CPLFree if
8792 : * NULL was passed for pTranslationTable.
8793 : */
8794 :
8795 : unsigned char *
8796 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8797 : unsigned char *pTranslationTable,
8798 : int *pApproximateMatching)
8799 : {
8800 4 : if (poReferenceBand == nullptr)
8801 0 : return nullptr;
8802 :
8803 : // cppcheck-suppress knownConditionTrueFalse
8804 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8805 : // cppcheck-suppress knownConditionTrueFalse
8806 4 : GetColorInterpretation() == GCI_PaletteIndex &&
8807 12 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
8808 4 : GetRasterDataType() == GDT_Byte)
8809 : {
8810 4 : const GDALColorTable *srcColorTable = GetColorTable();
8811 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8812 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
8813 : {
8814 4 : const int nEntries = srcColorTable->GetColorEntryCount();
8815 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
8816 :
8817 4 : int bHasNoDataValueSrc = FALSE;
8818 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8819 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8820 4 : dfNoDataValueSrc <= 255 &&
8821 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8822 0 : bHasNoDataValueSrc = FALSE;
8823 4 : const int noDataValueSrc =
8824 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8825 :
8826 4 : int bHasNoDataValueRef = FALSE;
8827 : const double dfNoDataValueRef =
8828 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8829 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8830 3 : dfNoDataValueRef <= 255 &&
8831 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8832 1 : bHasNoDataValueRef = FALSE;
8833 4 : const int noDataValueRef =
8834 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8835 :
8836 4 : bool samePalette = false;
8837 :
8838 4 : if (pApproximateMatching)
8839 3 : *pApproximateMatching = FALSE;
8840 :
8841 4 : if (nEntries == nRefEntries &&
8842 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
8843 3 : (bHasNoDataValueSrc == FALSE ||
8844 : noDataValueSrc == noDataValueRef))
8845 : {
8846 3 : samePalette = true;
8847 654 : for (int i = 0; i < nEntries; ++i)
8848 : {
8849 651 : if (noDataValueSrc == i)
8850 3 : continue;
8851 : const GDALColorEntry *entry =
8852 648 : srcColorTable->GetColorEntry(i);
8853 : const GDALColorEntry *entryRef =
8854 648 : destColorTable->GetColorEntry(i);
8855 648 : if (entry->c1 != entryRef->c1 ||
8856 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8857 : {
8858 0 : samePalette = false;
8859 : }
8860 : }
8861 : }
8862 :
8863 4 : if (!samePalette)
8864 : {
8865 1 : if (pTranslationTable == nullptr)
8866 : {
8867 : pTranslationTable = static_cast<unsigned char *>(
8868 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8869 1 : if (pTranslationTable == nullptr)
8870 1 : return nullptr;
8871 : }
8872 :
8873 : // Trying to remap the product palette on the subdataset
8874 : // palette.
8875 5 : for (int i = 0; i < nEntries; ++i)
8876 : {
8877 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8878 : noDataValueSrc == i)
8879 0 : continue;
8880 : const GDALColorEntry *entry =
8881 4 : srcColorTable->GetColorEntry(i);
8882 4 : bool bMatchFound = false;
8883 13 : for (int j = 0; j < nRefEntries; ++j)
8884 : {
8885 10 : if (bHasNoDataValueRef && noDataValueRef == j)
8886 0 : continue;
8887 : const GDALColorEntry *entryRef =
8888 10 : destColorTable->GetColorEntry(j);
8889 10 : if (entry->c1 == entryRef->c1 &&
8890 2 : entry->c2 == entryRef->c2 &&
8891 2 : entry->c3 == entryRef->c3)
8892 : {
8893 1 : pTranslationTable[i] =
8894 : static_cast<unsigned char>(j);
8895 1 : bMatchFound = true;
8896 1 : break;
8897 : }
8898 : }
8899 4 : if (!bMatchFound)
8900 : {
8901 : // No exact match. Looking for closest color now.
8902 3 : int best_j = 0;
8903 3 : int best_distance = 0;
8904 3 : if (pApproximateMatching)
8905 0 : *pApproximateMatching = TRUE;
8906 12 : for (int j = 0; j < nRefEntries; ++j)
8907 : {
8908 : const GDALColorEntry *entryRef =
8909 9 : destColorTable->GetColorEntry(j);
8910 9 : int distance = (entry->c1 - entryRef->c1) *
8911 9 : (entry->c1 - entryRef->c1) +
8912 9 : (entry->c2 - entryRef->c2) *
8913 9 : (entry->c2 - entryRef->c2) +
8914 9 : (entry->c3 - entryRef->c3) *
8915 9 : (entry->c3 - entryRef->c3);
8916 9 : if (j == 0 || distance < best_distance)
8917 : {
8918 7 : best_j = j;
8919 7 : best_distance = distance;
8920 : }
8921 : }
8922 3 : pTranslationTable[i] =
8923 : static_cast<unsigned char>(best_j);
8924 : }
8925 : }
8926 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
8927 0 : pTranslationTable[noDataValueSrc] =
8928 : static_cast<unsigned char>(noDataValueRef);
8929 :
8930 1 : return pTranslationTable;
8931 : }
8932 : }
8933 : }
8934 3 : return nullptr;
8935 : }
8936 :
8937 : /************************************************************************/
8938 : /* SetFlushBlockErr() */
8939 : /************************************************************************/
8940 :
8941 : /**
8942 : * \brief Store that an error occurred while writing a dirty block.
8943 : *
8944 : * This function stores the fact that an error occurred while writing a dirty
8945 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8946 : * flushed when the block cache get full, it is not convenient/possible to
8947 : * report that a dirty block could not be written correctly. This function
8948 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8949 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8950 : * places where the user can easily match the error with the relevant dataset.
8951 : */
8952 :
8953 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8954 : {
8955 0 : eFlushBlockErr = eErr;
8956 0 : }
8957 :
8958 : /************************************************************************/
8959 : /* IncDirtyBlocks() */
8960 : /************************************************************************/
8961 :
8962 : /**
8963 : * \brief Increment/decrement the number of dirty blocks
8964 : */
8965 :
8966 552608 : void GDALRasterBand::IncDirtyBlocks(int nInc)
8967 : {
8968 552608 : if (poBandBlockCache)
8969 552607 : poBandBlockCache->IncDirtyBlocks(nInc);
8970 552607 : }
8971 :
8972 : /************************************************************************/
8973 : /* ReportError() */
8974 : /************************************************************************/
8975 :
8976 : #ifndef DOXYGEN_XML
8977 : /**
8978 : * \brief Emits an error related to a raster band.
8979 : *
8980 : * This function is a wrapper for regular CPLError(). The only difference
8981 : * with CPLError() is that it prepends the error message with the dataset
8982 : * name and the band number.
8983 : *
8984 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
8985 : * @param err_no the error number (CPLE_*) from cpl_error.h.
8986 : * @param fmt a printf() style format string. Any additional arguments
8987 : * will be treated as arguments to fill in this format in a manner
8988 : * similar to printf().
8989 : *
8990 : * @since GDAL 1.9.0
8991 : */
8992 :
8993 2459 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
8994 : const char *fmt, ...) const
8995 : {
8996 : va_list args;
8997 :
8998 2459 : va_start(args, fmt);
8999 :
9000 2459 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
9001 2459 : pszDSName = CPLGetFilename(pszDSName);
9002 2459 : if (pszDSName[0] != '\0')
9003 : {
9004 2394 : CPLError(eErrClass, err_no, "%s",
9005 4788 : CPLString()
9006 2394 : .Printf("%s, band %d: ", pszDSName, GetBand())
9007 4788 : .append(CPLString().vPrintf(fmt, args))
9008 : .c_str());
9009 : }
9010 : else
9011 : {
9012 65 : CPLErrorV(eErrClass, err_no, fmt, args);
9013 : }
9014 :
9015 2459 : va_end(args);
9016 2459 : }
9017 : #endif
9018 :
9019 : /************************************************************************/
9020 : /* GetVirtualMemAuto() */
9021 : /************************************************************************/
9022 :
9023 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9024 : *
9025 : * Only supported on Linux and Unix systems with mmap() for now.
9026 : *
9027 : * This method allows creating a virtual memory object for a GDALRasterBand,
9028 : * that exposes the whole image data as a virtual array.
9029 : *
9030 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9031 : * specialized implementation, such as for raw files, may also directly use
9032 : * mechanisms of the operating system to create a view of the underlying file
9033 : * into virtual memory ( CPLVirtualMemFileMapNew() )
9034 : *
9035 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9036 : * offer a specialized implementation with direct file mapping, provided that
9037 : * some requirements are met :
9038 : * - for all drivers, the dataset must be backed by a "real" file in the file
9039 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9040 : * must match the native ordering of the CPU.
9041 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9042 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9043 : * the file in sequential order, and be equally spaced (which is generally the
9044 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9045 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9046 : *
9047 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
9048 : * CPLVirtualMemFree() must be called before the raster band object is
9049 : * destroyed.
9050 : *
9051 : * If p is such a pointer and base_type the type matching
9052 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9053 : * accessed with
9054 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9055 : *
9056 : * This method is the same as the C GDALGetVirtualMemAuto() function.
9057 : *
9058 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9059 : * read/write the band.
9060 : *
9061 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
9062 : * one pixel value in the buffer to the start of the next pixel value within a
9063 : * scanline.
9064 : *
9065 : * @param pnLineSpace Output parameter giving the byte offset from the start of
9066 : * one scanline in the buffer to the start of the next.
9067 : *
9068 : * @param papszOptions NULL terminated list of options.
9069 : * If a specialized implementation exists, defining
9070 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9071 : * used. On the contrary, starting with GDAL 2.2, defining
9072 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9073 : * being used (thus only allowing efficient implementations to be used). When
9074 : * requiring or falling back to the default implementation, the following
9075 : * options are available : CACHE_SIZE (in bytes, defaults to
9076 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9077 : * to FALSE)
9078 : *
9079 : * @return a virtual memory object that must be unreferenced by
9080 : * CPLVirtualMemFree(), or NULL in case of failure.
9081 : *
9082 : * @since GDAL 1.11
9083 : */
9084 :
9085 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9086 : int *pnPixelSpace,
9087 : GIntBig *pnLineSpace,
9088 : char **papszOptions)
9089 : {
9090 9 : const char *pszImpl = CSLFetchNameValueDef(
9091 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9092 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9093 8 : EQUAL(pszImpl, "FALSE"))
9094 : {
9095 1 : return nullptr;
9096 : }
9097 :
9098 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9099 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9100 8 : if (pnPixelSpace)
9101 8 : *pnPixelSpace = nPixelSpace;
9102 8 : if (pnLineSpace)
9103 8 : *pnLineSpace = nLineSpace;
9104 : const size_t nCacheSize =
9105 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9106 : const size_t nPageSizeHint =
9107 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9108 8 : const bool bSingleThreadUsage = CPLTestBool(
9109 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9110 8 : return GDALRasterBandGetVirtualMem(
9111 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9112 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9113 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9114 8 : papszOptions);
9115 : }
9116 :
9117 : /************************************************************************/
9118 : /* GDALGetVirtualMemAuto() */
9119 : /************************************************************************/
9120 :
9121 : /**
9122 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9123 : *
9124 : * @see GDALRasterBand::GetVirtualMemAuto()
9125 : */
9126 :
9127 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9128 : int *pnPixelSpace, GIntBig *pnLineSpace,
9129 : CSLConstList papszOptions)
9130 : {
9131 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9132 :
9133 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9134 :
9135 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9136 31 : const_cast<char **>(papszOptions));
9137 : }
9138 :
9139 : /************************************************************************/
9140 : /* GDALGetDataCoverageStatus() */
9141 : /************************************************************************/
9142 :
9143 : /**
9144 : * \brief Get the coverage status of a sub-window of the raster.
9145 : *
9146 : * Returns whether a sub-window of the raster contains only data, only empty
9147 : * blocks or a mix of both. This function can be used to determine quickly
9148 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9149 : * be sparse.
9150 : *
9151 : * Empty blocks are blocks that are generally not physically present in the
9152 : * file, and when read through GDAL, contain only pixels whose value is the
9153 : * nodata value when it is set, or whose value is 0 when the nodata value is
9154 : * not set.
9155 : *
9156 : * The query is done in an efficient way without reading the actual pixel
9157 : * values. If not possible, or not implemented at all by the driver,
9158 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9159 : * be returned.
9160 : *
9161 : * The values that can be returned by the function are the following,
9162 : * potentially combined with the binary or operator :
9163 : * <ul>
9164 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9165 : * GetDataCoverageStatus(). This flag should be returned together with
9166 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9167 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9168 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9169 : * the queried window. This is typically identified by the concept of missing
9170 : * block in formats that supports it.
9171 : * </li>
9172 : * </ul>
9173 : *
9174 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9175 : * should be interpreted more as hint of potential presence of data. For example
9176 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9177 : * nodata value), instead of using the missing block mechanism,
9178 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9179 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9180 : *
9181 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9182 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9183 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9184 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9185 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9186 : * the function will exit, so that you can potentially refine the requested area
9187 : * to find which particular region(s) have missing blocks.
9188 : *
9189 : * @see GDALRasterBand::GetDataCoverageStatus()
9190 : *
9191 : * @param hBand raster band
9192 : *
9193 : * @param nXOff The pixel offset to the top left corner of the region
9194 : * of the band to be queried. This would be zero to start from the left side.
9195 : *
9196 : * @param nYOff The line offset to the top left corner of the region
9197 : * of the band to be queried. This would be zero to start from the top.
9198 : *
9199 : * @param nXSize The width of the region of the band to be queried in pixels.
9200 : *
9201 : * @param nYSize The height of the region of the band to be queried in lines.
9202 : *
9203 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9204 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9205 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9206 : * as the computation of the coverage matches the mask, the computation will be
9207 : * stopped. *pdfDataPct will not be valid in that case.
9208 : *
9209 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9210 : * to the (approximate) percentage in [0,100] of pixels in the queried
9211 : * sub-window that have valid values. The implementation might not always be
9212 : * able to compute it, in which case it will be set to a negative value.
9213 : *
9214 : * @return a binary-or'ed combination of possible values
9215 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9216 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9217 : *
9218 : * @note Added in GDAL 2.2
9219 : */
9220 :
9221 26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
9222 : int nYOff, int nXSize, int nYSize,
9223 : int nMaskFlagStop, double *pdfDataPct)
9224 : {
9225 26 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
9226 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
9227 :
9228 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9229 :
9230 26 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
9231 26 : nMaskFlagStop, pdfDataPct);
9232 : }
9233 :
9234 : /************************************************************************/
9235 : /* GetDataCoverageStatus() */
9236 : /************************************************************************/
9237 :
9238 : /**
9239 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
9240 : * int nYOff,
9241 : * int nXSize,
9242 : * int nYSize,
9243 : * int nMaskFlagStop,
9244 : * double* pdfDataPct)
9245 : * \brief Get the coverage status of a sub-window of the raster.
9246 : *
9247 : * Returns whether a sub-window of the raster contains only data, only empty
9248 : * blocks or a mix of both. This function can be used to determine quickly
9249 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9250 : * be sparse.
9251 : *
9252 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9253 : * value when it is set, or whose value is 0 when the nodata value is not set.
9254 : *
9255 : * The query is done in an efficient way without reading the actual pixel
9256 : * values. If not possible, or not implemented at all by the driver,
9257 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9258 : * be returned.
9259 : *
9260 : * The values that can be returned by the function are the following,
9261 : * potentially combined with the binary or operator :
9262 : * <ul>
9263 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9264 : * GetDataCoverageStatus(). This flag should be returned together with
9265 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9266 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9267 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9268 : * the queried window. This is typically identified by the concept of missing
9269 : * block in formats that supports it.
9270 : * </li>
9271 : * </ul>
9272 : *
9273 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9274 : * should be interpreted more as hint of potential presence of data. For example
9275 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9276 : * nodata value), instead of using the missing block mechanism,
9277 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9278 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9279 : *
9280 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9281 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9282 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9283 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9284 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9285 : * the function will exit, so that you can potentially refine the requested area
9286 : * to find which particular region(s) have missing blocks.
9287 : *
9288 : * @see GDALGetDataCoverageStatus()
9289 : *
9290 : * @param nXOff The pixel offset to the top left corner of the region
9291 : * of the band to be queried. This would be zero to start from the left side.
9292 : *
9293 : * @param nYOff The line offset to the top left corner of the region
9294 : * of the band to be queried. This would be zero to start from the top.
9295 : *
9296 : * @param nXSize The width of the region of the band to be queried in pixels.
9297 : *
9298 : * @param nYSize The height of the region of the band to be queried in lines.
9299 : *
9300 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9301 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9302 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9303 : * as the computation of the coverage matches the mask, the computation will be
9304 : * stopped. *pdfDataPct will not be valid in that case.
9305 : *
9306 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9307 : * to the (approximate) percentage in [0,100] of pixels in the queried
9308 : * sub-window that have valid values. The implementation might not always be
9309 : * able to compute it, in which case it will be set to a negative value.
9310 : *
9311 : * @return a binary-or'ed combination of possible values
9312 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9313 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9314 : *
9315 : * @note Added in GDAL 2.2
9316 : */
9317 :
9318 : /**
9319 : * \brief Get the coverage status of a sub-window of the raster.
9320 : *
9321 : * Returns whether a sub-window of the raster contains only data, only empty
9322 : * blocks or a mix of both. This function can be used to determine quickly
9323 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9324 : * be sparse.
9325 : *
9326 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9327 : * value when it is set, or whose value is 0 when the nodata value is not set.
9328 : *
9329 : * The query is done in an efficient way without reading the actual pixel
9330 : * values. If not possible, or not implemented at all by the driver,
9331 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9332 : * be returned.
9333 : *
9334 : * The values that can be returned by the function are the following,
9335 : * potentially combined with the binary or operator :
9336 : * <ul>
9337 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9338 : * GetDataCoverageStatus(). This flag should be returned together with
9339 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9340 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9341 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9342 : * the queried window. This is typically identified by the concept of missing
9343 : * block in formats that supports it.
9344 : * </li>
9345 : * </ul>
9346 : *
9347 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9348 : * should be interpreted more as hint of potential presence of data. For example
9349 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9350 : * nodata value), instead of using the missing block mechanism,
9351 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9352 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9353 : *
9354 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9355 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9356 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9357 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9358 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9359 : * the function will exit, so that you can potentially refine the requested area
9360 : * to find which particular region(s) have missing blocks.
9361 : *
9362 : * @see GDALGetDataCoverageStatus()
9363 : *
9364 : * @param nXOff The pixel offset to the top left corner of the region
9365 : * of the band to be queried. This would be zero to start from the left side.
9366 : *
9367 : * @param nYOff The line offset to the top left corner of the region
9368 : * of the band to be queried. This would be zero to start from the top.
9369 : *
9370 : * @param nXSize The width of the region of the band to be queried in pixels.
9371 : *
9372 : * @param nYSize The height of the region of the band to be queried in lines.
9373 : *
9374 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9375 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9376 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9377 : * as the computation of the coverage matches the mask, the computation will be
9378 : * stopped. *pdfDataPct will not be valid in that case.
9379 : *
9380 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9381 : * to the (approximate) percentage in [0,100] of pixels in the queried
9382 : * sub-window that have valid values. The implementation might not always be
9383 : * able to compute it, in which case it will be set to a negative value.
9384 : *
9385 : * @return a binary-or'ed combination of possible values
9386 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9387 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9388 : *
9389 : * @note Added in GDAL 2.2
9390 : */
9391 :
9392 4603 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9393 : int nYSize, int nMaskFlagStop,
9394 : double *pdfDataPct)
9395 : {
9396 4603 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9397 4603 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9398 4603 : nYOff + nYSize > nRasterYSize)
9399 : {
9400 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9401 0 : if (pdfDataPct)
9402 0 : *pdfDataPct = 0.0;
9403 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9404 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
9405 : }
9406 4603 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9407 4603 : pdfDataPct);
9408 : }
9409 :
9410 : /************************************************************************/
9411 : /* IGetDataCoverageStatus() */
9412 : /************************************************************************/
9413 :
9414 683 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9415 : int /*nXSize*/, int /*nYSize*/,
9416 : int /*nMaskFlagStop*/,
9417 : double *pdfDataPct)
9418 : {
9419 683 : if (pdfDataPct != nullptr)
9420 0 : *pdfDataPct = 100.0;
9421 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9422 683 : GDAL_DATA_COVERAGE_STATUS_DATA;
9423 : }
9424 :
9425 : //! @cond Doxygen_Suppress
9426 : /************************************************************************/
9427 : /* EnterReadWrite() */
9428 : /************************************************************************/
9429 :
9430 7481830 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9431 : {
9432 7481830 : if (poDS != nullptr)
9433 6722650 : return poDS->EnterReadWrite(eRWFlag);
9434 759186 : return FALSE;
9435 : }
9436 :
9437 : /************************************************************************/
9438 : /* LeaveReadWrite() */
9439 : /************************************************************************/
9440 :
9441 1028260 : void GDALRasterBand::LeaveReadWrite()
9442 : {
9443 1028260 : if (poDS != nullptr)
9444 1028240 : poDS->LeaveReadWrite();
9445 1028230 : }
9446 :
9447 : /************************************************************************/
9448 : /* InitRWLock() */
9449 : /************************************************************************/
9450 :
9451 3856150 : void GDALRasterBand::InitRWLock()
9452 : {
9453 3856150 : if (poDS != nullptr)
9454 3855750 : poDS->InitRWLock();
9455 3856150 : }
9456 :
9457 : //! @endcond
9458 :
9459 : // clang-format off
9460 :
9461 : /**
9462 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9463 : * \brief Set metadata.
9464 : *
9465 : * CAUTION: depending on the format, older values of the updated information
9466 : * might still be found in the file in a "ghost" state, even if no longer
9467 : * accessible through the GDAL API. This is for example the case of the GTiff
9468 : * format (this is not a exhaustive list)
9469 : *
9470 : * The C function GDALSetMetadata() does the same thing as this method.
9471 : *
9472 : * @param papszMetadata the metadata in name=value string list format to
9473 : * apply.
9474 : * @param pszDomain the domain of interest. Use "" or NULL for the default
9475 : * domain.
9476 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9477 : * metadata has been accepted, but is likely not maintained persistently
9478 : * by the underlying object between sessions.
9479 : */
9480 :
9481 : /**
9482 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9483 : * \brief Set single metadata item.
9484 : *
9485 : * CAUTION: depending on the format, older values of the updated information
9486 : * might still be found in the file in a "ghost" state, even if no longer
9487 : * accessible through the GDAL API. This is for example the case of the GTiff
9488 : * format (this is not a exhaustive list)
9489 : *
9490 : * The C function GDALSetMetadataItem() does the same thing as this method.
9491 : *
9492 : * @param pszName the key for the metadata item to fetch.
9493 : * @param pszValue the value to assign to the key.
9494 : * @param pszDomain the domain to set within, use NULL for the default domain.
9495 : *
9496 : * @return CE_None on success, or an error code on failure.
9497 : */
9498 :
9499 : // clang-format on
9500 :
9501 : //! @cond Doxygen_Suppress
9502 : /************************************************************************/
9503 : /* EnablePixelTypeSignedByteWarning() */
9504 : /************************************************************************/
9505 :
9506 155554 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9507 : {
9508 155554 : m_bEnablePixelTypeSignedByteWarning = b;
9509 155554 : }
9510 :
9511 4866 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9512 : {
9513 4866 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9514 4866 : }
9515 :
9516 : //! @endcond
9517 :
9518 : /************************************************************************/
9519 : /* GetMetadataItem() */
9520 : /************************************************************************/
9521 :
9522 387111 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9523 : const char *pszDomain)
9524 : {
9525 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9526 387111 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9527 296602 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9528 287615 : EQUAL(pszName, "PIXELTYPE"))
9529 : {
9530 2 : CPLError(CE_Warning, CPLE_AppDefined,
9531 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9532 : "used to signal signed 8-bit raster. Change your code to "
9533 : "test for the new GDT_Int8 data type instead.");
9534 : }
9535 387111 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9536 : }
9537 :
9538 : /************************************************************************/
9539 : /* GDALMDArrayFromRasterBand */
9540 : /************************************************************************/
9541 :
9542 : class GDALMDArrayFromRasterBand final : public GDALMDArray
9543 : {
9544 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9545 :
9546 : GDALDataset *m_poDS;
9547 : GDALRasterBand *m_poBand;
9548 : GDALExtendedDataType m_dt;
9549 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9550 : std::string m_osUnit;
9551 : std::vector<GByte> m_pabyNoData{};
9552 : std::shared_ptr<GDALMDArray> m_varX{};
9553 : std::shared_ptr<GDALMDArray> m_varY{};
9554 : std::string m_osFilename{};
9555 :
9556 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9557 : const size_t *count, const GInt64 *arrayStep,
9558 : const GPtrDiff_t *bufferStride,
9559 : const GDALExtendedDataType &bufferDataType,
9560 : void *pBuffer) const;
9561 :
9562 : protected:
9563 23 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9564 46 : : GDALAbstractMDArray(std::string(),
9565 46 : std::string(poDS->GetDescription()) +
9566 : CPLSPrintf(" band %d", poBand->GetBand())),
9567 46 : GDALMDArray(std::string(),
9568 46 : std::string(poDS->GetDescription()) +
9569 : CPLSPrintf(" band %d", poBand->GetBand())),
9570 : m_poDS(poDS), m_poBand(poBand),
9571 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9572 115 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9573 : {
9574 23 : m_poDS->Reference();
9575 :
9576 23 : int bHasNoData = false;
9577 23 : if (m_poBand->GetRasterDataType() == GDT_Int64)
9578 : {
9579 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9580 0 : if (bHasNoData)
9581 : {
9582 0 : m_pabyNoData.resize(m_dt.GetSize());
9583 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9584 : m_dt.GetNumericDataType(), 0, 1);
9585 : }
9586 : }
9587 23 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9588 : {
9589 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9590 0 : if (bHasNoData)
9591 : {
9592 0 : m_pabyNoData.resize(m_dt.GetSize());
9593 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9594 : m_dt.GetNumericDataType(), 0, 1);
9595 : }
9596 : }
9597 : else
9598 : {
9599 23 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9600 23 : if (bHasNoData)
9601 : {
9602 1 : m_pabyNoData.resize(m_dt.GetSize());
9603 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9604 : m_dt.GetNumericDataType(), 0, 1);
9605 : }
9606 : }
9607 :
9608 23 : const int nXSize = poBand->GetXSize();
9609 23 : const int nYSize = poBand->GetYSize();
9610 :
9611 23 : auto poSRS = m_poDS->GetSpatialRef();
9612 46 : std::string osTypeY;
9613 46 : std::string osTypeX;
9614 46 : std::string osDirectionY;
9615 46 : std::string osDirectionX;
9616 23 : if (poSRS && poSRS->GetAxesCount() == 2)
9617 : {
9618 21 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9619 21 : OGRAxisOrientation eOrientation1 = OAO_Other;
9620 21 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
9621 21 : OGRAxisOrientation eOrientation2 = OAO_Other;
9622 21 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
9623 21 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9624 : {
9625 5 : if (mapping == std::vector<int>{1, 2})
9626 : {
9627 5 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9628 5 : osDirectionY = "NORTH";
9629 5 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9630 5 : osDirectionX = "EAST";
9631 : }
9632 : }
9633 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9634 : {
9635 16 : if (mapping == std::vector<int>{2, 1})
9636 : {
9637 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9638 16 : osDirectionY = "NORTH";
9639 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9640 16 : osDirectionX = "EAST";
9641 : }
9642 : }
9643 : }
9644 :
9645 115 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9646 : "/", "Y", osTypeY, osDirectionY, nYSize),
9647 46 : std::make_shared<GDALDimensionWeakIndexingVar>(
9648 69 : "/", "X", osTypeX, osDirectionX, nXSize)};
9649 :
9650 : double adfGeoTransform[6];
9651 23 : if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
9652 23 : adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
9653 : {
9654 44 : m_varX = GDALMDArrayRegularlySpaced::Create(
9655 22 : "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
9656 22 : 0.5);
9657 22 : m_dims[1]->SetIndexingVariable(m_varX);
9658 :
9659 44 : m_varY = GDALMDArrayRegularlySpaced::Create(
9660 22 : "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
9661 22 : 0.5);
9662 22 : m_dims[0]->SetIndexingVariable(m_varY);
9663 : }
9664 23 : }
9665 :
9666 31 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9667 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9668 : const GDALExtendedDataType &bufferDataType,
9669 : void *pDstBuffer) const override
9670 : {
9671 31 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9672 31 : bufferDataType, pDstBuffer);
9673 : }
9674 :
9675 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9676 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9677 : const GDALExtendedDataType &bufferDataType,
9678 : const void *pSrcBuffer) override
9679 : {
9680 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9681 : bufferStride, bufferDataType,
9682 1 : const_cast<void *>(pSrcBuffer));
9683 : }
9684 :
9685 : public:
9686 46 : ~GDALMDArrayFromRasterBand()
9687 23 : {
9688 23 : m_poDS->ReleaseRef();
9689 46 : }
9690 :
9691 23 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9692 : GDALRasterBand *poBand)
9693 : {
9694 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9695 46 : new GDALMDArrayFromRasterBand(poDS, poBand)));
9696 23 : array->SetSelf(array);
9697 46 : return array;
9698 : }
9699 :
9700 2 : bool IsWritable() const override
9701 : {
9702 2 : return m_poDS->GetAccess() == GA_Update;
9703 : }
9704 :
9705 97 : const std::string &GetFilename() const override
9706 : {
9707 97 : return m_osFilename;
9708 : }
9709 :
9710 : const std::vector<std::shared_ptr<GDALDimension>> &
9711 299 : GetDimensions() const override
9712 : {
9713 299 : return m_dims;
9714 : }
9715 :
9716 138 : const GDALExtendedDataType &GetDataType() const override
9717 : {
9718 138 : return m_dt;
9719 : }
9720 :
9721 3 : const std::string &GetUnit() const override
9722 : {
9723 3 : return m_osUnit;
9724 : }
9725 :
9726 29 : const void *GetRawNoDataValue() const override
9727 : {
9728 29 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9729 : }
9730 :
9731 2 : double GetOffset(bool *pbHasOffset,
9732 : GDALDataType *peStorageType) const override
9733 : {
9734 2 : int bHasOffset = false;
9735 2 : double dfRes = m_poBand->GetOffset(&bHasOffset);
9736 2 : if (pbHasOffset)
9737 2 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9738 2 : if (peStorageType)
9739 1 : *peStorageType = GDT_Unknown;
9740 2 : return dfRes;
9741 : }
9742 :
9743 2 : double GetScale(bool *pbHasScale,
9744 : GDALDataType *peStorageType) const override
9745 : {
9746 2 : int bHasScale = false;
9747 2 : double dfRes = m_poBand->GetScale(&bHasScale);
9748 2 : if (pbHasScale)
9749 2 : *pbHasScale = CPL_TO_BOOL(bHasScale);
9750 2 : if (peStorageType)
9751 1 : *peStorageType = GDT_Unknown;
9752 2 : return dfRes;
9753 : }
9754 :
9755 84 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9756 : {
9757 84 : auto poSrcSRS = m_poDS->GetSpatialRef();
9758 84 : if (!poSrcSRS)
9759 2 : return nullptr;
9760 164 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9761 :
9762 164 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9763 82 : constexpr int iYDim = 0;
9764 82 : constexpr int iXDim = 1;
9765 246 : for (auto &m : axisMapping)
9766 : {
9767 164 : if (m == 1)
9768 82 : m = iXDim + 1;
9769 82 : else if (m == 2)
9770 82 : m = iYDim + 1;
9771 : else
9772 0 : m = 0;
9773 : }
9774 82 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9775 82 : return poSRS;
9776 : }
9777 :
9778 29 : std::vector<GUInt64> GetBlockSize() const override
9779 : {
9780 29 : int nBlockXSize = 0;
9781 29 : int nBlockYSize = 0;
9782 29 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9783 29 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9784 29 : static_cast<GUInt64>(nBlockXSize)};
9785 : }
9786 :
9787 : class MDIAsAttribute : public GDALAttribute
9788 : {
9789 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9790 : const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
9791 : std::string m_osValue;
9792 :
9793 : public:
9794 2 : MDIAsAttribute(const std::string &name, const std::string &value)
9795 2 : : GDALAbstractMDArray(std::string(), name),
9796 4 : GDALAttribute(std::string(), name), m_osValue(value)
9797 : {
9798 2 : }
9799 :
9800 : const std::vector<std::shared_ptr<GDALDimension>> &
9801 3 : GetDimensions() const override
9802 : {
9803 3 : return m_dims;
9804 : }
9805 :
9806 2 : const GDALExtendedDataType &GetDataType() const override
9807 : {
9808 2 : return m_dt;
9809 : }
9810 :
9811 1 : bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
9812 : const GPtrDiff_t *,
9813 : const GDALExtendedDataType &bufferDataType,
9814 : void *pDstBuffer) const override
9815 : {
9816 1 : const char *pszStr = m_osValue.c_str();
9817 1 : GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
9818 : bufferDataType);
9819 1 : return true;
9820 : }
9821 : };
9822 :
9823 : std::vector<std::shared_ptr<GDALAttribute>>
9824 14 : GetAttributes(CSLConstList) const override
9825 : {
9826 14 : std::vector<std::shared_ptr<GDALAttribute>> res;
9827 14 : auto papszMD = m_poBand->GetMetadata();
9828 16 : for (auto iter = papszMD; iter && iter[0]; ++iter)
9829 : {
9830 2 : char *pszKey = nullptr;
9831 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9832 2 : if (pszKey && pszValue)
9833 : {
9834 : res.emplace_back(
9835 2 : std::make_shared<MDIAsAttribute>(pszKey, pszValue));
9836 : }
9837 2 : CPLFree(pszKey);
9838 : }
9839 14 : return res;
9840 : }
9841 : };
9842 :
9843 : /************************************************************************/
9844 : /* ReadWrite() */
9845 : /************************************************************************/
9846 :
9847 32 : bool GDALMDArrayFromRasterBand::ReadWrite(
9848 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
9849 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9850 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
9851 : {
9852 32 : constexpr size_t iDimX = 1;
9853 32 : constexpr size_t iDimY = 0;
9854 32 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
9855 : arrayStartIdx, count, arrayStep, bufferStride,
9856 32 : bufferDataType, pBuffer);
9857 : }
9858 :
9859 : /************************************************************************/
9860 : /* GDALMDRasterIOFromBand() */
9861 : /************************************************************************/
9862 :
9863 65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
9864 : size_t iDimX, size_t iDimY,
9865 : const GUInt64 *arrayStartIdx, const size_t *count,
9866 : const GInt64 *arrayStep,
9867 : const GPtrDiff_t *bufferStride,
9868 : const GDALExtendedDataType &bufferDataType,
9869 : void *pBuffer)
9870 : {
9871 65 : const auto eDT(bufferDataType.GetNumericDataType());
9872 65 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
9873 65 : const int nX =
9874 65 : arrayStep[iDimX] > 0
9875 65 : ? static_cast<int>(arrayStartIdx[iDimX])
9876 2 : : static_cast<int>(arrayStartIdx[iDimX] -
9877 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
9878 65 : const int nY =
9879 65 : arrayStep[iDimY] > 0
9880 65 : ? static_cast<int>(arrayStartIdx[iDimY])
9881 2 : : static_cast<int>(arrayStartIdx[iDimY] -
9882 2 : (count[iDimY] - 1) * -arrayStep[iDimY]);
9883 65 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
9884 65 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
9885 65 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
9886 65 : int nStrideXSign = 1;
9887 65 : if (arrayStep[iDimX] < 0)
9888 : {
9889 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
9890 2 : nStrideXSign = -1;
9891 : }
9892 65 : int nStrideYSign = 1;
9893 65 : if (arrayStep[iDimY] < 0)
9894 : {
9895 2 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
9896 2 : nStrideYSign = -1;
9897 : }
9898 :
9899 130 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
9900 65 : static_cast<int>(count[iDimX]),
9901 65 : static_cast<int>(count[iDimY]), eDT,
9902 : static_cast<GSpacing>(
9903 65 : nStrideXSign * bufferStride[iDimX] * nDTSize),
9904 : static_cast<GSpacing>(
9905 65 : nStrideYSign * bufferStride[iDimY] * nDTSize),
9906 65 : nullptr) == CE_None;
9907 : }
9908 :
9909 : /************************************************************************/
9910 : /* AsMDArray() */
9911 : /************************************************************************/
9912 :
9913 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
9914 : *
9915 : * The band must be linked to a GDALDataset. If this dataset is not already
9916 : * marked as shared, it will be, so that the returned array holds a reference
9917 : * to it.
9918 : *
9919 : * If the dataset has a geotransform attached, the X and Y dimensions of the
9920 : * returned array will have an associated indexing variable.
9921 : *
9922 : * This is the same as the C function GDALRasterBandAsMDArray().
9923 : *
9924 : * The "reverse" method is GDALMDArray::AsClassicDataset().
9925 : *
9926 : * @return a new array, or nullptr.
9927 : *
9928 : * @since GDAL 3.1
9929 : */
9930 23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
9931 : {
9932 23 : if (!poDS)
9933 : {
9934 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
9935 0 : return nullptr;
9936 : }
9937 23 : if (!poDS->GetShared())
9938 : {
9939 23 : poDS->MarkAsShared();
9940 : }
9941 : return GDALMDArrayFromRasterBand::Create(
9942 23 : poDS, const_cast<GDALRasterBand *>(this));
9943 : }
9944 :
9945 : /************************************************************************/
9946 : /* InterpolateAtPoint() */
9947 : /************************************************************************/
9948 :
9949 : /**
9950 : * \brief Interpolates the value between pixels using a resampling algorithm,
9951 : * taking pixel/line coordinates as input.
9952 : *
9953 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
9954 : * @param dfLine line coordinate as a double, where interpolation should be done.
9955 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
9956 : * @param pdfRealValue pointer to real part of interpolated value
9957 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
9958 : *
9959 : * @return CE_None on success, or an error code on failure.
9960 : * @since GDAL 3.10
9961 : */
9962 :
9963 153 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
9964 : GDALRIOResampleAlg eInterpolation,
9965 : double *pdfRealValue,
9966 : double *pdfImagValue) const
9967 : {
9968 153 : if (eInterpolation != GRIORA_NearestNeighbour &&
9969 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
9970 : eInterpolation != GRIORA_CubicSpline)
9971 : {
9972 2 : CPLError(CE_Failure, CPLE_AppDefined,
9973 : "Only nearest, bilinear, cubic and cubicspline interpolation "
9974 : "methods "
9975 : "allowed");
9976 :
9977 2 : return CE_Failure;
9978 : }
9979 :
9980 151 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
9981 151 : if (!m_poPointsCache)
9982 71 : m_poPointsCache = new GDALDoublePointsCache();
9983 :
9984 : const bool res =
9985 151 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
9986 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
9987 :
9988 151 : return res ? CE_None : CE_Failure;
9989 : }
9990 :
9991 : /************************************************************************/
9992 : /* GDALRasterInterpolateAtPoint() */
9993 : /************************************************************************/
9994 :
9995 : /**
9996 : * \brief Interpolates the value between pixels using
9997 : * a resampling algorithm
9998 : *
9999 : * @see GDALRasterBand::InterpolateAtPoint()
10000 : * @since GDAL 3.10
10001 : */
10002 :
10003 130 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10004 : double dfLine,
10005 : GDALRIOResampleAlg eInterpolation,
10006 : double *pdfRealValue, double *pdfImagValue)
10007 : {
10008 130 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10009 :
10010 130 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10011 130 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10012 130 : pdfRealValue, pdfImagValue);
10013 : }
10014 :
10015 : /************************************************************************/
10016 : /* InterpolateAtGeolocation() */
10017 : /************************************************************************/
10018 :
10019 : /**
10020 : * \brief Interpolates the value between pixels using a resampling algorithm,
10021 : * taking georeferenced coordinates as input.
10022 : *
10023 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
10024 : * must be in the "natural" SRS of the dataset, that is the one returned by
10025 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
10026 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
10027 : * array (generally WGS 84) if there is a geolocation array.
10028 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10029 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10030 : * be a easting, and dfGeolocY a northing.
10031 : *
10032 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10033 : * expressed in that CRS, and that tuple must be conformant with the
10034 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10035 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10036 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10037 : * before calling this method, and in that case, dfGeolocX must be a longitude
10038 : * or an easting value, and dfGeolocX a latitude or a northing value.
10039 : *
10040 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
10041 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
10042 : * it for details on how that transformation is done.
10043 : *
10044 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
10045 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10046 : * where interpolation should be done.
10047 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
10048 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10049 : * where interpolation should be done.
10050 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
10051 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10052 : * @param pdfRealValue pointer to real part of interpolated value
10053 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10054 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
10055 : *
10056 : * @return CE_None on success, or an error code on failure.
10057 : * @since GDAL 3.11
10058 : */
10059 :
10060 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
10061 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
10062 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
10063 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
10064 : {
10065 : double dfPixel;
10066 : double dfLine;
10067 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
10068 : &dfLine,
10069 15 : papszTransformerOptions) != CE_None)
10070 : {
10071 1 : return CE_Failure;
10072 : }
10073 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
10074 14 : pdfImagValue);
10075 : }
10076 :
10077 : /************************************************************************/
10078 : /* GDALRasterInterpolateAtGeolocation() */
10079 : /************************************************************************/
10080 :
10081 : /**
10082 : * \brief Interpolates the value between pixels using a resampling algorithm,
10083 : * taking georeferenced coordinates as input.
10084 : *
10085 : * @see GDALRasterBand::InterpolateAtGeolocation()
10086 : * @since GDAL 3.11
10087 : */
10088 :
10089 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
10090 : double dfGeolocX, double dfGeolocY,
10091 : OGRSpatialReferenceH hSRS,
10092 : GDALRIOResampleAlg eInterpolation,
10093 : double *pdfRealValue,
10094 : double *pdfImagValue,
10095 : CSLConstList papszTransformerOptions)
10096 : {
10097 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
10098 :
10099 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10100 15 : return poBand->InterpolateAtGeolocation(
10101 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
10102 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
10103 : }
|