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 "cpl_float.h"
17 : #include "gdal_priv.h"
18 :
19 : #include <cassert>
20 : #include <climits>
21 : #include <cmath>
22 : #include <cstdarg>
23 : #include <cstddef>
24 : #include <cstdio>
25 : #include <cstdlib>
26 : #include <cstring>
27 : #include <algorithm>
28 : #include <limits>
29 : #include <memory>
30 : #include <new>
31 : #include <type_traits>
32 :
33 : #include "cpl_conv.h"
34 : #include "cpl_error.h"
35 : #include "cpl_float.h"
36 : #include "cpl_progress.h"
37 : #include "cpl_string.h"
38 : #include "cpl_virtualmem.h"
39 : #include "cpl_vsi.h"
40 : #include "gdal.h"
41 : #include "gdal_rat.h"
42 : #include "gdal_priv_templates.hpp"
43 : #include "gdal_interpolateatpoint.h"
44 : #include "gdal_minmax_element.hpp"
45 :
46 : /************************************************************************/
47 : /* GDALRasterBand() */
48 : /************************************************************************/
49 :
50 : /*! Constructor. Applications should never create GDALRasterBands directly. */
51 :
52 1640860 : GDALRasterBand::GDALRasterBand()
53 : : GDALRasterBand(
54 1640860 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
55 : {
56 1640620 : }
57 :
58 : /** Constructor. Applications should never create GDALRasterBands directly.
59 : * @param bForceCachedIOIn Whether cached IO should be forced.
60 : */
61 1917240 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
62 1917240 : : bForceCachedIO(bForceCachedIOIn)
63 :
64 : {
65 1916880 : }
66 :
67 : /************************************************************************/
68 : /* ~GDALRasterBand() */
69 : /************************************************************************/
70 :
71 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
72 : instead destroy the GDALDataset. */
73 :
74 1917230 : GDALRasterBand::~GDALRasterBand()
75 :
76 : {
77 1917230 : if (poDS && poDS->IsMarkedSuppressOnClose())
78 : {
79 501 : if (poBandBlockCache)
80 438 : poBandBlockCache->DisableDirtyBlockWriting();
81 : }
82 1917220 : GDALRasterBand::FlushCache(true);
83 :
84 1917220 : delete poBandBlockCache;
85 :
86 1917220 : if (static_cast<GIntBig>(nBlockReads) >
87 1917220 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
88 220 : nBand == 1 && poDS != nullptr)
89 : {
90 320 : CPLDebug(
91 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
92 160 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
93 160 : poDS->GetDescription());
94 : }
95 :
96 1917220 : InvalidateMaskBand();
97 1917230 : nBand = -nBand;
98 :
99 1917230 : delete m_poPointsCache;
100 1917220 : }
101 :
102 : /************************************************************************/
103 : /* RasterIO() */
104 : /************************************************************************/
105 :
106 : /**
107 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
108 : * int nXOff, int nYOff, int nXSize, int nYSize,
109 : * void * pData, int nBufXSize, int nBufYSize,
110 : * GDALDataType eBufType,
111 : * GSpacing nPixelSpace,
112 : * GSpacing nLineSpace,
113 : * GDALRasterIOExtraArg* psExtraArg )
114 : * \brief Read/write a region of image data for this band.
115 : *
116 : * This method allows reading a region of a GDALRasterBand into a buffer,
117 : * or writing data from a buffer into a region of a GDALRasterBand. It
118 : * automatically takes care of data type translation if the data type
119 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
120 : * The method also takes care of image decimation / replication if the
121 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
122 : * region being accessed (nXSize x nYSize).
123 : *
124 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
125 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
126 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
127 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
128 : * Or use nLineSpace and a possibly shifted pData value.
129 : *
130 : * The nPixelSpace and nLineSpace parameters allow reading into or
131 : * writing from unusually organized buffers. This is primarily used
132 : * for buffers containing more than one bands raster data in interleaved
133 : * format.
134 : *
135 : * Some formats may efficiently implement decimation into a buffer by
136 : * reading from lower resolution overview images. The logic of the default
137 : * implementation in the base class GDALRasterBand is the following one. It
138 : * computes a target_downscaling_factor from the window of interest and buffer
139 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
140 : * It then walks through overviews and will select the first one whose
141 : * downscaling factor is greater than target_downscaling_factor / 1.2.
142 : *
143 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
144 : * The relationship between target_downscaling_factor and the select overview
145 : * level is the following one:
146 : *
147 : * target_downscaling_factor | selected_overview
148 : * ------------------------- | -----------------
149 : * ]0, 2 / 1.2] | full resolution band
150 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
151 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
152 : * ]8 / 1.2, infinity[ | 8x downsampled band
153 : *
154 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
155 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
156 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
157 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
158 : * this oversampling threshold defaults to 1. Consequently if there are overviews
159 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
160 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
161 : *
162 : * For highest performance full resolution data access, read and write
163 : * on "block boundaries" as returned by GetBlockSize(), or use the
164 : * ReadBlock() and WriteBlock() methods.
165 : *
166 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
167 : * functions.
168 : *
169 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
170 : * write a region of data.
171 : *
172 : * @param nXOff The pixel offset to the top left corner of the region
173 : * of the band to be accessed. This would be zero to start from the left side.
174 : *
175 : * @param nYOff The line offset to the top left corner of the region
176 : * of the band to be accessed. This would be zero to start from the top.
177 : *
178 : * @param nXSize The width of the region of the band to be accessed in pixels.
179 : *
180 : * @param nYSize The height of the region of the band to be accessed in lines.
181 : *
182 : * @param pData The buffer into which the data should be read, or from which
183 : * it should be written. This buffer must contain at least nBufXSize *
184 : * nBufYSize words of type eBufType. It is organized in left to right,
185 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
186 : * and nLineSpace parameters.
187 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
188 : * temporarily modified during the execution of this method (and eventually
189 : * restored back to its original content), so it is not safe to use a buffer
190 : * stored in a read-only section of the calling program.
191 : *
192 : * @param nBufXSize the width of the buffer image into which the desired region
193 : * is to be read, or from which it is to be written.
194 : *
195 : * @param nBufYSize the height of the buffer image into which the desired region
196 : * is to be read, or from which it is to be written.
197 : *
198 : * @param eBufType the type of the pixel values in the pData data buffer. The
199 : * pixel values will automatically be translated to/from the GDALRasterBand
200 : * data type as needed. Most driver implementations will use GDALCopyWords64()
201 : * to perform data type translation.
202 : *
203 : * @param nPixelSpace The byte offset from the start of one pixel value in
204 : * pData to the start of the next pixel value within a scanline. If defaulted
205 : * (0) the size of the datatype eBufType is used.
206 : *
207 : * @param nLineSpace The byte offset from the start of one scanline in
208 : * pData to the start of the next. If defaulted (0) the size of the datatype
209 : * eBufType * nBufXSize is used.
210 : *
211 : * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
212 : * structure with additional arguments to specify resampling and progress
213 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
214 : * configuration option can also be defined to override the default resampling
215 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
216 : *
217 : * @return CE_Failure if the access fails, otherwise CE_None.
218 : */
219 :
220 : /**
221 : * \brief Read/write a region of image data for this band.
222 : *
223 : * This method allows reading a region of a GDALRasterBand into a buffer,
224 : * or writing data from a buffer into a region of a GDALRasterBand. It
225 : * automatically takes care of data type translation if the data type
226 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
227 : * The method also takes care of image decimation / replication if the
228 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
229 : * region being accessed (nXSize x nYSize).
230 : *
231 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
232 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
233 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
234 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
235 : * Or use nLineSpace and a possibly shifted pData value.
236 : *
237 : * The nPixelSpace and nLineSpace parameters allow reading into or
238 : * writing from unusually organized buffers. This is primarily used
239 : * for buffers containing more than one bands raster data in interleaved
240 : * format.
241 : *
242 : * Some formats may efficiently implement decimation into a buffer by
243 : * reading from lower resolution overview images. The logic of the default
244 : * implementation in the base class GDALRasterBand is the following one. It
245 : * computes a target_downscaling_factor from the window of interest and buffer
246 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
247 : * It then walks through overviews and will select the first one whose
248 : * downscaling factor is greater than target_downscaling_factor / 1.2.
249 : *
250 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
251 : * The relationship between target_downscaling_factor and the select overview
252 : * level is the following one:
253 : *
254 : * target_downscaling_factor | selected_overview
255 : * ------------------------- | -----------------
256 : * ]0, 2 / 1.2] | full resolution band
257 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
258 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
259 : * ]8 / 1.2, infinity[ | 8x downsampled band
260 : *
261 : * For highest performance full resolution data access, read and write
262 : * on "block boundaries" as returned by GetBlockSize(), or use the
263 : * ReadBlock() and WriteBlock() methods.
264 : *
265 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
266 : * functions.
267 : *
268 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
269 : * more convenient to use for most common use cases.
270 : *
271 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
272 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
273 : * instance of this dataset) concurrently from several threads.
274 : *
275 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
276 : * write a region of data.
277 : *
278 : * @param nXOff The pixel offset to the top left corner of the region
279 : * of the band to be accessed. This would be zero to start from the left side.
280 : *
281 : * @param nYOff The line offset to the top left corner of the region
282 : * of the band to be accessed. This would be zero to start from the top.
283 : *
284 : * @param nXSize The width of the region of the band to be accessed in pixels.
285 : *
286 : * @param nYSize The height of the region of the band to be accessed in lines.
287 : *
288 : * @param[in,out] pData The buffer into which the data should be read, or from
289 : * which it should be written. This buffer must contain at least nBufXSize *
290 : * nBufYSize words of type eBufType. It is organized in left to right,
291 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
292 : * and nLineSpace parameters.
293 : *
294 : * @param nBufXSize the width of the buffer image into which the desired region
295 : * is to be read, or from which it is to be written.
296 : *
297 : * @param nBufYSize the height of the buffer image into which the desired region
298 : * is to be read, or from which it is to be written.
299 : *
300 : * @param eBufType the type of the pixel values in the pData data buffer. The
301 : * pixel values will automatically be translated to/from the GDALRasterBand
302 : * data type as needed.
303 : *
304 : * @param nPixelSpace The byte offset from the start of one pixel value in
305 : * pData to the start of the next pixel value within a scanline. If defaulted
306 : * (0) the size of the datatype eBufType is used.
307 : *
308 : * @param nLineSpace The byte offset from the start of one scanline in
309 : * pData to the start of the next. If defaulted (0) the size of the datatype
310 : * eBufType * nBufXSize is used.
311 : *
312 : * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
313 : * structure with additional arguments to specify resampling and progress
314 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
315 : * configuration option can also be defined to override the default resampling
316 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
317 : *
318 : * @return CE_Failure if the access fails, otherwise CE_None.
319 : *
320 : * @see GDALRasterBand::ReadRaster()
321 : */
322 :
323 4381430 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
324 : int nXSize, int nYSize, void *pData,
325 : int nBufXSize, int nBufYSize,
326 : GDALDataType eBufType, GSpacing nPixelSpace,
327 : GSpacing nLineSpace,
328 : GDALRasterIOExtraArg *psExtraArg)
329 :
330 : {
331 : GDALRasterIOExtraArg sExtraArg;
332 4381430 : if (psExtraArg == nullptr)
333 : {
334 3778770 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
335 3778770 : psExtraArg = &sExtraArg;
336 : }
337 602659 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
338 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
339 : {
340 0 : ReportError(CE_Failure, CPLE_AppDefined,
341 : "Unhandled version of GDALRasterIOExtraArg");
342 0 : return CE_Failure;
343 : }
344 :
345 4381430 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
346 : nBufYSize);
347 :
348 4390300 : if (CPL_UNLIKELY(nullptr == pData))
349 : {
350 0 : ReportError(CE_Failure, CPLE_AppDefined,
351 : "The buffer into which the data should be read is null");
352 0 : return CE_Failure;
353 : }
354 :
355 : /* -------------------------------------------------------------------- */
356 : /* Some size values are "noop". Lets just return to avoid */
357 : /* stressing lower level functions. */
358 : /* -------------------------------------------------------------------- */
359 4390300 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
360 : nBufYSize < 1))
361 : {
362 2 : CPLDebug("GDAL",
363 : "RasterIO() skipped for odd window or buffer size.\n"
364 : " Window = (%d,%d)x%dx%d\n"
365 : " Buffer = %dx%d\n",
366 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
367 :
368 2 : return CE_None;
369 : }
370 :
371 4390300 : if (eRWFlag == GF_Write)
372 : {
373 363974 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
374 : {
375 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
376 : "An error occurred while writing a dirty block "
377 : "from GDALRasterBand::RasterIO");
378 0 : CPLErr eErr = eFlushBlockErr;
379 0 : eFlushBlockErr = CE_None;
380 0 : return eErr;
381 : }
382 363974 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
383 : {
384 7 : return CE_Failure;
385 : }
386 : }
387 :
388 : /* -------------------------------------------------------------------- */
389 : /* If pixel and line spacing are defaulted assign reasonable */
390 : /* value assuming a packed buffer. */
391 : /* -------------------------------------------------------------------- */
392 4390340 : if (nPixelSpace == 0)
393 : {
394 3979460 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
395 : }
396 :
397 4380520 : if (nLineSpace == 0)
398 : {
399 3957960 : nLineSpace = nPixelSpace * nBufXSize;
400 : }
401 :
402 : /* -------------------------------------------------------------------- */
403 : /* Do some validation of parameters. */
404 : /* -------------------------------------------------------------------- */
405 4380520 : if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
406 : nXOff + nXSize > nRasterXSize || nYOff < 0 ||
407 : nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
408 : {
409 15 : ReportError(CE_Failure, CPLE_IllegalArg,
410 : "Access window out of range in RasterIO(). Requested\n"
411 : "(%d,%d) of size %dx%d on raster of %dx%d.",
412 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
413 15 : return CE_Failure;
414 : }
415 :
416 4380510 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
417 : {
418 0 : ReportError(
419 : CE_Failure, CPLE_IllegalArg,
420 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
421 : eRWFlag);
422 0 : return CE_Failure;
423 : }
424 4380510 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
425 : {
426 2 : ReportError(CE_Failure, CPLE_IllegalArg,
427 : "Illegal GDT_Unknown/GDT_TypeCount argument");
428 2 : return CE_Failure;
429 : }
430 :
431 4380510 : return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
432 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
433 4364130 : nLineSpace, psExtraArg);
434 : }
435 :
436 : /************************************************************************/
437 : /* RasterIOInternal() */
438 : /************************************************************************/
439 :
440 4386410 : CPLErr GDALRasterBand::RasterIOInternal(
441 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
442 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
443 : GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
444 : {
445 : /* -------------------------------------------------------------------- */
446 : /* Call the format specific function. */
447 : /* -------------------------------------------------------------------- */
448 :
449 4386410 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
450 :
451 : CPLErr eErr;
452 4385340 : if (bForceCachedIO)
453 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
454 : pData, nBufXSize, nBufYSize, eBufType,
455 : nPixelSpace, nLineSpace, psExtraArg);
456 : else
457 : eErr =
458 4378450 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
459 4385320 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
460 :
461 4378470 : if (bCallLeaveReadWrite)
462 600745 : LeaveReadWrite();
463 :
464 4347740 : return eErr;
465 : }
466 :
467 : /************************************************************************/
468 : /* GDALRasterIO() */
469 : /************************************************************************/
470 :
471 : /**
472 : * \brief Read/write a region of image data for this band.
473 : *
474 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
475 : * resolution, progress callback, etc. are needed)
476 : *
477 : * @see GDALRasterBand::RasterIO()
478 : */
479 :
480 3383720 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
481 : int nXOff, int nYOff, int nXSize, int nYSize,
482 : void *pData, int nBufXSize, int nBufYSize,
483 : GDALDataType eBufType, int nPixelSpace,
484 : int nLineSpace)
485 :
486 : {
487 3383720 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
488 :
489 3383720 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
490 :
491 3385180 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
492 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
493 3365800 : nLineSpace, nullptr));
494 : }
495 :
496 : /************************************************************************/
497 : /* GDALRasterIOEx() */
498 : /************************************************************************/
499 :
500 : /**
501 : * \brief Read/write a region of image data for this band.
502 : *
503 : * @see GDALRasterBand::RasterIO()
504 : * @since GDAL 2.0
505 : */
506 :
507 40186 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
508 : int nXOff, int nYOff, int nXSize, int nYSize,
509 : void *pData, int nBufXSize, int nBufYSize,
510 : GDALDataType eBufType, GSpacing nPixelSpace,
511 : GSpacing nLineSpace,
512 : GDALRasterIOExtraArg *psExtraArg)
513 :
514 : {
515 40186 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
516 :
517 40186 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
518 :
519 40185 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
520 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
521 40179 : nLineSpace, psExtraArg));
522 : }
523 :
524 : /************************************************************************/
525 : /* GetGDTFromCppType() */
526 : /************************************************************************/
527 :
528 : namespace
529 : {
530 : template <class T> struct GetGDTFromCppType;
531 :
532 : #define DEFINE_GetGDTFromCppType(T, eDT) \
533 : template <> struct GetGDTFromCppType<T> \
534 : { \
535 : static constexpr GDALDataType GDT = eDT; \
536 : }
537 :
538 : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
539 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
540 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
541 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
542 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
543 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
544 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
545 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
546 : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
547 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
548 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
549 : // Not allowed by C++ standard
550 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
551 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
552 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
553 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
554 : } // namespace
555 :
556 : /************************************************************************/
557 : /* ReadRaster() */
558 : /************************************************************************/
559 :
560 : // clang-format off
561 : /** Read a region of image data for this band.
562 : *
563 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
564 : * for common use cases, like reading a whole band.
565 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
566 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
567 : * float, double, std::complex<float|double>.
568 : *
569 : * 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>&,
570 : * and can allocate memory automatically.
571 : *
572 : * To read a whole band (assuming it fits into memory), as an array of double:
573 : *
574 : \code{.cpp}
575 : double* myArray = static_cast<double*>(
576 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
577 : // TODO: check here that myArray != nullptr
578 : const size_t nArrayEltCount =
579 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
580 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
581 : {
582 : // do something
583 : }
584 : VSIFree(myArray)
585 : \endcode
586 : *
587 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
588 : *
589 : \code{.cpp}
590 : double* myArray = static_cast<double*>(
591 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
592 : // TODO: check here that myArray != nullptr
593 : const size_t nArrayEltCount = 128 * 128;
594 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
595 : {
596 : // do something
597 : }
598 : VSIFree(myArray)
599 : \endcode
600 : *
601 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
602 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
603 : * instance of this dataset) concurrently from several threads.
604 : *
605 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
606 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
607 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
608 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
609 : * Or use nLineSpace and a possibly shifted pData value.
610 : *
611 : * @param[out] pData The buffer into which the data should be written.
612 : * This buffer must contain at least nBufXSize *
613 : * nBufYSize words of type T. It is organized in left to right,
614 : * top to bottom pixel order, and fully packed.
615 : * The type of the buffer does not need to be the one of GetDataType(). The
616 : * method will perform data type translation (with potential rounding, clamping)
617 : * if needed.
618 : *
619 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
620 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
621 : * return in error if it is not. If set to zero, then pData is trusted to be
622 : * large enough.
623 : *
624 : * @param dfXOff The pixel offset to the top left corner of the region
625 : * of the band to be accessed. This would be zero to start from the left side.
626 : * Defaults to 0.
627 : *
628 : * @param dfYOff The line offset to the top left corner of the region
629 : * of the band to be accessed. This would be zero to start from the top.
630 : * Defaults to 0.
631 : *
632 : * @param dfXSize The width of the region of the band to be accessed in pixels.
633 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
634 : * dfXSize is set to the band width.
635 : *
636 : * @param dfYSize The height of the region of the band to be accessed in lines.
637 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
638 : * dfYSize is set to the band height.
639 : *
640 : * @param nBufXSize the width of the buffer image into which the desired region
641 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
642 : * then nBufXSize is initialized with dfXSize.
643 : *
644 : * @param nBufYSize the height of the buffer image into which the desired region
645 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
646 : * then nBufYSize is initialized with dfYSize.
647 : *
648 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
649 : *
650 : * @param pfnProgress Progress function. May be nullptr.
651 : *
652 : * @param pProgressData User data of pfnProgress. May be nullptr.
653 : *
654 : * @return CE_Failure if the access fails, otherwise CE_None.
655 : *
656 : * @see GDALRasterBand::RasterIO()
657 : * @since GDAL 3.10
658 : */
659 : // clang-format on
660 :
661 : template <class T>
662 20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
663 : double dfXOff, double dfYOff, double dfXSize,
664 : double dfYSize, size_t nBufXSize,
665 : size_t nBufYSize,
666 : GDALRIOResampleAlg eResampleAlg,
667 : GDALProgressFunc pfnProgress,
668 : void *pProgressData) const
669 : {
670 20 : if (((nBufXSize | nBufYSize) >> 31) != 0)
671 : {
672 2 : return CE_Failure;
673 : }
674 :
675 18 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
676 : {
677 16 : dfXSize = nRasterXSize;
678 16 : dfYSize = nRasterYSize;
679 : }
680 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
681 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
682 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
683 2 : dfYOff + dfYSize > INT_MAX)
684 : {
685 0 : return CE_Failure;
686 : }
687 :
688 : GDALRasterIOExtraArg sExtraArg;
689 18 : sExtraArg.nVersion = 1;
690 18 : sExtraArg.eResampleAlg = eResampleAlg;
691 18 : sExtraArg.pfnProgress = pfnProgress;
692 18 : sExtraArg.pProgressData = pProgressData;
693 18 : sExtraArg.bFloatingPointWindowValidity = true;
694 18 : sExtraArg.dfXOff = dfXOff;
695 18 : sExtraArg.dfYOff = dfYOff;
696 18 : sExtraArg.dfXSize = dfXSize;
697 18 : sExtraArg.dfYSize = dfYSize;
698 18 : const int nXOff = static_cast<int>(dfXOff);
699 18 : const int nYOff = static_cast<int>(dfYOff);
700 18 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
701 18 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
702 18 : if (nBufXSize == 0 && nBufYSize == 0)
703 : {
704 17 : if (static_cast<int>(dfXSize) == dfXSize &&
705 17 : static_cast<int>(dfYSize) == dfYSize)
706 : {
707 17 : nBufXSize = static_cast<int>(dfXSize);
708 17 : nBufYSize = static_cast<int>(dfYSize);
709 : }
710 : else
711 : {
712 0 : CPLError(CE_Failure, CPLE_AppDefined,
713 : "nBufXSize and nBufYSize must be provided if dfXSize or "
714 : "dfYSize is not an integer value");
715 0 : return CE_Failure;
716 : }
717 : }
718 18 : if (nBufXSize == 0 || nBufYSize == 0)
719 : {
720 0 : CPLDebug("GDAL",
721 : "RasterIO() skipped for odd window or buffer size.\n"
722 : " Window = (%d,%d)x%dx%d\n"
723 : " Buffer = %dx%d\n",
724 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
725 : static_cast<int>(nBufYSize));
726 :
727 0 : return CE_None;
728 : }
729 :
730 18 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
731 : {
732 1 : CPLError(CE_Failure, CPLE_AppDefined,
733 : "Provided array is not large enough");
734 1 : return CE_Failure;
735 : }
736 :
737 17 : constexpr GSpacing nPixelSpace = sizeof(T);
738 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
739 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
740 :
741 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
742 :
743 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
744 : static_cast<int>(nBufXSize),
745 : static_cast<int>(nBufYSize), eBufType,
746 17 : nPixelSpace, nLineSpace, &sExtraArg);
747 : }
748 :
749 : //! @cond Doxygen_Suppress
750 :
751 : #define INSTANTIATE_READ_RASTER(T) \
752 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
753 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
754 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
755 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
756 : void *pProgressData) const;
757 :
758 : INSTANTIATE_READ_RASTER(uint8_t)
759 : INSTANTIATE_READ_RASTER(int8_t)
760 : INSTANTIATE_READ_RASTER(uint16_t)
761 : INSTANTIATE_READ_RASTER(int16_t)
762 : INSTANTIATE_READ_RASTER(uint32_t)
763 : INSTANTIATE_READ_RASTER(int32_t)
764 : INSTANTIATE_READ_RASTER(uint64_t)
765 : INSTANTIATE_READ_RASTER(int64_t)
766 : INSTANTIATE_READ_RASTER(GFloat16)
767 : INSTANTIATE_READ_RASTER(float)
768 : INSTANTIATE_READ_RASTER(double)
769 : // Not allowed by C++ standard
770 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
771 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
772 : INSTANTIATE_READ_RASTER(std::complex<float>)
773 : INSTANTIATE_READ_RASTER(std::complex<double>)
774 :
775 : //! @endcond
776 :
777 : /************************************************************************/
778 : /* ReadRaster() */
779 : /************************************************************************/
780 :
781 : /** Read a region of image data for this band.
782 : *
783 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
784 : * for common use cases, like reading a whole band.
785 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
786 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
787 : * float, double, std::complex<float|double>.
788 : *
789 : * To read a whole band (assuming it fits into memory), as a vector of double:
790 : *
791 : \code
792 : std::vector<double> myArray;
793 : if (poBand->ReadRaster(myArray) == CE_None)
794 : {
795 : // do something
796 : }
797 : \endcode
798 : *
799 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
800 : *
801 : \code{.cpp}
802 : std::vector<double> myArray;
803 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
804 : {
805 : // do something
806 : }
807 : \endcode
808 : *
809 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
810 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
811 : * instance of this dataset) concurrently from several threads.
812 : *
813 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
814 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
815 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
816 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
817 : * Or use nLineSpace and a possibly shifted pData value.
818 : *
819 : * @param[out] vData The vector into which the data should be written.
820 : * The vector will be resized, if needed, to contain at least nBufXSize *
821 : * nBufYSize values. The values in the vector are organized in left to right,
822 : * top to bottom pixel order, and fully packed.
823 : * The type of the vector does not need to be the one of GetDataType(). The
824 : * method will perform data type translation (with potential rounding, clamping)
825 : * if needed.
826 : *
827 : * @param dfXOff The pixel offset to the top left corner of the region
828 : * of the band to be accessed. This would be zero to start from the left side.
829 : * Defaults to 0.
830 : *
831 : * @param dfYOff The line offset to the top left corner of the region
832 : * of the band to be accessed. This would be zero to start from the top.
833 : * Defaults to 0.
834 : *
835 : * @param dfXSize The width of the region of the band to be accessed in pixels.
836 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
837 : * dfXSize is set to the band width.
838 : *
839 : * @param dfYSize The height of the region of the band to be accessed in lines.
840 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
841 : * dfYSize is set to the band height.
842 : *
843 : * @param nBufXSize the width of the buffer image into which the desired region
844 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
845 : * then nBufXSize is initialized with dfXSize.
846 : *
847 : * @param nBufYSize the height of the buffer image into which the desired region
848 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
849 : * then nBufYSize is initialized with dfYSize.
850 : *
851 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
852 : *
853 : * @param pfnProgress Progress function. May be nullptr.
854 : *
855 : * @param pProgressData User data of pfnProgress. May be nullptr.
856 : *
857 : * @return CE_Failure if the access fails, otherwise CE_None.
858 : *
859 : * @see GDALRasterBand::RasterIO()
860 : * @since GDAL 3.10
861 : */
862 : template <class T>
863 22 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
864 : double dfYOff, double dfXSize, double dfYSize,
865 : size_t nBufXSize, size_t nBufYSize,
866 : GDALRIOResampleAlg eResampleAlg,
867 : GDALProgressFunc pfnProgress,
868 : void *pProgressData) const
869 : {
870 22 : if (((nBufXSize | nBufYSize) >> 31) != 0)
871 : {
872 2 : return CE_Failure;
873 : }
874 :
875 20 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
876 : {
877 13 : dfXSize = nRasterXSize;
878 13 : dfYSize = nRasterYSize;
879 : }
880 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
881 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
882 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
883 7 : dfYOff + dfYSize > INT_MAX)
884 : {
885 0 : return CE_Failure;
886 : }
887 :
888 : GDALRasterIOExtraArg sExtraArg;
889 20 : sExtraArg.nVersion = 1;
890 20 : sExtraArg.eResampleAlg = eResampleAlg;
891 20 : sExtraArg.pfnProgress = pfnProgress;
892 20 : sExtraArg.pProgressData = pProgressData;
893 20 : sExtraArg.bFloatingPointWindowValidity = true;
894 20 : sExtraArg.dfXOff = dfXOff;
895 20 : sExtraArg.dfYOff = dfYOff;
896 20 : sExtraArg.dfXSize = dfXSize;
897 20 : sExtraArg.dfYSize = dfYSize;
898 20 : const int nXOff = static_cast<int>(dfXOff);
899 20 : const int nYOff = static_cast<int>(dfYOff);
900 20 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
901 20 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
902 20 : if (nBufXSize == 0 && nBufYSize == 0)
903 : {
904 16 : if (static_cast<int>(dfXSize) == dfXSize &&
905 15 : static_cast<int>(dfYSize) == dfYSize)
906 : {
907 15 : nBufXSize = static_cast<int>(dfXSize);
908 15 : nBufYSize = static_cast<int>(dfYSize);
909 : }
910 : else
911 : {
912 1 : CPLError(CE_Failure, CPLE_AppDefined,
913 : "nBufXSize and nBufYSize must be provided if "
914 : "dfXSize or dfYSize is not an integer value");
915 1 : return CE_Failure;
916 : }
917 : }
918 19 : if (nBufXSize == 0 || nBufYSize == 0)
919 : {
920 0 : CPLDebug("GDAL",
921 : "RasterIO() skipped for odd window or buffer size.\n"
922 : " Window = (%d,%d)x%dx%d\n"
923 : " Buffer = %dx%d\n",
924 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
925 : static_cast<int>(nBufYSize));
926 :
927 0 : return CE_None;
928 : }
929 :
930 : if constexpr (SIZEOF_VOIDP < 8)
931 : {
932 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
933 : {
934 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
935 : return CE_Failure;
936 : }
937 : }
938 :
939 19 : if (vData.size() < nBufXSize * nBufYSize)
940 : {
941 : try
942 : {
943 17 : vData.resize(nBufXSize * nBufYSize);
944 : }
945 1 : catch (const std::exception &)
946 : {
947 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
948 1 : return CE_Failure;
949 : }
950 : }
951 :
952 18 : constexpr GSpacing nPixelSpace = sizeof(T);
953 18 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
954 18 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
955 :
956 18 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
957 :
958 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
959 : vData.data(), static_cast<int>(nBufXSize),
960 : static_cast<int>(nBufYSize), eBufType,
961 18 : nPixelSpace, nLineSpace, &sExtraArg);
962 : }
963 :
964 : //! @cond Doxygen_Suppress
965 :
966 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
967 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
968 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
969 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
970 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
971 : void *pProgressData) const;
972 :
973 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
974 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
975 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
976 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
977 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
978 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
979 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
980 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
981 : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
982 : INSTANTIATE_READ_RASTER_VECTOR(float)
983 : INSTANTIATE_READ_RASTER_VECTOR(double)
984 : // Not allowed by C++ standard
985 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
986 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
987 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
988 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
989 :
990 : //! @endcond
991 :
992 : /************************************************************************/
993 : /* ReadBlock() */
994 : /************************************************************************/
995 :
996 : /**
997 : * \brief Read a block of image data efficiently.
998 : *
999 : * This method accesses a "natural" block from the raster band without
1000 : * resampling, or data type conversion. For a more generalized, but
1001 : * potentially less efficient access use RasterIO().
1002 : *
1003 : * This method is the same as the C GDALReadBlock() function.
1004 : *
1005 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1006 : * block oriented data without an extra copy into an application buffer.
1007 : *
1008 : * The following code would efficiently compute a histogram of eight bit
1009 : * raster data. Note that the final block may be partial ... data beyond
1010 : * the edge of the underlying raster band in these edge blocks is of an
1011 : * undetermined value.
1012 : *
1013 : \code{.cpp}
1014 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1015 :
1016 : {
1017 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1018 :
1019 : CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1020 :
1021 : int nXBlockSize, nYBlockSize;
1022 :
1023 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1024 : int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1025 : int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1026 :
1027 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1028 :
1029 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1030 : {
1031 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1032 : {
1033 : int nXValid, nYValid;
1034 :
1035 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1036 :
1037 : // Compute the portion of the block that is valid
1038 : // for partial edge blocks.
1039 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1040 :
1041 : // Collect the histogram counts.
1042 : for( int iY = 0; iY < nYValid; iY++ )
1043 : {
1044 : for( int iX = 0; iX < nXValid; iX++ )
1045 : {
1046 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1047 : }
1048 : }
1049 : }
1050 : }
1051 : }
1052 : \endcode
1053 : *
1054 : * @param nXBlockOff the horizontal block offset, with zero indicating
1055 : * the left most block, 1 the next block and so forth.
1056 : *
1057 : * @param nYBlockOff the vertical block offset, with zero indicating
1058 : * the top most block, 1 the next block and so forth.
1059 : *
1060 : * @param pImage the buffer into which the data will be read. The buffer
1061 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1062 : * of type GetRasterDataType().
1063 : *
1064 : * @return CE_None on success or CE_Failure on an error.
1065 : */
1066 :
1067 894 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1068 :
1069 : {
1070 : /* -------------------------------------------------------------------- */
1071 : /* Validate arguments. */
1072 : /* -------------------------------------------------------------------- */
1073 894 : CPLAssert(pImage != nullptr);
1074 :
1075 894 : if (!InitBlockInfo())
1076 0 : return CE_Failure;
1077 :
1078 894 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1079 : {
1080 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1081 : "Illegal nXBlockOff value (%d) in "
1082 : "GDALRasterBand::ReadBlock()\n",
1083 : nXBlockOff);
1084 :
1085 0 : return (CE_Failure);
1086 : }
1087 :
1088 894 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1089 : {
1090 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1091 : "Illegal nYBlockOff value (%d) in "
1092 : "GDALRasterBand::ReadBlock()\n",
1093 : nYBlockOff);
1094 :
1095 0 : return (CE_Failure);
1096 : }
1097 :
1098 : /* -------------------------------------------------------------------- */
1099 : /* Invoke underlying implementation method. */
1100 : /* -------------------------------------------------------------------- */
1101 :
1102 894 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1103 894 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1104 894 : if (bCallLeaveReadWrite)
1105 4 : LeaveReadWrite();
1106 894 : return eErr;
1107 : }
1108 :
1109 : /************************************************************************/
1110 : /* GDALReadBlock() */
1111 : /************************************************************************/
1112 :
1113 : /**
1114 : * \brief Read a block of image data efficiently.
1115 : *
1116 : * @see GDALRasterBand::ReadBlock()
1117 : */
1118 :
1119 77 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1120 : void *pData)
1121 :
1122 : {
1123 77 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1124 :
1125 77 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1126 77 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1127 : }
1128 :
1129 : /************************************************************************/
1130 : /* IReadBlock() */
1131 : /************************************************************************/
1132 :
1133 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1134 : * ) \brief Read a block of data.
1135 : *
1136 : * Default internal implementation ... to be overridden by
1137 : * subclasses that support reading.
1138 : * @param nBlockXOff Block X Offset
1139 : * @param nBlockYOff Block Y Offset
1140 : * @param pData Pixel buffer into which to place read data.
1141 : * @return CE_None on success or CE_Failure on an error.
1142 : */
1143 :
1144 : /************************************************************************/
1145 : /* IWriteBlock() */
1146 : /************************************************************************/
1147 :
1148 : /**
1149 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1150 : * Write a block of data.
1151 : *
1152 : * Default internal implementation ... to be overridden by
1153 : * subclasses that support writing.
1154 : * @param nBlockXOff Block X Offset
1155 : * @param nBlockYOff Block Y Offset
1156 : * @param pData Pixel buffer to write
1157 : * @return CE_None on success or CE_Failure on an error.
1158 : */
1159 :
1160 : /**/
1161 : /**/
1162 :
1163 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1164 : void * /*pData*/)
1165 :
1166 : {
1167 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1168 0 : ReportError(CE_Failure, CPLE_NotSupported,
1169 : "WriteBlock() not supported for this dataset.");
1170 :
1171 0 : return (CE_Failure);
1172 : }
1173 :
1174 : /************************************************************************/
1175 : /* WriteBlock() */
1176 : /************************************************************************/
1177 :
1178 : /**
1179 : * \brief Write a block of image data efficiently.
1180 : *
1181 : * This method accesses a "natural" block from the raster band without
1182 : * resampling, or data type conversion. For a more generalized, but
1183 : * potentially less efficient access use RasterIO().
1184 : *
1185 : * This method is the same as the C GDALWriteBlock() function.
1186 : *
1187 : * See ReadBlock() for an example of block oriented data access.
1188 : *
1189 : * @param nXBlockOff the horizontal block offset, with zero indicating
1190 : * the left most block, 1 the next block and so forth.
1191 : *
1192 : * @param nYBlockOff the vertical block offset, with zero indicating
1193 : * the left most block, 1 the next block and so forth.
1194 : *
1195 : * @param pImage the buffer from which the data will be written. The buffer
1196 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1197 : * of type GetRasterDataType(). Note that the content of the buffer might be
1198 : * temporarily modified during the execution of this method (and eventually
1199 : * restored back to its original content), so it is not safe to use a buffer
1200 : * stored in a read-only section of the calling program.
1201 : *
1202 : * @return CE_None on success or CE_Failure on an error.
1203 : */
1204 :
1205 4887 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1206 :
1207 : {
1208 : /* -------------------------------------------------------------------- */
1209 : /* Validate arguments. */
1210 : /* -------------------------------------------------------------------- */
1211 4887 : CPLAssert(pImage != nullptr);
1212 :
1213 4887 : if (!InitBlockInfo())
1214 0 : return CE_Failure;
1215 :
1216 4887 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1217 : {
1218 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1219 : "Illegal nXBlockOff value (%d) in "
1220 : "GDALRasterBand::WriteBlock()\n",
1221 : nXBlockOff);
1222 :
1223 0 : return (CE_Failure);
1224 : }
1225 :
1226 4887 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1227 : {
1228 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1229 : "Illegal nYBlockOff value (%d) in "
1230 : "GDALRasterBand::WriteBlock()\n",
1231 : nYBlockOff);
1232 :
1233 0 : return (CE_Failure);
1234 : }
1235 :
1236 4887 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1237 : {
1238 0 : return CE_Failure;
1239 : }
1240 :
1241 4887 : if (eFlushBlockErr != CE_None)
1242 : {
1243 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1244 : "An error occurred while writing a dirty block "
1245 : "from GDALRasterBand::WriteBlock");
1246 0 : CPLErr eErr = eFlushBlockErr;
1247 0 : eFlushBlockErr = CE_None;
1248 0 : return eErr;
1249 : }
1250 :
1251 : /* -------------------------------------------------------------------- */
1252 : /* Invoke underlying implementation method. */
1253 : /* -------------------------------------------------------------------- */
1254 :
1255 4887 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1256 4887 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1257 4887 : if (bCallLeaveReadWrite)
1258 4887 : LeaveReadWrite();
1259 :
1260 4887 : return eErr;
1261 : }
1262 :
1263 : /************************************************************************/
1264 : /* GDALWriteBlock() */
1265 : /************************************************************************/
1266 :
1267 : /**
1268 : * \brief Write a block of image data efficiently.
1269 : *
1270 : * @see GDALRasterBand::WriteBlock()
1271 : */
1272 :
1273 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1274 : void *pData)
1275 :
1276 : {
1277 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1278 :
1279 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1280 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1281 : }
1282 :
1283 : /************************************************************************/
1284 : /* EmitErrorMessageIfWriteNotSupported() */
1285 : /************************************************************************/
1286 :
1287 : /**
1288 : * Emit an error message if a write operation to this band is not supported.
1289 : *
1290 : * The base implementation will emit an error message if the access mode is
1291 : * read-only. Derived classes may implement it to provide a custom message.
1292 : *
1293 : * @param pszCaller Calling function.
1294 : * @return true if an error message has been emitted.
1295 : */
1296 637498 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1297 : const char *pszCaller) const
1298 : {
1299 637498 : if (eAccess == GA_ReadOnly)
1300 : {
1301 4 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1302 : "%s: attempt to write to dataset opened in read-only mode.",
1303 : pszCaller);
1304 :
1305 4 : return true;
1306 : }
1307 637494 : return false;
1308 : }
1309 :
1310 : /************************************************************************/
1311 : /* GetActualBlockSize() */
1312 : /************************************************************************/
1313 : /**
1314 : * \brief Fetch the actual block size for a given block offset.
1315 : *
1316 : * Handles partial blocks at the edges of the raster and returns the true
1317 : * number of pixels
1318 : *
1319 : * @param nXBlockOff the horizontal block offset for which to calculate the
1320 : * number of valid pixels, with zero indicating the left most block, 1 the next
1321 : * block and so forth.
1322 : *
1323 : * @param nYBlockOff the vertical block offset, with zero indicating
1324 : * the top most block, 1 the next block and so forth.
1325 : *
1326 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1327 : * the x direction will be stored
1328 : *
1329 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1330 : * the y direction will be stored
1331 : *
1332 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1333 : *
1334 : * @since GDAL 2.2
1335 : */
1336 51654 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1337 : int *pnXValid, int *pnYValid) const
1338 : {
1339 103307 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1340 103306 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1341 103304 : nYBlockOff < 0 || nBlockYSize == 0 ||
1342 51652 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1343 : {
1344 3 : return CE_Failure;
1345 : }
1346 :
1347 51651 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1348 51651 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1349 :
1350 51651 : *pnXValid = nBlockXSize;
1351 51651 : *pnYValid = nBlockYSize;
1352 :
1353 51651 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1354 : {
1355 50111 : *pnXValid = nRasterXSize - nXPixelOff;
1356 : }
1357 :
1358 51651 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1359 : {
1360 3677 : *pnYValid = nRasterYSize - nYPixelOff;
1361 : }
1362 :
1363 51651 : return CE_None;
1364 : }
1365 :
1366 : /************************************************************************/
1367 : /* GDALGetActualBlockSize() */
1368 : /************************************************************************/
1369 :
1370 : /**
1371 : * \brief Retrieve the actual block size for a given block offset.
1372 : *
1373 : * @see GDALRasterBand::GetActualBlockSize()
1374 : */
1375 :
1376 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1377 : int nYBlockOff, int *pnXValid,
1378 : int *pnYValid)
1379 :
1380 : {
1381 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1382 :
1383 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1384 : return (
1385 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1386 : }
1387 :
1388 : /************************************************************************/
1389 : /* GetSuggestedBlockAccessPattern() */
1390 : /************************************************************************/
1391 :
1392 : /**
1393 : * \brief Return the suggested/most efficient access pattern to blocks
1394 : * (for read operations).
1395 : *
1396 : * While all GDAL drivers have to expose a block size, not all can guarantee
1397 : * efficient random access (GSBAP_RANDOM) to any block.
1398 : * Some drivers for example decompress sequentially a compressed stream from
1399 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1400 : * case best performance will be achieved while reading blocks in that order.
1401 : * (accessing blocks in random access in such rasters typically causes the
1402 : * decoding to be re-initialized from the start if accessing blocks in
1403 : * a non-sequential order)
1404 : *
1405 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1406 : * returned by drivers that expose a somewhat artificial block size, because
1407 : * they can extract any part of a raster, but in a rather inefficient way.
1408 : *
1409 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1410 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1411 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1412 : * most efficient strategy is to read as many pixels as possible in the less
1413 : * RasterIO() operations.
1414 : *
1415 : * The return of this method is for example used to determine the swath size
1416 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1417 : *
1418 : * @since GDAL 3.6
1419 : */
1420 :
1421 : GDALSuggestedBlockAccessPattern
1422 2374 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1423 : {
1424 2374 : return GSBAP_UNKNOWN;
1425 : }
1426 :
1427 : /************************************************************************/
1428 : /* GetRasterDataType() */
1429 : /************************************************************************/
1430 :
1431 : /**
1432 : * \brief Fetch the pixel data type for this band.
1433 : *
1434 : * This method is the same as the C function GDALGetRasterDataType().
1435 : *
1436 : * @return the data type of pixels for this band.
1437 : */
1438 :
1439 8956280 : GDALDataType GDALRasterBand::GetRasterDataType() const
1440 :
1441 : {
1442 8956280 : return eDataType;
1443 : }
1444 :
1445 : /************************************************************************/
1446 : /* GDALGetRasterDataType() */
1447 : /************************************************************************/
1448 :
1449 : /**
1450 : * \brief Fetch the pixel data type for this band.
1451 : *
1452 : * @see GDALRasterBand::GetRasterDataType()
1453 : */
1454 :
1455 905183 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1456 :
1457 : {
1458 905183 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1459 :
1460 905183 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1461 905182 : return poBand->GetRasterDataType();
1462 : }
1463 :
1464 : /************************************************************************/
1465 : /* GetBlockSize() */
1466 : /************************************************************************/
1467 :
1468 : /**
1469 : * \brief Fetch the "natural" block size of this band.
1470 : *
1471 : * GDAL contains a concept of the natural block size of rasters so that
1472 : * applications can organized data access efficiently for some file formats.
1473 : * The natural block size is the block size that is most efficient for
1474 : * accessing the format. For many formats this is simple a whole scanline
1475 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1476 : *
1477 : * However, for tiled images this will typically be the tile size.
1478 : *
1479 : * Note that the X and Y block sizes don't have to divide the image size
1480 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1481 : * See ReadBlock() for an example of code dealing with these issues.
1482 : *
1483 : * This method is the same as the C function GDALGetBlockSize().
1484 : *
1485 : * @param pnXSize integer to put the X block size into or NULL.
1486 : *
1487 : * @param pnYSize integer to put the Y block size into or NULL.
1488 : */
1489 :
1490 5437370 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1491 :
1492 : {
1493 5437370 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1494 : {
1495 37860 : ReportError(CE_Failure, CPLE_AppDefined,
1496 37860 : "Invalid block dimension : %d * %d", nBlockXSize,
1497 37860 : nBlockYSize);
1498 4 : if (pnXSize != nullptr)
1499 4 : *pnXSize = 0;
1500 4 : if (pnYSize != nullptr)
1501 4 : *pnYSize = 0;
1502 : }
1503 : else
1504 : {
1505 5399510 : if (pnXSize != nullptr)
1506 5397730 : *pnXSize = nBlockXSize;
1507 5399510 : if (pnYSize != nullptr)
1508 5398750 : *pnYSize = nBlockYSize;
1509 : }
1510 5399520 : }
1511 :
1512 : /************************************************************************/
1513 : /* GDALGetBlockSize() */
1514 : /************************************************************************/
1515 :
1516 : /**
1517 : * \brief Fetch the "natural" block size of this band.
1518 : *
1519 : * @see GDALRasterBand::GetBlockSize()
1520 : */
1521 :
1522 41129 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1523 : int *pnYSize)
1524 :
1525 : {
1526 41129 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1527 :
1528 41129 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1529 41129 : poBand->GetBlockSize(pnXSize, pnYSize);
1530 : }
1531 :
1532 : /************************************************************************/
1533 : /* InitBlockInfo() */
1534 : /************************************************************************/
1535 :
1536 : //! @cond Doxygen_Suppress
1537 3643270 : int GDALRasterBand::InitBlockInfo()
1538 :
1539 : {
1540 3643270 : if (poBandBlockCache != nullptr)
1541 3405080 : return poBandBlockCache->IsInitOK();
1542 :
1543 : /* Do some validation of raster and block dimensions in case the driver */
1544 : /* would have neglected to do it itself */
1545 238196 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1546 : {
1547 4 : ReportError(CE_Failure, CPLE_AppDefined,
1548 : "Invalid block dimension : %d * %d", nBlockXSize,
1549 : nBlockYSize);
1550 0 : return FALSE;
1551 : }
1552 :
1553 238192 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1554 : {
1555 5 : ReportError(CE_Failure, CPLE_AppDefined,
1556 : "Invalid raster dimension : %d * %d", nRasterXSize,
1557 : nRasterYSize);
1558 0 : return FALSE;
1559 : }
1560 :
1561 238187 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1562 238187 : if (nDataTypeSize == 0)
1563 : {
1564 0 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1565 0 : return FALSE;
1566 : }
1567 :
1568 : #if SIZEOF_VOIDP == 4
1569 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1570 : {
1571 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1572 : * multiplication in other cases */
1573 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1574 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1575 : {
1576 : ReportError(CE_Failure, CPLE_NotSupported,
1577 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1578 : nBlockYSize);
1579 : return FALSE;
1580 : }
1581 : }
1582 : #endif
1583 :
1584 238188 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1585 238188 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1586 :
1587 : const char *pszBlockStrategy =
1588 238188 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1589 238197 : bool bUseArray = true;
1590 238197 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1591 : {
1592 238157 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1593 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1594 : {
1595 238138 : GUIntBig nBlockCount =
1596 238138 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1597 238138 : if (poDS != nullptr)
1598 237936 : nBlockCount *= poDS->GetRasterCount();
1599 238138 : bUseArray = (nBlockCount < 1024 * 1024);
1600 : }
1601 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1602 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1603 : {
1604 0 : bUseArray = false;
1605 238157 : }
1606 : }
1607 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1608 40 : bUseArray = false;
1609 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1610 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1611 : pszBlockStrategy);
1612 :
1613 238197 : if (bUseArray)
1614 238126 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1615 : else
1616 : {
1617 71 : if (nBand == 1)
1618 26 : CPLDebug("GDAL", "Use hashset band block cache");
1619 71 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1620 : }
1621 238196 : if (poBandBlockCache == nullptr)
1622 0 : return FALSE;
1623 238196 : return poBandBlockCache->Init();
1624 : }
1625 :
1626 : //! @endcond
1627 :
1628 : /************************************************************************/
1629 : /* FlushCache() */
1630 : /************************************************************************/
1631 :
1632 : /**
1633 : * \brief Flush raster data cache.
1634 : *
1635 : * This call will recover memory used to cache data blocks for this raster
1636 : * band, and ensure that new requests are referred to the underlying driver.
1637 : *
1638 : * This method is the same as the C function GDALFlushRasterCache().
1639 : *
1640 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1641 : * @return CE_None on success.
1642 : */
1643 :
1644 5636880 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1645 :
1646 : {
1647 5752860 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1648 115974 : poBandBlockCache)
1649 2935 : poBandBlockCache->DisableDirtyBlockWriting();
1650 :
1651 5646680 : CPLErr eGlobalErr = eFlushBlockErr;
1652 :
1653 5646680 : if (eFlushBlockErr != CE_None)
1654 : {
1655 0 : ReportError(
1656 : eFlushBlockErr, CPLE_AppDefined,
1657 : "An error occurred while writing a dirty block from FlushCache");
1658 0 : eFlushBlockErr = CE_None;
1659 : }
1660 :
1661 5646680 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1662 4870500 : return eGlobalErr;
1663 :
1664 776190 : return poBandBlockCache->FlushCache();
1665 : }
1666 :
1667 : /************************************************************************/
1668 : /* GDALFlushRasterCache() */
1669 : /************************************************************************/
1670 :
1671 : /**
1672 : * \brief Flush raster data cache.
1673 : *
1674 : * @see GDALRasterBand::FlushCache()
1675 : */
1676 :
1677 487 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1678 :
1679 : {
1680 487 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1681 :
1682 487 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1683 : }
1684 :
1685 : /************************************************************************/
1686 : /* DropCache() */
1687 : /************************************************************************/
1688 :
1689 : /**
1690 : * \brief Drop raster data cache : data in cache will be lost.
1691 : *
1692 : * This call will recover memory used to cache data blocks for this raster
1693 : * band, and ensure that new requests are referred to the underlying driver.
1694 : *
1695 : * This method is the same as the C function GDALDropRasterCache().
1696 : *
1697 : * @return CE_None on success.
1698 : * @since 3.9
1699 : */
1700 :
1701 1 : CPLErr GDALRasterBand::DropCache()
1702 :
1703 : {
1704 1 : CPLErr result = CE_None;
1705 :
1706 1 : if (poBandBlockCache)
1707 1 : poBandBlockCache->DisableDirtyBlockWriting();
1708 :
1709 1 : CPLErr eGlobalErr = eFlushBlockErr;
1710 :
1711 1 : if (eFlushBlockErr != CE_None)
1712 : {
1713 0 : ReportError(
1714 : eFlushBlockErr, CPLE_AppDefined,
1715 : "An error occurred while writing a dirty block from DropCache");
1716 0 : eFlushBlockErr = CE_None;
1717 : }
1718 :
1719 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1720 0 : result = eGlobalErr;
1721 : else
1722 1 : result = poBandBlockCache->FlushCache();
1723 :
1724 1 : if (poBandBlockCache)
1725 1 : poBandBlockCache->EnableDirtyBlockWriting();
1726 :
1727 1 : return result;
1728 : }
1729 :
1730 : /************************************************************************/
1731 : /* GDALDropRasterCache() */
1732 : /************************************************************************/
1733 :
1734 : /**
1735 : * \brief Drop raster data cache.
1736 : *
1737 : * @see GDALRasterBand::DropCache()
1738 : * @since 3.9
1739 : */
1740 :
1741 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1742 :
1743 : {
1744 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1745 :
1746 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1747 : }
1748 :
1749 : /************************************************************************/
1750 : /* UnreferenceBlock() */
1751 : /* */
1752 : /* Unreference the block from our array of blocks */
1753 : /* This method should only be called by */
1754 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1755 : /* the block cache mutex) */
1756 : /************************************************************************/
1757 :
1758 29642 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1759 : {
1760 : #ifdef notdef
1761 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1762 : {
1763 : if (poBandBlockCache == nullptr)
1764 : printf("poBandBlockCache == NULL\n"); /*ok*/
1765 : else
1766 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1767 : printf("caller = %s\n", pszCaller); /*ok*/
1768 : printf("GDALRasterBand: %p\n", this); /*ok*/
1769 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1770 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1771 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1772 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1773 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1774 : poBlock->DumpBlock();
1775 : if (GetDataset() != nullptr)
1776 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1777 : GDALRasterBlock::Verify();
1778 : abort();
1779 : }
1780 : #endif
1781 29642 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1782 29642 : return poBandBlockCache->UnreferenceBlock(poBlock);
1783 : }
1784 :
1785 : /************************************************************************/
1786 : /* AddBlockToFreeList() */
1787 : /* */
1788 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1789 : /* finished with a block about to be free'd, they pass it to that */
1790 : /* method. */
1791 : /************************************************************************/
1792 :
1793 : //! @cond Doxygen_Suppress
1794 29642 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1795 : {
1796 29642 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1797 29642 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1798 : }
1799 :
1800 : //! @endcond
1801 :
1802 : /************************************************************************/
1803 : /* FlushBlock() */
1804 : /************************************************************************/
1805 :
1806 : /** Flush a block out of the block cache.
1807 : * @param nXBlockOff block x offset
1808 : * @param nYBlockOff blocky offset
1809 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1810 : * @return CE_None in case of success, an error code otherwise.
1811 : */
1812 2310 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1813 : int bWriteDirtyBlock)
1814 :
1815 : {
1816 2310 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1817 0 : return (CE_Failure);
1818 :
1819 : /* -------------------------------------------------------------------- */
1820 : /* Validate the request */
1821 : /* -------------------------------------------------------------------- */
1822 2310 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1823 : {
1824 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1825 : "Illegal nBlockXOff value (%d) in "
1826 : "GDALRasterBand::FlushBlock()\n",
1827 : nXBlockOff);
1828 :
1829 0 : return (CE_Failure);
1830 : }
1831 :
1832 2310 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1833 : {
1834 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1835 : "Illegal nBlockYOff value (%d) in "
1836 : "GDALRasterBand::FlushBlock()\n",
1837 : nYBlockOff);
1838 :
1839 0 : return (CE_Failure);
1840 : }
1841 :
1842 2310 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1843 2310 : bWriteDirtyBlock);
1844 : }
1845 :
1846 : /************************************************************************/
1847 : /* TryGetLockedBlockRef() */
1848 : /************************************************************************/
1849 :
1850 : /**
1851 : * \brief Try fetching block ref.
1852 : *
1853 : * This method will returned the requested block (locked) if it is already
1854 : * in the block cache for the layer. If not, nullptr is returned.
1855 : *
1856 : * If a non-NULL value is returned, then a lock for the block will have been
1857 : * acquired on behalf of the caller. It is absolutely imperative that the
1858 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1859 : * severe problems may result.
1860 : *
1861 : * @param nXBlockOff the horizontal block offset, with zero indicating
1862 : * the left most block, 1 the next block and so forth.
1863 : *
1864 : * @param nYBlockOff the vertical block offset, with zero indicating
1865 : * the top most block, 1 the next block and so forth.
1866 : *
1867 : * @return NULL if block not available, or locked block pointer.
1868 : */
1869 :
1870 10633900 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1871 : int nYBlockOff)
1872 :
1873 : {
1874 10633900 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1875 172239 : return nullptr;
1876 :
1877 : /* -------------------------------------------------------------------- */
1878 : /* Validate the request */
1879 : /* -------------------------------------------------------------------- */
1880 10462000 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1881 : {
1882 305 : ReportError(CE_Failure, CPLE_IllegalArg,
1883 : "Illegal nBlockXOff value (%d) in "
1884 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1885 : nXBlockOff);
1886 :
1887 0 : return (nullptr);
1888 : }
1889 :
1890 10461700 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1891 : {
1892 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1893 : "Illegal nBlockYOff value (%d) in "
1894 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1895 : nYBlockOff);
1896 :
1897 0 : return (nullptr);
1898 : }
1899 :
1900 10461700 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1901 : }
1902 :
1903 : /************************************************************************/
1904 : /* GetLockedBlockRef() */
1905 : /************************************************************************/
1906 :
1907 : /**
1908 : * \brief Fetch a pointer to an internally cached raster block.
1909 : *
1910 : * This method will returned the requested block (locked) if it is already
1911 : * in the block cache for the layer. If not, the block will be read from
1912 : * the driver, and placed in the layer block cached, then returned. If an
1913 : * error occurs reading the block from the driver, a NULL value will be
1914 : * returned.
1915 : *
1916 : * If a non-NULL value is returned, then a lock for the block will have been
1917 : * acquired on behalf of the caller. It is absolutely imperative that the
1918 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1919 : * severe problems may result.
1920 : *
1921 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1922 : * enable caching.
1923 : *
1924 : * @param nXBlockOff the horizontal block offset, with zero indicating
1925 : * the left most block, 1 the next block and so forth.
1926 : *
1927 : * @param nYBlockOff the vertical block offset, with zero indicating
1928 : * the top most block, 1 the next block and so forth.
1929 : *
1930 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1931 : * but not actually read from the source. This is useful when it will just
1932 : * be completely set and written back.
1933 : *
1934 : * @return pointer to the block object, or NULL on failure.
1935 : */
1936 :
1937 10324100 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1938 : int nYBlockOff,
1939 : int bJustInitialize)
1940 :
1941 : {
1942 : /* -------------------------------------------------------------------- */
1943 : /* Try and fetch from cache. */
1944 : /* -------------------------------------------------------------------- */
1945 10324100 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1946 :
1947 : /* -------------------------------------------------------------------- */
1948 : /* If we didn't find it in our memory cache, instantiate a */
1949 : /* block (potentially load from disk) and "adopt" it into the */
1950 : /* cache. */
1951 : /* -------------------------------------------------------------------- */
1952 10325100 : if (poBlock == nullptr)
1953 : {
1954 3366560 : if (!InitBlockInfo())
1955 0 : return (nullptr);
1956 :
1957 : /* --------------------------------------------------------------------
1958 : */
1959 : /* Validate the request */
1960 : /* --------------------------------------------------------------------
1961 : */
1962 3366540 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1963 : {
1964 30 : ReportError(CE_Failure, CPLE_IllegalArg,
1965 : "Illegal nBlockXOff value (%d) in "
1966 : "GDALRasterBand::GetLockedBlockRef()\n",
1967 : nXBlockOff);
1968 :
1969 0 : return (nullptr);
1970 : }
1971 :
1972 3366500 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1973 : {
1974 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1975 : "Illegal nBlockYOff value (%d) in "
1976 : "GDALRasterBand::GetLockedBlockRef()\n",
1977 : nYBlockOff);
1978 :
1979 0 : return (nullptr);
1980 : }
1981 :
1982 3366510 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1983 3366540 : if (poBlock == nullptr)
1984 0 : return nullptr;
1985 :
1986 3366540 : poBlock->AddLock();
1987 :
1988 : /* We need to temporarily drop the read-write lock in the following */
1989 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
1990 : */
1991 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
1992 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
1993 : */
1994 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
1995 : */
1996 : /* called and attempt at taking the lock on T2 (already taken).
1997 : * Similarly */
1998 : /* for T2 with D1, hence a deadlock situation (#6163) */
1999 : /* But this may open the door to other problems... */
2000 3366540 : if (poDS)
2001 3365810 : poDS->TemporarilyDropReadWriteLock();
2002 : /* allocate data space */
2003 3366540 : CPLErr eErr = poBlock->Internalize();
2004 3366610 : if (poDS)
2005 3365860 : poDS->ReacquireReadWriteLock();
2006 3366610 : if (eErr != CE_None)
2007 : {
2008 0 : poBlock->DropLock();
2009 0 : delete poBlock;
2010 0 : return nullptr;
2011 : }
2012 :
2013 3366610 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2014 : {
2015 0 : poBlock->DropLock();
2016 0 : delete poBlock;
2017 0 : return nullptr;
2018 : }
2019 :
2020 3366610 : if (!bJustInitialize)
2021 : {
2022 2881890 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2023 2881860 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2024 2881890 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2025 2881850 : if (bCallLeaveReadWrite)
2026 130023 : LeaveReadWrite();
2027 2881840 : if (eErr != CE_None)
2028 : {
2029 1160 : poBlock->DropLock();
2030 1160 : FlushBlock(nXBlockOff, nYBlockOff);
2031 1160 : ReportError(CE_Failure, CPLE_AppDefined,
2032 : "IReadBlock failed at X offset %d, Y offset %d%s",
2033 : nXBlockOff, nYBlockOff,
2034 1160 : (nErrorCounter != CPLGetErrorCounter())
2035 1158 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2036 : : "");
2037 1160 : return nullptr;
2038 : }
2039 :
2040 2880680 : nBlockReads++;
2041 2880680 : if (static_cast<GIntBig>(nBlockReads) ==
2042 2880680 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2043 220 : 1 &&
2044 220 : nBand == 1 && poDS != nullptr)
2045 : {
2046 160 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2047 160 : poDS->GetDescription());
2048 : }
2049 : }
2050 : }
2051 :
2052 10324000 : return poBlock;
2053 : }
2054 :
2055 : /************************************************************************/
2056 : /* Fill() */
2057 : /************************************************************************/
2058 :
2059 : /**
2060 : * \brief Fill this band with a constant value.
2061 : *
2062 : * GDAL makes no guarantees
2063 : * about what values pixels in newly created files are set to, so this
2064 : * method can be used to clear a band to a specified "default" value.
2065 : * The fill value is passed in as a double but this will be converted
2066 : * to the underlying type before writing to the file. An optional
2067 : * second argument allows the imaginary component of a complex
2068 : * constant value to be specified.
2069 : *
2070 : * This method is the same as the C function GDALFillRaster().
2071 : *
2072 : * @param dfRealValue Real component of fill value
2073 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2074 : *
2075 : * @return CE_Failure if the write fails, otherwise CE_None
2076 : */
2077 268648 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2078 : {
2079 :
2080 : // General approach is to construct a source block of the file's
2081 : // native type containing the appropriate value and then copy this
2082 : // to each block in the image via the RasterBlock cache. Using
2083 : // the cache means we avoid file I/O if it is not necessary, at the
2084 : // expense of some extra memcpy's (since we write to the
2085 : // RasterBlock cache, which is then at some point written to the
2086 : // underlying file, rather than simply directly to the underlying
2087 : // file.)
2088 :
2089 : // Check we can write to the file.
2090 268648 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2091 : {
2092 6 : return CE_Failure;
2093 : }
2094 :
2095 : // Make sure block parameters are set.
2096 268642 : if (!InitBlockInfo())
2097 0 : return CE_Failure;
2098 :
2099 : // Allocate the source block.
2100 268642 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2101 268642 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2102 268642 : auto blockByteSize = blockSize * elementSize;
2103 : unsigned char *srcBlock =
2104 268642 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2105 268642 : if (srcBlock == nullptr)
2106 : {
2107 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2108 : "GDALRasterBand::Fill(): Out of memory "
2109 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2110 : static_cast<GUIntBig>(blockByteSize));
2111 0 : return CE_Failure;
2112 : }
2113 :
2114 : // Initialize the source block.
2115 268642 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2116 268642 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2117 : elementSize, blockSize);
2118 :
2119 268642 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2120 :
2121 : // Write block to block cache
2122 871119 : for (int j = 0; j < nBlocksPerColumn; ++j)
2123 : {
2124 1499290 : for (int i = 0; i < nBlocksPerRow; ++i)
2125 : {
2126 896810 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2127 896810 : if (destBlock == nullptr)
2128 : {
2129 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2130 : "GDALRasterBand::Fill(): Error "
2131 : "while retrieving cache block.");
2132 0 : VSIFree(srcBlock);
2133 0 : return CE_Failure;
2134 : }
2135 896810 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2136 896810 : destBlock->MarkDirty();
2137 896810 : destBlock->DropLock();
2138 : }
2139 : }
2140 :
2141 268642 : if (bCallLeaveReadWrite)
2142 267633 : LeaveReadWrite();
2143 :
2144 : // Free up the source block
2145 268642 : VSIFree(srcBlock);
2146 :
2147 268642 : return CE_None;
2148 : }
2149 :
2150 : /************************************************************************/
2151 : /* GDALFillRaster() */
2152 : /************************************************************************/
2153 :
2154 : /**
2155 : * \brief Fill this band with a constant value.
2156 : *
2157 : * @see GDALRasterBand::Fill()
2158 : */
2159 268580 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2160 : double dfImaginaryValue)
2161 : {
2162 268580 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2163 :
2164 268580 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2165 268580 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2166 : }
2167 :
2168 : /************************************************************************/
2169 : /* GetAccess() */
2170 : /************************************************************************/
2171 :
2172 : /**
2173 : * \brief Find out if we have update permission for this band.
2174 : *
2175 : * This method is the same as the C function GDALGetRasterAccess().
2176 : *
2177 : * @return Either GA_Update or GA_ReadOnly.
2178 : */
2179 :
2180 2975 : GDALAccess GDALRasterBand::GetAccess()
2181 :
2182 : {
2183 2975 : return eAccess;
2184 : }
2185 :
2186 : /************************************************************************/
2187 : /* GDALGetRasterAccess() */
2188 : /************************************************************************/
2189 :
2190 : /**
2191 : * \brief Find out if we have update permission for this band.
2192 : *
2193 : * @see GDALRasterBand::GetAccess()
2194 : */
2195 :
2196 2324 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2197 :
2198 : {
2199 2324 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2200 :
2201 2324 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2202 2324 : return poBand->GetAccess();
2203 : }
2204 :
2205 : /************************************************************************/
2206 : /* GetCategoryNames() */
2207 : /************************************************************************/
2208 :
2209 : /**
2210 : * \brief Fetch the list of category names for this raster.
2211 : *
2212 : * The return list is a "StringList" in the sense of the CPL functions.
2213 : * That is a NULL terminated array of strings. Raster values without
2214 : * associated names will have an empty string in the returned list. The
2215 : * first entry in the list is for raster values of zero, and so on.
2216 : *
2217 : * The returned stringlist should not be altered or freed by the application.
2218 : * It may change on the next GDAL call, so please copy it if it is needed
2219 : * for any period of time.
2220 : *
2221 : * This method is the same as the C function GDALGetRasterCategoryNames().
2222 : *
2223 : * @return list of names, or NULL if none.
2224 : */
2225 :
2226 297 : char **GDALRasterBand::GetCategoryNames()
2227 :
2228 : {
2229 297 : return nullptr;
2230 : }
2231 :
2232 : /************************************************************************/
2233 : /* GDALGetRasterCategoryNames() */
2234 : /************************************************************************/
2235 :
2236 : /**
2237 : * \brief Fetch the list of category names for this raster.
2238 : *
2239 : * @see GDALRasterBand::GetCategoryNames()
2240 : */
2241 :
2242 191 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2243 :
2244 : {
2245 191 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2246 :
2247 191 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2248 191 : return poBand->GetCategoryNames();
2249 : }
2250 :
2251 : /************************************************************************/
2252 : /* SetCategoryNames() */
2253 : /************************************************************************/
2254 :
2255 : /**
2256 : * \fn GDALRasterBand::SetCategoryNames(char**)
2257 : * \brief Set the category names for this band.
2258 : *
2259 : * See the GetCategoryNames() method for more on the interpretation of
2260 : * category names.
2261 : *
2262 : * This method is the same as the C function GDALSetRasterCategoryNames().
2263 : *
2264 : * @param papszNames the NULL terminated StringList of category names. May
2265 : * be NULL to just clear the existing list.
2266 : *
2267 : * @return CE_None on success of CE_Failure on failure. If unsupported
2268 : * by the driver CE_Failure is returned, but no error message is reported.
2269 : */
2270 :
2271 : /**/
2272 : /**/
2273 :
2274 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2275 : {
2276 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2277 0 : ReportError(CE_Failure, CPLE_NotSupported,
2278 : "SetCategoryNames() not supported for this dataset.");
2279 :
2280 0 : return CE_Failure;
2281 : }
2282 :
2283 : /************************************************************************/
2284 : /* GDALSetCategoryNames() */
2285 : /************************************************************************/
2286 :
2287 : /**
2288 : * \brief Set the category names for this band.
2289 : *
2290 : * @see GDALRasterBand::SetCategoryNames()
2291 : */
2292 :
2293 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2294 : CSLConstList papszNames)
2295 :
2296 : {
2297 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2298 :
2299 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2300 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2301 : }
2302 :
2303 : /************************************************************************/
2304 : /* GetNoDataValue() */
2305 : /************************************************************************/
2306 :
2307 : /**
2308 : * \brief Fetch the no data value for this band.
2309 : *
2310 : * If there is no out of data value, an out of range value will generally
2311 : * be returned. The no data value for a band is generally a special marker
2312 : * value used to mark pixels that are not valid data. Such pixels should
2313 : * generally not be displayed, nor contribute to analysis operations.
2314 : *
2315 : * The no data value returned is 'raw', meaning that it has no offset and
2316 : * scale applied.
2317 : *
2318 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2319 : * lossy if the nodata value cannot exactly been represented by a double.
2320 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2321 : *
2322 : * This method is the same as the C function GDALGetRasterNoDataValue().
2323 : *
2324 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2325 : * is actually associated with this layer. May be NULL (default).
2326 : *
2327 : * @return the nodata value for this band.
2328 : */
2329 :
2330 31582 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2331 :
2332 : {
2333 31582 : if (pbSuccess != nullptr)
2334 31582 : *pbSuccess = FALSE;
2335 :
2336 31582 : return -1e10;
2337 : }
2338 :
2339 : /************************************************************************/
2340 : /* GDALGetRasterNoDataValue() */
2341 : /************************************************************************/
2342 :
2343 : /**
2344 : * \brief Fetch the no data value for this band.
2345 : *
2346 : * @see GDALRasterBand::GetNoDataValue()
2347 : */
2348 :
2349 414357 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2350 : int *pbSuccess)
2351 :
2352 : {
2353 414357 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2354 :
2355 414357 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2356 414357 : return poBand->GetNoDataValue(pbSuccess);
2357 : }
2358 :
2359 : /************************************************************************/
2360 : /* GetNoDataValueAsInt64() */
2361 : /************************************************************************/
2362 :
2363 : /**
2364 : * \brief Fetch the no data value for this band.
2365 : *
2366 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2367 : *
2368 : * If there is no out of data value, an out of range value will generally
2369 : * be returned. The no data value for a band is generally a special marker
2370 : * value used to mark pixels that are not valid data. Such pixels should
2371 : * generally not be displayed, nor contribute to analysis operations.
2372 : *
2373 : * The no data value returned is 'raw', meaning that it has no offset and
2374 : * scale applied.
2375 : *
2376 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2377 : *
2378 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2379 : * is actually associated with this layer. May be NULL (default).
2380 : *
2381 : * @return the nodata value for this band.
2382 : *
2383 : * @since GDAL 3.5
2384 : */
2385 :
2386 5 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2387 :
2388 : {
2389 5 : if (pbSuccess != nullptr)
2390 5 : *pbSuccess = FALSE;
2391 :
2392 5 : return std::numeric_limits<int64_t>::min();
2393 : }
2394 :
2395 : /************************************************************************/
2396 : /* GDALGetRasterNoDataValueAsInt64() */
2397 : /************************************************************************/
2398 :
2399 : /**
2400 : * \brief Fetch the no data value for this band.
2401 : *
2402 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2403 : *
2404 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2405 : *
2406 : * @since GDAL 3.5
2407 : */
2408 :
2409 31 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2410 : int *pbSuccess)
2411 :
2412 : {
2413 31 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2414 : std::numeric_limits<int64_t>::min());
2415 :
2416 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2417 31 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2418 : }
2419 :
2420 : /************************************************************************/
2421 : /* GetNoDataValueAsUInt64() */
2422 : /************************************************************************/
2423 :
2424 : /**
2425 : * \brief Fetch the no data value for this band.
2426 : *
2427 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2428 : *
2429 : * If there is no out of data value, an out of range value will generally
2430 : * be returned. The no data value for a band is generally a special marker
2431 : * value used to mark pixels that are not valid data. Such pixels should
2432 : * generally not be displayed, nor contribute to analysis operations.
2433 : *
2434 : * The no data value returned is 'raw', meaning that it has no offset and
2435 : * scale applied.
2436 : *
2437 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2438 : *
2439 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2440 : * is actually associated with this layer. May be NULL (default).
2441 : *
2442 : * @return the nodata value for this band.
2443 : *
2444 : * @since GDAL 3.5
2445 : */
2446 :
2447 4 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2448 :
2449 : {
2450 4 : if (pbSuccess != nullptr)
2451 4 : *pbSuccess = FALSE;
2452 :
2453 4 : return std::numeric_limits<uint64_t>::max();
2454 : }
2455 :
2456 : /************************************************************************/
2457 : /* GDALGetRasterNoDataValueAsUInt64() */
2458 : /************************************************************************/
2459 :
2460 : /**
2461 : * \brief Fetch the no data value for this band.
2462 : *
2463 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2464 : *
2465 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2466 : *
2467 : * @since GDAL 3.5
2468 : */
2469 :
2470 22 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2471 : int *pbSuccess)
2472 :
2473 : {
2474 22 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2475 : std::numeric_limits<uint64_t>::max());
2476 :
2477 22 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2478 22 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2479 : }
2480 :
2481 : /************************************************************************/
2482 : /* SetNoDataValueAsString() */
2483 : /************************************************************************/
2484 :
2485 : /**
2486 : * \brief Set the no data value for this band.
2487 : *
2488 : * Depending on drivers, changing the no data value may or may not have an
2489 : * effect on the pixel values of a raster that has just been created. It is
2490 : * thus advised to explicitly called Fill() if the intent is to initialize
2491 : * the raster to the nodata value.
2492 : * In any case, changing an existing no data value, when one already exists and
2493 : * the dataset exists or has been initialized, has no effect on the pixel whose
2494 : * value matched the previous nodata value.
2495 : *
2496 : * To clear the nodata value, use DeleteNoDataValue().
2497 : *
2498 : * @param pszNoData the value to set.
2499 : * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2500 : * If the value cannot be exactly represented on the output data
2501 : * type, *pbCannotBeExactlyRepresented will be set to true.
2502 : *
2503 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2504 : * by the driver, CE_Failure is returned but no error message will have
2505 : * been emitted.
2506 : *
2507 : * @since 3.11
2508 : */
2509 :
2510 : CPLErr
2511 123 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2512 : bool *pbCannotBeExactlyRepresented)
2513 : {
2514 123 : if (pbCannotBeExactlyRepresented)
2515 123 : *pbCannotBeExactlyRepresented = false;
2516 123 : if (eDataType == GDT_Int64)
2517 : {
2518 8 : if (strchr(pszNoData, '.') ||
2519 3 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2520 : {
2521 2 : char *endptr = nullptr;
2522 2 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2523 4 : if (endptr == pszNoData + strlen(pszNoData) &&
2524 2 : GDALIsValueExactAs<int64_t>(dfVal))
2525 : {
2526 0 : return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2527 : }
2528 : }
2529 : else
2530 : {
2531 : try
2532 : {
2533 7 : const auto val = std::stoll(pszNoData);
2534 1 : return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2535 : }
2536 2 : catch (const std::exception &)
2537 : {
2538 : }
2539 : }
2540 : }
2541 118 : else if (eDataType == GDT_UInt64)
2542 : {
2543 2 : if (strchr(pszNoData, '.') ||
2544 1 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2545 : {
2546 0 : char *endptr = nullptr;
2547 0 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2548 0 : if (endptr == pszNoData + strlen(pszNoData) &&
2549 0 : GDALIsValueExactAs<uint64_t>(dfVal))
2550 : {
2551 0 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2552 : }
2553 : }
2554 : else
2555 : {
2556 : try
2557 : {
2558 1 : const auto val = std::stoull(pszNoData);
2559 1 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2560 : }
2561 0 : catch (const std::exception &)
2562 : {
2563 : }
2564 : }
2565 : }
2566 117 : else if (eDataType == GDT_Float32)
2567 : {
2568 10 : char *endptr = nullptr;
2569 10 : const float fVal = CPLStrtof(pszNoData, &endptr);
2570 10 : if (endptr == pszNoData + strlen(pszNoData))
2571 : {
2572 10 : return SetNoDataValue(double(fVal));
2573 : }
2574 : }
2575 : else
2576 : {
2577 107 : char *endptr = nullptr;
2578 107 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2579 214 : if (endptr == pszNoData + strlen(pszNoData) &&
2580 107 : GDALIsValueExactAs(dfVal, eDataType))
2581 : {
2582 106 : return SetNoDataValue(dfVal);
2583 : }
2584 : }
2585 5 : if (pbCannotBeExactlyRepresented)
2586 5 : *pbCannotBeExactlyRepresented = true;
2587 5 : return CE_Failure;
2588 : }
2589 :
2590 : /************************************************************************/
2591 : /* SetNoDataValue() */
2592 : /************************************************************************/
2593 :
2594 : /**
2595 : * \fn GDALRasterBand::SetNoDataValue(double)
2596 : * \brief Set the no data value for this band.
2597 : *
2598 : * Depending on drivers, changing the no data value may or may not have an
2599 : * effect on the pixel values of a raster that has just been created. It is
2600 : * thus advised to explicitly called Fill() if the intent is to initialize
2601 : * the raster to the nodata value.
2602 : * In any case, changing an existing no data value, when one already exists and
2603 : * the dataset exists or has been initialized, has no effect on the pixel whose
2604 : * value matched the previous nodata value.
2605 : *
2606 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2607 : * be represented by a double, use SetNoDataValueAsInt64() or
2608 : * SetNoDataValueAsUInt64() instead.
2609 : *
2610 : * To clear the nodata value, use DeleteNoDataValue().
2611 : *
2612 : * This method is the same as the C function GDALSetRasterNoDataValue().
2613 : *
2614 : * @param dfNoData the value to set.
2615 : *
2616 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2617 : * by the driver, CE_Failure is returned but no error message will have
2618 : * been emitted.
2619 : */
2620 :
2621 : /**/
2622 : /**/
2623 :
2624 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2625 :
2626 : {
2627 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2628 0 : ReportError(CE_Failure, CPLE_NotSupported,
2629 : "SetNoDataValue() not supported for this dataset.");
2630 :
2631 0 : return CE_Failure;
2632 : }
2633 :
2634 : /************************************************************************/
2635 : /* GDALSetRasterNoDataValue() */
2636 : /************************************************************************/
2637 :
2638 : /**
2639 : * \brief Set the no data value for this band.
2640 : *
2641 : * Depending on drivers, changing the no data value may or may not have an
2642 : * effect on the pixel values of a raster that has just been created. It is
2643 : * thus advised to explicitly called Fill() if the intent is to initialize
2644 : * the raster to the nodata value.
2645 : * In any case, changing an existing no data value, when one already exists and
2646 : * the dataset exists or has been initialized, has no effect on the pixel whose
2647 : * value matched the previous nodata value.
2648 : *
2649 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2650 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2651 : * GDALSetRasterNoDataValueAsUInt64() instead.
2652 : *
2653 : * @see GDALRasterBand::SetNoDataValue()
2654 : */
2655 :
2656 867 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2657 : double dfValue)
2658 :
2659 : {
2660 867 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2661 :
2662 867 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2663 867 : return poBand->SetNoDataValue(dfValue);
2664 : }
2665 :
2666 : /************************************************************************/
2667 : /* SetNoDataValueAsInt64() */
2668 : /************************************************************************/
2669 :
2670 : /**
2671 : * \brief Set the no data value for this band.
2672 : *
2673 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2674 : *
2675 : * Depending on drivers, changing the no data value may or may not have an
2676 : * effect on the pixel values of a raster that has just been created. It is
2677 : * thus advised to explicitly called Fill() if the intent is to initialize
2678 : * the raster to the nodata value.
2679 : * In ay case, changing an existing no data value, when one already exists and
2680 : * the dataset exists or has been initialized, has no effect on the pixel whose
2681 : * value matched the previous nodata value.
2682 : *
2683 : * To clear the nodata value, use DeleteNoDataValue().
2684 : *
2685 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2686 : *
2687 : * @param nNoDataValue the value to set.
2688 : *
2689 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2690 : * by the driver, CE_Failure is returned but no error message will have
2691 : * been emitted.
2692 : *
2693 : * @since GDAL 3.5
2694 : */
2695 :
2696 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2697 :
2698 : {
2699 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2700 0 : ReportError(CE_Failure, CPLE_NotSupported,
2701 : "SetNoDataValueAsInt64() not supported for this dataset.");
2702 :
2703 0 : return CE_Failure;
2704 : }
2705 :
2706 : /************************************************************************/
2707 : /* GDALSetRasterNoDataValueAsInt64() */
2708 : /************************************************************************/
2709 :
2710 : /**
2711 : * \brief Set the no data value for this band.
2712 : *
2713 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2714 : *
2715 : * Depending on drivers, changing the no data value may or may not have an
2716 : * effect on the pixel values of a raster that has just been created. It is
2717 : * thus advised to explicitly called Fill() if the intent is to initialize
2718 : * the raster to the nodata value.
2719 : * In ay case, changing an existing no data value, when one already exists and
2720 : * the dataset exists or has been initialized, has no effect on the pixel whose
2721 : * value matched the previous nodata value.
2722 : *
2723 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2724 : *
2725 : * @since GDAL 3.5
2726 : */
2727 :
2728 22 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2729 : int64_t nValue)
2730 :
2731 : {
2732 22 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2733 :
2734 22 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2735 22 : return poBand->SetNoDataValueAsInt64(nValue);
2736 : }
2737 :
2738 : /************************************************************************/
2739 : /* SetNoDataValueAsUInt64() */
2740 : /************************************************************************/
2741 :
2742 : /**
2743 : * \brief Set the no data value for this band.
2744 : *
2745 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2746 : *
2747 : * Depending on drivers, changing the no data value may or may not have an
2748 : * effect on the pixel values of a raster that has just been created. It is
2749 : * thus advised to explicitly called Fill() if the intent is to initialize
2750 : * the raster to the nodata value.
2751 : * In ay case, changing an existing no data value, when one already exists and
2752 : * the dataset exists or has been initialized, has no effect on the pixel whose
2753 : * value matched the previous nodata value.
2754 : *
2755 : * To clear the nodata value, use DeleteNoDataValue().
2756 : *
2757 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2758 : *
2759 : * @param nNoDataValue the value to set.
2760 : *
2761 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2762 : * by the driver, CE_Failure is returned but no error message will have
2763 : * been emitted.
2764 : *
2765 : * @since GDAL 3.5
2766 : */
2767 :
2768 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2769 :
2770 : {
2771 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2772 0 : ReportError(CE_Failure, CPLE_NotSupported,
2773 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2774 :
2775 0 : return CE_Failure;
2776 : }
2777 :
2778 : /************************************************************************/
2779 : /* GDALSetRasterNoDataValueAsUInt64() */
2780 : /************************************************************************/
2781 :
2782 : /**
2783 : * \brief Set the no data value for this band.
2784 : *
2785 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2786 : *
2787 : * Depending on drivers, changing the no data value may or may not have an
2788 : * effect on the pixel values of a raster that has just been created. It is
2789 : * thus advised to explicitly called Fill() if the intent is to initialize
2790 : * the raster to the nodata value.
2791 : * In ay case, changing an existing no data value, when one already exists and
2792 : * the dataset exists or has been initialized, has no effect on the pixel whose
2793 : * value matched the previous nodata value.
2794 : *
2795 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2796 : *
2797 : * @since GDAL 3.5
2798 : */
2799 :
2800 20 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2801 : uint64_t nValue)
2802 :
2803 : {
2804 20 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2805 :
2806 20 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2807 20 : return poBand->SetNoDataValueAsUInt64(nValue);
2808 : }
2809 :
2810 : /************************************************************************/
2811 : /* DeleteNoDataValue() */
2812 : /************************************************************************/
2813 :
2814 : /**
2815 : * \brief Remove the no data value for this band.
2816 : *
2817 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2818 : *
2819 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2820 : * by the driver, CE_Failure is returned but no error message will have
2821 : * been emitted.
2822 : *
2823 : * @since GDAL 2.1
2824 : */
2825 :
2826 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2827 :
2828 : {
2829 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2830 0 : ReportError(CE_Failure, CPLE_NotSupported,
2831 : "DeleteNoDataValue() not supported for this dataset.");
2832 :
2833 0 : return CE_Failure;
2834 : }
2835 :
2836 : /************************************************************************/
2837 : /* GDALDeleteRasterNoDataValue() */
2838 : /************************************************************************/
2839 :
2840 : /**
2841 : * \brief Remove the no data value for this band.
2842 : *
2843 : * @see GDALRasterBand::DeleteNoDataValue()
2844 : *
2845 : * @since GDAL 2.1
2846 : */
2847 :
2848 53 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2849 :
2850 : {
2851 53 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2852 :
2853 53 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2854 53 : return poBand->DeleteNoDataValue();
2855 : }
2856 :
2857 : /************************************************************************/
2858 : /* GetMaximum() */
2859 : /************************************************************************/
2860 :
2861 : /**
2862 : * \brief Fetch the maximum value for this band.
2863 : *
2864 : * For file formats that don't know this intrinsically, the maximum supported
2865 : * value for the data type will generally be returned.
2866 : *
2867 : * This method is the same as the C function GDALGetRasterMaximum().
2868 : *
2869 : * @param pbSuccess pointer to a boolean to use to indicate if the
2870 : * returned value is a tight maximum or not. May be NULL (default).
2871 : *
2872 : * @return the maximum raster value (excluding no data pixels)
2873 : */
2874 :
2875 525 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2876 :
2877 : {
2878 525 : const char *pszValue = nullptr;
2879 :
2880 525 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2881 : {
2882 47 : if (pbSuccess != nullptr)
2883 42 : *pbSuccess = TRUE;
2884 :
2885 47 : return CPLAtofM(pszValue);
2886 : }
2887 :
2888 478 : if (pbSuccess != nullptr)
2889 474 : *pbSuccess = FALSE;
2890 :
2891 478 : switch (eDataType)
2892 : {
2893 327 : case GDT_Byte:
2894 : {
2895 327 : EnablePixelTypeSignedByteWarning(false);
2896 : const char *pszPixelType =
2897 327 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2898 327 : EnablePixelTypeSignedByteWarning(true);
2899 327 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2900 0 : return 127;
2901 :
2902 327 : return 255;
2903 : }
2904 :
2905 1 : case GDT_Int8:
2906 1 : return 127;
2907 :
2908 21 : case GDT_UInt16:
2909 21 : return 65535;
2910 :
2911 24 : case GDT_Int16:
2912 : case GDT_CInt16:
2913 24 : return 32767;
2914 :
2915 39 : case GDT_Int32:
2916 : case GDT_CInt32:
2917 39 : return 2147483647.0;
2918 :
2919 12 : case GDT_UInt32:
2920 12 : return 4294967295.0;
2921 :
2922 1 : case GDT_Int64:
2923 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2924 :
2925 1 : case GDT_UInt64:
2926 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2927 :
2928 0 : case GDT_Float16:
2929 : case GDT_CFloat16:
2930 0 : return 65504.0;
2931 :
2932 30 : case GDT_Float32:
2933 : case GDT_CFloat32:
2934 30 : return 4294967295.0; // Not actually accurate.
2935 :
2936 22 : case GDT_Float64:
2937 : case GDT_CFloat64:
2938 22 : return 4294967295.0; // Not actually accurate.
2939 :
2940 0 : case GDT_Unknown:
2941 : case GDT_TypeCount:
2942 0 : break;
2943 : }
2944 0 : return 4294967295.0; // Not actually accurate.
2945 : }
2946 :
2947 : /************************************************************************/
2948 : /* GDALGetRasterMaximum() */
2949 : /************************************************************************/
2950 :
2951 : /**
2952 : * \brief Fetch the maximum value for this band.
2953 : *
2954 : * @see GDALRasterBand::GetMaximum()
2955 : */
2956 :
2957 324 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2958 :
2959 : {
2960 324 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2961 :
2962 324 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2963 324 : return poBand->GetMaximum(pbSuccess);
2964 : }
2965 :
2966 : /************************************************************************/
2967 : /* GetMinimum() */
2968 : /************************************************************************/
2969 :
2970 : /**
2971 : * \brief Fetch the minimum value for this band.
2972 : *
2973 : * For file formats that don't know this intrinsically, the minimum supported
2974 : * value for the data type will generally be returned.
2975 : *
2976 : * This method is the same as the C function GDALGetRasterMinimum().
2977 : *
2978 : * @param pbSuccess pointer to a boolean to use to indicate if the
2979 : * returned value is a tight minimum or not. May be NULL (default).
2980 : *
2981 : * @return the minimum raster value (excluding no data pixels)
2982 : */
2983 :
2984 533 : double GDALRasterBand::GetMinimum(int *pbSuccess)
2985 :
2986 : {
2987 533 : const char *pszValue = nullptr;
2988 :
2989 533 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
2990 : {
2991 52 : if (pbSuccess != nullptr)
2992 47 : *pbSuccess = TRUE;
2993 :
2994 52 : return CPLAtofM(pszValue);
2995 : }
2996 :
2997 481 : if (pbSuccess != nullptr)
2998 477 : *pbSuccess = FALSE;
2999 :
3000 481 : switch (eDataType)
3001 : {
3002 330 : case GDT_Byte:
3003 : {
3004 330 : EnablePixelTypeSignedByteWarning(false);
3005 : const char *pszPixelType =
3006 330 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3007 330 : EnablePixelTypeSignedByteWarning(true);
3008 330 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3009 0 : return -128;
3010 :
3011 330 : return 0;
3012 : }
3013 :
3014 1 : case GDT_Int8:
3015 1 : return -128;
3016 :
3017 21 : case GDT_UInt16:
3018 21 : return 0;
3019 :
3020 24 : case GDT_Int16:
3021 : case GDT_CInt16:
3022 24 : return -32768;
3023 :
3024 39 : case GDT_Int32:
3025 : case GDT_CInt32:
3026 39 : return -2147483648.0;
3027 :
3028 12 : case GDT_UInt32:
3029 12 : return 0;
3030 :
3031 1 : case GDT_Int64:
3032 1 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3033 :
3034 1 : case GDT_UInt64:
3035 1 : return 0;
3036 :
3037 0 : case GDT_Float16:
3038 : case GDT_CFloat16:
3039 0 : return -65504.0;
3040 :
3041 30 : case GDT_Float32:
3042 : case GDT_CFloat32:
3043 30 : return -4294967295.0; // Not actually accurate.
3044 :
3045 22 : case GDT_Float64:
3046 : case GDT_CFloat64:
3047 22 : return -4294967295.0; // Not actually accurate.
3048 :
3049 0 : case GDT_Unknown:
3050 : case GDT_TypeCount:
3051 0 : break;
3052 : }
3053 0 : return -4294967295.0; // Not actually accurate.
3054 : }
3055 :
3056 : /************************************************************************/
3057 : /* GDALGetRasterMinimum() */
3058 : /************************************************************************/
3059 :
3060 : /**
3061 : * \brief Fetch the minimum value for this band.
3062 : *
3063 : * @see GDALRasterBand::GetMinimum()
3064 : */
3065 :
3066 334 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3067 :
3068 : {
3069 334 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3070 :
3071 334 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3072 334 : return poBand->GetMinimum(pbSuccess);
3073 : }
3074 :
3075 : /************************************************************************/
3076 : /* GetColorInterpretation() */
3077 : /************************************************************************/
3078 :
3079 : /**
3080 : * \brief How should this band be interpreted as color?
3081 : *
3082 : * GCI_Undefined is returned when the format doesn't know anything
3083 : * about the color interpretation.
3084 : *
3085 : * This method is the same as the C function
3086 : * GDALGetRasterColorInterpretation().
3087 : *
3088 : * @return color interpretation value for band.
3089 : */
3090 :
3091 163 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
3092 :
3093 : {
3094 163 : return GCI_Undefined;
3095 : }
3096 :
3097 : /************************************************************************/
3098 : /* GDALGetRasterColorInterpretation() */
3099 : /************************************************************************/
3100 :
3101 : /**
3102 : * \brief How should this band be interpreted as color?
3103 : *
3104 : * @see GDALRasterBand::GetColorInterpretation()
3105 : */
3106 :
3107 : GDALColorInterp CPL_STDCALL
3108 5606 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3109 :
3110 : {
3111 5606 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3112 :
3113 5606 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3114 5606 : return poBand->GetColorInterpretation();
3115 : }
3116 :
3117 : /************************************************************************/
3118 : /* SetColorInterpretation() */
3119 : /************************************************************************/
3120 :
3121 : /**
3122 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3123 : * \brief Set color interpretation of a band.
3124 : *
3125 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3126 : *
3127 : * @param eColorInterp the new color interpretation to apply to this band.
3128 : *
3129 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3130 : */
3131 :
3132 : /**/
3133 : /**/
3134 :
3135 3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3136 :
3137 : {
3138 3 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3139 3 : ReportError(CE_Failure, CPLE_NotSupported,
3140 : "SetColorInterpretation() not supported for this dataset.");
3141 3 : return CE_Failure;
3142 : }
3143 :
3144 : /************************************************************************/
3145 : /* GDALSetRasterColorInterpretation() */
3146 : /************************************************************************/
3147 :
3148 : /**
3149 : * \brief Set color interpretation of a band.
3150 : *
3151 : * @see GDALRasterBand::SetColorInterpretation()
3152 : */
3153 :
3154 1839 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3155 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3156 :
3157 : {
3158 1839 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3159 :
3160 1839 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3161 1839 : return poBand->SetColorInterpretation(eColorInterp);
3162 : }
3163 :
3164 : /************************************************************************/
3165 : /* GetColorTable() */
3166 : /************************************************************************/
3167 :
3168 : /**
3169 : * \brief Fetch the color table associated with band.
3170 : *
3171 : * If there is no associated color table, the return result is NULL. The
3172 : * returned color table remains owned by the GDALRasterBand, and can't
3173 : * be depended on for long, nor should it ever be modified by the caller.
3174 : *
3175 : * This method is the same as the C function GDALGetRasterColorTable().
3176 : *
3177 : * @return internal color table, or NULL.
3178 : */
3179 :
3180 234 : GDALColorTable *GDALRasterBand::GetColorTable()
3181 :
3182 : {
3183 234 : return nullptr;
3184 : }
3185 :
3186 : /************************************************************************/
3187 : /* GDALGetRasterColorTable() */
3188 : /************************************************************************/
3189 :
3190 : /**
3191 : * \brief Fetch the color table associated with band.
3192 : *
3193 : * @see GDALRasterBand::GetColorTable()
3194 : */
3195 :
3196 1971 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3197 :
3198 : {
3199 1971 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3200 :
3201 1971 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3202 1971 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3203 : }
3204 :
3205 : /************************************************************************/
3206 : /* SetColorTable() */
3207 : /************************************************************************/
3208 :
3209 : /**
3210 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3211 : * \brief Set the raster color table.
3212 : *
3213 : * The driver will make a copy of all desired data in the colortable. It
3214 : * remains owned by the caller after the call.
3215 : *
3216 : * This method is the same as the C function GDALSetRasterColorTable().
3217 : *
3218 : * @param poCT the color table to apply. This may be NULL to clear the color
3219 : * table (where supported).
3220 : *
3221 : * @return CE_None on success, or CE_Failure on failure. If the action is
3222 : * unsupported by the driver, a value of CE_Failure is returned, but no
3223 : * error is issued.
3224 : */
3225 :
3226 : /**/
3227 : /**/
3228 :
3229 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3230 :
3231 : {
3232 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3233 0 : ReportError(CE_Failure, CPLE_NotSupported,
3234 : "SetColorTable() not supported for this dataset.");
3235 0 : return CE_Failure;
3236 : }
3237 :
3238 : /************************************************************************/
3239 : /* GDALSetRasterColorTable() */
3240 : /************************************************************************/
3241 :
3242 : /**
3243 : * \brief Set the raster color table.
3244 : *
3245 : * @see GDALRasterBand::SetColorTable()
3246 : */
3247 :
3248 78 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3249 : GDALColorTableH hCT)
3250 :
3251 : {
3252 78 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3253 :
3254 78 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3255 78 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3256 : }
3257 :
3258 : /************************************************************************/
3259 : /* HasArbitraryOverviews() */
3260 : /************************************************************************/
3261 :
3262 : /**
3263 : * \brief Check for arbitrary overviews.
3264 : *
3265 : * This returns TRUE if the underlying datastore can compute arbitrary
3266 : * overviews efficiently, such as is the case with OGDI over a network.
3267 : * Datastores with arbitrary overviews don't generally have any fixed
3268 : * overviews, but the RasterIO() method can be used in downsampling mode
3269 : * to get overview data efficiently.
3270 : *
3271 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3272 : *
3273 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3274 : * FALSE.
3275 : */
3276 :
3277 260 : int GDALRasterBand::HasArbitraryOverviews()
3278 :
3279 : {
3280 260 : return FALSE;
3281 : }
3282 :
3283 : /************************************************************************/
3284 : /* GDALHasArbitraryOverviews() */
3285 : /************************************************************************/
3286 :
3287 : /**
3288 : * \brief Check for arbitrary overviews.
3289 : *
3290 : * @see GDALRasterBand::HasArbitraryOverviews()
3291 : */
3292 :
3293 181 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3294 :
3295 : {
3296 181 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3297 :
3298 181 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3299 181 : return poBand->HasArbitraryOverviews();
3300 : }
3301 :
3302 : /************************************************************************/
3303 : /* GetOverviewCount() */
3304 : /************************************************************************/
3305 :
3306 : /**
3307 : * \brief Return the number of overview layers available.
3308 : *
3309 : * This method is the same as the C function GDALGetOverviewCount().
3310 : *
3311 : * @return overview count, zero if none.
3312 : */
3313 :
3314 1066300 : int GDALRasterBand::GetOverviewCount()
3315 :
3316 : {
3317 1723040 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3318 656736 : poDS->AreOverviewsEnabled())
3319 656737 : return poDS->oOvManager.GetOverviewCount(nBand);
3320 :
3321 409560 : return 0;
3322 : }
3323 :
3324 : /************************************************************************/
3325 : /* GDALGetOverviewCount() */
3326 : /************************************************************************/
3327 :
3328 : /**
3329 : * \brief Return the number of overview layers available.
3330 : *
3331 : * @see GDALRasterBand::GetOverviewCount()
3332 : */
3333 :
3334 3289 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3335 :
3336 : {
3337 3289 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3338 :
3339 3289 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3340 3289 : return poBand->GetOverviewCount();
3341 : }
3342 :
3343 : /************************************************************************/
3344 : /* GetOverview() */
3345 : /************************************************************************/
3346 :
3347 : /**
3348 : * \brief Fetch overview raster band object.
3349 : *
3350 : * This method is the same as the C function GDALGetOverview().
3351 : *
3352 : * @param i overview index between 0 and GetOverviewCount()-1.
3353 : *
3354 : * @return overview GDALRasterBand.
3355 : */
3356 :
3357 846 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3358 :
3359 : {
3360 1636 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3361 790 : poDS->AreOverviewsEnabled())
3362 790 : return poDS->oOvManager.GetOverview(nBand, i);
3363 :
3364 56 : return nullptr;
3365 : }
3366 :
3367 : /************************************************************************/
3368 : /* GDALGetOverview() */
3369 : /************************************************************************/
3370 :
3371 : /**
3372 : * \brief Fetch overview raster band object.
3373 : *
3374 : * @see GDALRasterBand::GetOverview()
3375 : */
3376 :
3377 5658 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3378 :
3379 : {
3380 5658 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3381 :
3382 5658 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3383 5658 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3384 : }
3385 :
3386 : /************************************************************************/
3387 : /* GetRasterSampleOverview() */
3388 : /************************************************************************/
3389 :
3390 : /**
3391 : * \brief Fetch best sampling overview.
3392 : *
3393 : * Returns the most reduced overview of the given band that still satisfies
3394 : * the desired number of samples. This function can be used with zero
3395 : * as the number of desired samples to fetch the most reduced overview.
3396 : * The same band as was passed in will be returned if it has not overviews,
3397 : * or if none of the overviews have enough samples.
3398 : *
3399 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3400 : * and GDALGetRasterSampleOverviewEx().
3401 : *
3402 : * @param nDesiredSamples the returned band will have at least this many
3403 : * pixels.
3404 : *
3405 : * @return optimal overview or the band itself.
3406 : */
3407 :
3408 : GDALRasterBand *
3409 2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3410 :
3411 : {
3412 2006 : GDALRasterBand *poBestBand = this;
3413 :
3414 2006 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3415 :
3416 4023 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3417 : {
3418 2017 : GDALRasterBand *poOBand = GetOverview(iOverview);
3419 :
3420 2017 : if (poOBand == nullptr)
3421 0 : continue;
3422 :
3423 : const double dfOSamples =
3424 2017 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3425 :
3426 2017 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3427 : {
3428 2014 : dfBestSamples = dfOSamples;
3429 2014 : poBestBand = poOBand;
3430 : }
3431 : }
3432 :
3433 2006 : return poBestBand;
3434 : }
3435 :
3436 : /************************************************************************/
3437 : /* GDALGetRasterSampleOverview() */
3438 : /************************************************************************/
3439 :
3440 : /**
3441 : * \brief Fetch best sampling overview.
3442 : *
3443 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3444 : * billion samples.
3445 : *
3446 : * @see GDALRasterBand::GetRasterSampleOverview()
3447 : * @see GDALGetRasterSampleOverviewEx()
3448 : */
3449 :
3450 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3451 : int nDesiredSamples)
3452 :
3453 : {
3454 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3455 :
3456 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3457 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3458 0 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3459 : }
3460 :
3461 : /************************************************************************/
3462 : /* GDALGetRasterSampleOverviewEx() */
3463 : /************************************************************************/
3464 :
3465 : /**
3466 : * \brief Fetch best sampling overview.
3467 : *
3468 : * @see GDALRasterBand::GetRasterSampleOverview()
3469 : * @since GDAL 2.0
3470 : */
3471 :
3472 : GDALRasterBandH CPL_STDCALL
3473 2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3474 :
3475 : {
3476 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3477 :
3478 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3479 2000 : return GDALRasterBand::ToHandle(
3480 4000 : poBand->GetRasterSampleOverview(nDesiredSamples));
3481 : }
3482 :
3483 : /************************************************************************/
3484 : /* BuildOverviews() */
3485 : /************************************************************************/
3486 :
3487 : /**
3488 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3489 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3490 : *
3491 : * If the operation is unsupported for the indicated dataset, then
3492 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3493 : * CPLE_NotSupported.
3494 : *
3495 : * WARNING: Most formats don't support per-band overview computation, but
3496 : * require that overviews are computed for all bands of a dataset, using
3497 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3498 : * is the HFA driver which supports this method.
3499 : *
3500 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3501 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3502 : * applied.
3503 : * @param nOverviews number of overviews to build.
3504 : * @param panOverviewList the list of overview decimation factors to build.
3505 : * @param pfnProgress a function to call to report progress, or NULL.
3506 : * @param pProgressData application data to pass to the progress function.
3507 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3508 : * key=value pairs, or NULL
3509 : *
3510 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3511 : */
3512 :
3513 : /**/
3514 : /**/
3515 :
3516 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3517 : int /*nOverviews*/,
3518 : const int * /*panOverviewList*/,
3519 : GDALProgressFunc /*pfnProgress*/,
3520 : void * /*pProgressData*/,
3521 : CSLConstList /* papszOptions */)
3522 :
3523 : {
3524 0 : ReportError(CE_Failure, CPLE_NotSupported,
3525 : "BuildOverviews() not supported for this dataset.");
3526 :
3527 0 : return (CE_Failure);
3528 : }
3529 :
3530 : /************************************************************************/
3531 : /* GetOffset() */
3532 : /************************************************************************/
3533 :
3534 : /**
3535 : * \brief Fetch the raster value offset.
3536 : *
3537 : * This value (in combination with the GetScale() value) can be used to
3538 : * transform raw pixel values into the units returned by GetUnitType().
3539 : * For example this might be used to store elevations in GUInt16 bands
3540 : * with a precision of 0.1, and starting from -100.
3541 : *
3542 : * Units value = (raw value * scale) + offset
3543 : *
3544 : * Note that applying scale and offset is of the responsibility of the user,
3545 : * and is not done by methods such as RasterIO() or ReadBlock().
3546 : *
3547 : * For file formats that don't know this intrinsically a value of zero
3548 : * is returned.
3549 : *
3550 : * This method is the same as the C function GDALGetRasterOffset().
3551 : *
3552 : * @param pbSuccess pointer to a boolean to use to indicate if the
3553 : * returned value is meaningful or not. May be NULL (default).
3554 : *
3555 : * @return the raster offset.
3556 : */
3557 :
3558 463 : double GDALRasterBand::GetOffset(int *pbSuccess)
3559 :
3560 : {
3561 463 : if (pbSuccess != nullptr)
3562 354 : *pbSuccess = FALSE;
3563 :
3564 463 : return 0.0;
3565 : }
3566 :
3567 : /************************************************************************/
3568 : /* GDALGetRasterOffset() */
3569 : /************************************************************************/
3570 :
3571 : /**
3572 : * \brief Fetch the raster value offset.
3573 : *
3574 : * @see GDALRasterBand::GetOffset()
3575 : */
3576 :
3577 385 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3578 :
3579 : {
3580 385 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3581 :
3582 385 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3583 385 : return poBand->GetOffset(pbSuccess);
3584 : }
3585 :
3586 : /************************************************************************/
3587 : /* SetOffset() */
3588 : /************************************************************************/
3589 :
3590 : /**
3591 : * \fn GDALRasterBand::SetOffset(double)
3592 : * \brief Set scaling offset.
3593 : *
3594 : * Very few formats implement this method. When not implemented it will
3595 : * issue a CPLE_NotSupported error and return CE_Failure.
3596 : *
3597 : * This method is the same as the C function GDALSetRasterOffset().
3598 : *
3599 : * @param dfNewOffset the new offset.
3600 : *
3601 : * @return CE_None or success or CE_Failure on failure.
3602 : */
3603 :
3604 : /**/
3605 : /**/
3606 :
3607 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3608 : {
3609 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3610 0 : ReportError(CE_Failure, CPLE_NotSupported,
3611 : "SetOffset() not supported on this raster band.");
3612 :
3613 0 : return CE_Failure;
3614 : }
3615 :
3616 : /************************************************************************/
3617 : /* GDALSetRasterOffset() */
3618 : /************************************************************************/
3619 :
3620 : /**
3621 : * \brief Set scaling offset.
3622 : *
3623 : * @see GDALRasterBand::SetOffset()
3624 : */
3625 :
3626 75 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3627 : double dfNewOffset)
3628 :
3629 : {
3630 75 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3631 :
3632 75 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3633 75 : return poBand->SetOffset(dfNewOffset);
3634 : }
3635 :
3636 : /************************************************************************/
3637 : /* GetScale() */
3638 : /************************************************************************/
3639 :
3640 : /**
3641 : * \brief Fetch the raster value scale.
3642 : *
3643 : * This value (in combination with the GetOffset() value) can be used to
3644 : * transform raw pixel values into the units returned by GetUnitType().
3645 : * For example this might be used to store elevations in GUInt16 bands
3646 : * with a precision of 0.1, and starting from -100.
3647 : *
3648 : * Units value = (raw value * scale) + offset
3649 : *
3650 : * Note that applying scale and offset is of the responsibility of the user,
3651 : * and is not done by methods such as RasterIO() or ReadBlock().
3652 : *
3653 : * For file formats that don't know this intrinsically a value of one
3654 : * is returned.
3655 : *
3656 : * This method is the same as the C function GDALGetRasterScale().
3657 : *
3658 : * @param pbSuccess pointer to a boolean to use to indicate if the
3659 : * returned value is meaningful or not. May be NULL (default).
3660 : *
3661 : * @return the raster scale.
3662 : */
3663 :
3664 463 : double GDALRasterBand::GetScale(int *pbSuccess)
3665 :
3666 : {
3667 463 : if (pbSuccess != nullptr)
3668 354 : *pbSuccess = FALSE;
3669 :
3670 463 : return 1.0;
3671 : }
3672 :
3673 : /************************************************************************/
3674 : /* GDALGetRasterScale() */
3675 : /************************************************************************/
3676 :
3677 : /**
3678 : * \brief Fetch the raster value scale.
3679 : *
3680 : * @see GDALRasterBand::GetScale()
3681 : */
3682 :
3683 383 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3684 :
3685 : {
3686 383 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3687 :
3688 383 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3689 383 : return poBand->GetScale(pbSuccess);
3690 : }
3691 :
3692 : /************************************************************************/
3693 : /* SetScale() */
3694 : /************************************************************************/
3695 :
3696 : /**
3697 : * \fn GDALRasterBand::SetScale(double)
3698 : * \brief Set scaling ratio.
3699 : *
3700 : * Very few formats implement this method. When not implemented it will
3701 : * issue a CPLE_NotSupported error and return CE_Failure.
3702 : *
3703 : * This method is the same as the C function GDALSetRasterScale().
3704 : *
3705 : * @param dfNewScale the new scale.
3706 : *
3707 : * @return CE_None or success or CE_Failure on failure.
3708 : */
3709 :
3710 : /**/
3711 : /**/
3712 :
3713 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3714 :
3715 : {
3716 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3717 0 : ReportError(CE_Failure, CPLE_NotSupported,
3718 : "SetScale() not supported on this raster band.");
3719 :
3720 0 : return CE_Failure;
3721 : }
3722 :
3723 : /************************************************************************/
3724 : /* GDALSetRasterScale() */
3725 : /************************************************************************/
3726 :
3727 : /**
3728 : * \brief Set scaling ratio.
3729 : *
3730 : * @see GDALRasterBand::SetScale()
3731 : */
3732 :
3733 76 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3734 :
3735 : {
3736 76 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3737 :
3738 76 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3739 76 : return poBand->SetScale(dfNewOffset);
3740 : }
3741 :
3742 : /************************************************************************/
3743 : /* GetUnitType() */
3744 : /************************************************************************/
3745 :
3746 : /**
3747 : * \brief Return raster unit type.
3748 : *
3749 : * Return a name for the units of this raster's values. For instance, it
3750 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3751 : * units are available, a value of "" will be returned. The returned string
3752 : * should not be modified, nor freed by the calling application.
3753 : *
3754 : * This method is the same as the C function GDALGetRasterUnitType().
3755 : *
3756 : * @return unit name string.
3757 : */
3758 :
3759 183 : const char *GDALRasterBand::GetUnitType()
3760 :
3761 : {
3762 183 : return "";
3763 : }
3764 :
3765 : /************************************************************************/
3766 : /* GDALGetRasterUnitType() */
3767 : /************************************************************************/
3768 :
3769 : /**
3770 : * \brief Return raster unit type.
3771 : *
3772 : * @see GDALRasterBand::GetUnitType()
3773 : */
3774 :
3775 1454 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3776 :
3777 : {
3778 1454 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3779 :
3780 1454 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3781 1454 : return poBand->GetUnitType();
3782 : }
3783 :
3784 : /************************************************************************/
3785 : /* SetUnitType() */
3786 : /************************************************************************/
3787 :
3788 : /**
3789 : * \fn GDALRasterBand::SetUnitType(const char*)
3790 : * \brief Set unit type.
3791 : *
3792 : * Set the unit type for a raster band. Values should be one of
3793 : * "" (the default indicating it is unknown), "m" indicating meters,
3794 : * or "ft" indicating feet, though other nonstandard values are allowed.
3795 : *
3796 : * This method is the same as the C function GDALSetRasterUnitType().
3797 : *
3798 : * @param pszNewValue the new unit type value.
3799 : *
3800 : * @return CE_None on success or CE_Failure if not successful, or
3801 : * unsupported.
3802 : */
3803 :
3804 : /**/
3805 : /**/
3806 :
3807 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3808 :
3809 : {
3810 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3811 0 : ReportError(CE_Failure, CPLE_NotSupported,
3812 : "SetUnitType() not supported on this raster band.");
3813 0 : return CE_Failure;
3814 : }
3815 :
3816 : /************************************************************************/
3817 : /* GDALSetRasterUnitType() */
3818 : /************************************************************************/
3819 :
3820 : /**
3821 : * \brief Set unit type.
3822 : *
3823 : * @see GDALRasterBand::SetUnitType()
3824 : *
3825 : * @since GDAL 1.8.0
3826 : */
3827 :
3828 75 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3829 : const char *pszNewValue)
3830 :
3831 : {
3832 75 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3833 :
3834 75 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3835 75 : return poBand->SetUnitType(pszNewValue);
3836 : }
3837 :
3838 : /************************************************************************/
3839 : /* GetXSize() */
3840 : /************************************************************************/
3841 :
3842 : /**
3843 : * \brief Fetch XSize of raster.
3844 : *
3845 : * This method is the same as the C function GDALGetRasterBandXSize().
3846 : *
3847 : * @return the width in pixels of this band.
3848 : */
3849 :
3850 8381490 : int GDALRasterBand::GetXSize() const
3851 :
3852 : {
3853 8381490 : return nRasterXSize;
3854 : }
3855 :
3856 : /************************************************************************/
3857 : /* GDALGetRasterBandXSize() */
3858 : /************************************************************************/
3859 :
3860 : /**
3861 : * \brief Fetch XSize of raster.
3862 : *
3863 : * @see GDALRasterBand::GetXSize()
3864 : */
3865 :
3866 57674 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3867 :
3868 : {
3869 57674 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3870 :
3871 57674 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3872 57674 : return poBand->GetXSize();
3873 : }
3874 :
3875 : /************************************************************************/
3876 : /* GetYSize() */
3877 : /************************************************************************/
3878 :
3879 : /**
3880 : * \brief Fetch YSize of raster.
3881 : *
3882 : * This method is the same as the C function GDALGetRasterBandYSize().
3883 : *
3884 : * @return the height in pixels of this band.
3885 : */
3886 :
3887 4584470 : int GDALRasterBand::GetYSize() const
3888 :
3889 : {
3890 4584470 : return nRasterYSize;
3891 : }
3892 :
3893 : /************************************************************************/
3894 : /* GDALGetRasterBandYSize() */
3895 : /************************************************************************/
3896 :
3897 : /**
3898 : * \brief Fetch YSize of raster.
3899 : *
3900 : * @see GDALRasterBand::GetYSize()
3901 : */
3902 :
3903 56532 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3904 :
3905 : {
3906 56532 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3907 :
3908 56532 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3909 56533 : return poBand->GetYSize();
3910 : }
3911 :
3912 : /************************************************************************/
3913 : /* GetBand() */
3914 : /************************************************************************/
3915 :
3916 : /**
3917 : * \brief Fetch the band number.
3918 : *
3919 : * This method returns the band that this GDALRasterBand objects represents
3920 : * within its dataset. This method may return a value of 0 to indicate
3921 : * GDALRasterBand objects without an apparently relationship to a dataset,
3922 : * such as GDALRasterBands serving as overviews.
3923 : *
3924 : * This method is the same as the C function GDALGetBandNumber().
3925 : *
3926 : * @return band number (1+) or 0 if the band number isn't known.
3927 : */
3928 :
3929 151983 : int GDALRasterBand::GetBand() const
3930 :
3931 : {
3932 151983 : return nBand;
3933 : }
3934 :
3935 : /************************************************************************/
3936 : /* GDALGetBandNumber() */
3937 : /************************************************************************/
3938 :
3939 : /**
3940 : * \brief Fetch the band number.
3941 : *
3942 : * @see GDALRasterBand::GetBand()
3943 : */
3944 :
3945 208 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3946 :
3947 : {
3948 208 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3949 :
3950 208 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3951 208 : return poBand->GetBand();
3952 : }
3953 :
3954 : /************************************************************************/
3955 : /* GetDataset() */
3956 : /************************************************************************/
3957 :
3958 : /**
3959 : * \brief Fetch the owning dataset handle.
3960 : *
3961 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3962 : * such as overviews or other "freestanding" bands.
3963 : *
3964 : * This method is the same as the C function GDALGetBandDataset().
3965 : *
3966 : * @return the pointer to the GDALDataset to which this band belongs, or
3967 : * NULL if this cannot be determined.
3968 : */
3969 :
3970 5282660 : GDALDataset *GDALRasterBand::GetDataset() const
3971 :
3972 : {
3973 5282660 : return poDS;
3974 : }
3975 :
3976 : /************************************************************************/
3977 : /* GDALGetBandDataset() */
3978 : /************************************************************************/
3979 :
3980 : /**
3981 : * \brief Fetch the owning dataset handle.
3982 : *
3983 : * @see GDALRasterBand::GetDataset()
3984 : */
3985 :
3986 445 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
3987 :
3988 : {
3989 445 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
3990 :
3991 445 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3992 445 : return GDALDataset::ToHandle(poBand->GetDataset());
3993 : }
3994 :
3995 : /************************************************************************/
3996 : /* ComputeFloat16NoDataValue() */
3997 : /************************************************************************/
3998 :
3999 2231 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4000 : double dfNoDataValue,
4001 : int &bGotNoDataValue,
4002 : GFloat16 &fNoDataValue,
4003 : bool &bGotFloat16NoDataValue)
4004 : {
4005 2231 : if (eDataType == GDT_Float16 && bGotNoDataValue)
4006 : {
4007 0 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4008 0 : if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4009 : {
4010 0 : fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4011 0 : bGotFloat16NoDataValue = true;
4012 0 : bGotNoDataValue = false;
4013 : }
4014 : }
4015 2231 : }
4016 :
4017 : /************************************************************************/
4018 : /* ComputeFloatNoDataValue() */
4019 : /************************************************************************/
4020 :
4021 2232 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4022 : double dfNoDataValue,
4023 : int &bGotNoDataValue,
4024 : float &fNoDataValue,
4025 : bool &bGotFloatNoDataValue)
4026 : {
4027 2232 : if (eDataType == GDT_Float32 && bGotNoDataValue)
4028 : {
4029 88 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4030 88 : if (GDALIsValueInRange<float>(dfNoDataValue))
4031 : {
4032 88 : fNoDataValue = static_cast<float>(dfNoDataValue);
4033 88 : bGotFloatNoDataValue = true;
4034 88 : bGotNoDataValue = false;
4035 : }
4036 : }
4037 2232 : }
4038 :
4039 : /************************************************************************/
4040 : /* struct GDALNoDataValues */
4041 : /************************************************************************/
4042 :
4043 : /**
4044 : * \brief No-data-values for all types
4045 : *
4046 : * The functions below pass various no-data-values around. To avoid
4047 : * long argument lists, this struct collects the no-data-values for
4048 : * all types into a single, convenient place.
4049 : **/
4050 :
4051 : struct GDALNoDataValues
4052 : {
4053 : int bGotNoDataValue;
4054 : double dfNoDataValue;
4055 :
4056 : bool bGotInt64NoDataValue;
4057 : int64_t nInt64NoDataValue;
4058 :
4059 : bool bGotUInt64NoDataValue;
4060 : uint64_t nUInt64NoDataValue;
4061 :
4062 : bool bGotFloatNoDataValue;
4063 : float fNoDataValue;
4064 :
4065 : bool bGotFloat16NoDataValue;
4066 : GFloat16 hfNoDataValue;
4067 :
4068 2276 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4069 2276 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4070 : bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4071 : bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4072 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4073 2276 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4074 : {
4075 2276 : if (eDataType == GDT_Int64)
4076 : {
4077 28 : int nGot = false;
4078 28 : nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4079 28 : bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4080 28 : if (bGotInt64NoDataValue)
4081 : {
4082 3 : dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4083 3 : bGotNoDataValue =
4084 3 : nInt64NoDataValue <=
4085 6 : std::numeric_limits<int64_t>::max() - 1024 &&
4086 3 : static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4087 : }
4088 : else
4089 25 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4090 : }
4091 2248 : else if (eDataType == GDT_UInt64)
4092 : {
4093 16 : int nGot = false;
4094 16 : nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4095 16 : bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4096 16 : if (bGotUInt64NoDataValue)
4097 : {
4098 3 : dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4099 3 : bGotNoDataValue =
4100 3 : nUInt64NoDataValue <=
4101 6 : std::numeric_limits<uint64_t>::max() - 2048 &&
4102 3 : static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4103 : }
4104 : else
4105 13 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4106 : }
4107 : else
4108 : {
4109 2232 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4110 2232 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4111 :
4112 2232 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4113 2232 : fNoDataValue, bGotFloatNoDataValue);
4114 :
4115 2232 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4116 2232 : hfNoDataValue, bGotFloat16NoDataValue);
4117 : }
4118 2276 : }
4119 : };
4120 :
4121 : /************************************************************************/
4122 : /* ARE_REAL_EQUAL() */
4123 : /************************************************************************/
4124 :
4125 0 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4126 : {
4127 : using std::abs;
4128 0 : return dfVal1 == dfVal2 || /* Should cover infinity */
4129 0 : abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4130 0 : abs(dfVal1 + dfVal2) * ulp;
4131 : }
4132 :
4133 : /************************************************************************/
4134 : /* GetHistogram() */
4135 : /************************************************************************/
4136 :
4137 : /**
4138 : * \brief Compute raster histogram.
4139 : *
4140 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4141 : *
4142 : * For example to compute a simple 256 entry histogram of eight bit data,
4143 : * the following would be suitable. The unusual bounds are to ensure that
4144 : * bucket boundaries don't fall right on integer values causing possible errors
4145 : * due to rounding after scaling.
4146 : \code{.cpp}
4147 : GUIntBig anHistogram[256];
4148 :
4149 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4150 : GDALDummyProgress, nullptr );
4151 : \endcode
4152 : *
4153 : * Note that setting bApproxOK will generally result in a subsampling of the
4154 : * file, and will utilize overviews if available. It should generally
4155 : * produce a representative histogram for the data that is suitable for use
4156 : * in generating histogram based luts for instance. Generally bApproxOK is
4157 : * much faster than an exactly computed histogram.
4158 : *
4159 : * This method is the same as the C functions GDALGetRasterHistogram() and
4160 : * GDALGetRasterHistogramEx().
4161 : *
4162 : * @param dfMin the lower bound of the histogram.
4163 : * @param dfMax the upper bound of the histogram.
4164 : * @param nBuckets the number of buckets in panHistogram.
4165 : * @param panHistogram array into which the histogram totals are placed.
4166 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4167 : * mapped into panHistogram[0], and values above will be mapped into
4168 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4169 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4170 : * @param pfnProgress function to report progress to completion.
4171 : * @param pProgressData application data to pass to pfnProgress.
4172 : *
4173 : * @return CE_None on success, or CE_Failure if something goes wrong.
4174 : */
4175 :
4176 42 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4177 : GUIntBig *panHistogram,
4178 : int bIncludeOutOfRange, int bApproxOK,
4179 : GDALProgressFunc pfnProgress,
4180 : void *pProgressData)
4181 :
4182 : {
4183 42 : CPLAssert(nullptr != panHistogram);
4184 :
4185 42 : if (pfnProgress == nullptr)
4186 29 : pfnProgress = GDALDummyProgress;
4187 :
4188 : /* -------------------------------------------------------------------- */
4189 : /* If we have overviews, use them for the histogram. */
4190 : /* -------------------------------------------------------------------- */
4191 42 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4192 : {
4193 : // FIXME: should we use the most reduced overview here or use some
4194 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4195 : // does?
4196 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4197 :
4198 0 : if (poBestOverview != this)
4199 : {
4200 0 : return poBestOverview->GetHistogram(
4201 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4202 0 : bApproxOK, pfnProgress, pProgressData);
4203 : }
4204 : }
4205 :
4206 : /* -------------------------------------------------------------------- */
4207 : /* Read actual data and build histogram. */
4208 : /* -------------------------------------------------------------------- */
4209 42 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4210 : {
4211 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4212 0 : return CE_Failure;
4213 : }
4214 :
4215 : // Written this way to deal with NaN
4216 42 : if (!(dfMax > dfMin))
4217 : {
4218 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4219 : "dfMax should be strictly greater than dfMin");
4220 5 : return CE_Failure;
4221 : }
4222 :
4223 : GDALRasterIOExtraArg sExtraArg;
4224 37 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4225 :
4226 37 : const double dfScale = nBuckets / (dfMax - dfMin);
4227 37 : if (dfScale == 0 || !std::isfinite(dfScale))
4228 : {
4229 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4230 : "dfMin and dfMax should be finite values such that "
4231 : "nBuckets / (dfMax - dfMin) is non-zero");
4232 5 : return CE_Failure;
4233 : }
4234 32 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4235 :
4236 32 : GDALNoDataValues sNoDataValues(this, eDataType);
4237 32 : GDALRasterBand *poMaskBand = nullptr;
4238 32 : if (!sNoDataValues.bGotNoDataValue)
4239 : {
4240 31 : const int l_nMaskFlags = GetMaskFlags();
4241 33 : if (l_nMaskFlags != GMF_ALL_VALID &&
4242 2 : GetColorInterpretation() != GCI_AlphaBand)
4243 : {
4244 2 : poMaskBand = GetMaskBand();
4245 : }
4246 : }
4247 :
4248 32 : bool bSignedByte = false;
4249 32 : if (eDataType == GDT_Byte)
4250 : {
4251 23 : EnablePixelTypeSignedByteWarning(false);
4252 : const char *pszPixelType =
4253 23 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4254 23 : EnablePixelTypeSignedByteWarning(true);
4255 23 : bSignedByte =
4256 23 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4257 : }
4258 :
4259 32 : if (bApproxOK && HasArbitraryOverviews())
4260 : {
4261 : /* --------------------------------------------------------------------
4262 : */
4263 : /* Figure out how much the image should be reduced to get an */
4264 : /* approximate value. */
4265 : /* --------------------------------------------------------------------
4266 : */
4267 : const double dfReduction =
4268 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4269 : GDALSTAT_APPROX_NUMSAMPLES);
4270 :
4271 0 : int nXReduced = nRasterXSize;
4272 0 : int nYReduced = nRasterYSize;
4273 0 : if (dfReduction > 1.0)
4274 : {
4275 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4276 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4277 :
4278 : // Catch the case of huge resizing ratios here
4279 0 : if (nXReduced == 0)
4280 0 : nXReduced = 1;
4281 0 : if (nYReduced == 0)
4282 0 : nYReduced = 1;
4283 : }
4284 :
4285 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4286 : nXReduced, nYReduced);
4287 0 : if (!pData)
4288 0 : return CE_Failure;
4289 :
4290 : const CPLErr eErr =
4291 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4292 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4293 0 : if (eErr != CE_None)
4294 : {
4295 0 : CPLFree(pData);
4296 0 : return eErr;
4297 : }
4298 :
4299 0 : GByte *pabyMaskData = nullptr;
4300 0 : if (poMaskBand)
4301 : {
4302 : pabyMaskData =
4303 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4304 0 : if (!pabyMaskData)
4305 : {
4306 0 : CPLFree(pData);
4307 0 : return CE_Failure;
4308 : }
4309 :
4310 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4311 : pabyMaskData, nXReduced, nYReduced,
4312 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
4313 : {
4314 0 : CPLFree(pData);
4315 0 : CPLFree(pabyMaskData);
4316 0 : return CE_Failure;
4317 : }
4318 : }
4319 :
4320 : // This isn't the fastest way to do this, but is easier for now.
4321 0 : for (int iY = 0; iY < nYReduced; iY++)
4322 : {
4323 0 : for (int iX = 0; iX < nXReduced; iX++)
4324 : {
4325 0 : const int iOffset = iX + iY * nXReduced;
4326 0 : double dfValue = 0.0;
4327 :
4328 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4329 0 : continue;
4330 :
4331 0 : switch (eDataType)
4332 : {
4333 0 : case GDT_Byte:
4334 : {
4335 0 : if (bSignedByte)
4336 0 : dfValue =
4337 0 : static_cast<signed char *>(pData)[iOffset];
4338 : else
4339 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4340 0 : break;
4341 : }
4342 0 : case GDT_Int8:
4343 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4344 0 : break;
4345 0 : case GDT_UInt16:
4346 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4347 0 : break;
4348 0 : case GDT_Int16:
4349 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4350 0 : break;
4351 0 : case GDT_UInt32:
4352 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4353 0 : break;
4354 0 : case GDT_Int32:
4355 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4356 0 : break;
4357 0 : case GDT_UInt64:
4358 0 : dfValue = static_cast<double>(
4359 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4360 0 : break;
4361 0 : case GDT_Int64:
4362 0 : dfValue = static_cast<double>(
4363 0 : static_cast<GInt64 *>(pData)[iOffset]);
4364 0 : break;
4365 0 : case GDT_Float16:
4366 : {
4367 : using namespace std;
4368 0 : const GFloat16 hfValue =
4369 0 : static_cast<GFloat16 *>(pData)[iOffset];
4370 0 : if (isnan(hfValue) ||
4371 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4372 0 : ARE_REAL_EQUAL(hfValue,
4373 : sNoDataValues.hfNoDataValue)))
4374 0 : continue;
4375 0 : dfValue = hfValue;
4376 0 : break;
4377 : }
4378 0 : case GDT_Float32:
4379 : {
4380 0 : const float fValue =
4381 0 : static_cast<float *>(pData)[iOffset];
4382 0 : if (std::isnan(fValue) ||
4383 0 : (sNoDataValues.bGotFloatNoDataValue &&
4384 0 : ARE_REAL_EQUAL(fValue,
4385 : sNoDataValues.fNoDataValue)))
4386 0 : continue;
4387 0 : dfValue = double(fValue);
4388 0 : break;
4389 : }
4390 0 : case GDT_Float64:
4391 0 : dfValue = static_cast<double *>(pData)[iOffset];
4392 0 : if (std::isnan(dfValue))
4393 0 : continue;
4394 0 : break;
4395 0 : case GDT_CInt16:
4396 : {
4397 0 : const double dfReal =
4398 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4399 0 : const double dfImag =
4400 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4401 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4402 0 : continue;
4403 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4404 : }
4405 0 : break;
4406 0 : case GDT_CInt32:
4407 : {
4408 0 : const double dfReal =
4409 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4410 0 : const double dfImag =
4411 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4412 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4413 0 : continue;
4414 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4415 : }
4416 0 : break;
4417 0 : case GDT_CFloat16:
4418 : {
4419 : const double dfReal =
4420 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4421 : const double dfImag =
4422 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4423 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4424 0 : continue;
4425 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4426 0 : break;
4427 : }
4428 0 : case GDT_CFloat32:
4429 : {
4430 0 : const double dfReal =
4431 0 : double(static_cast<float *>(pData)[iOffset * 2]);
4432 0 : const double dfImag = double(
4433 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4434 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4435 0 : continue;
4436 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4437 0 : break;
4438 : }
4439 0 : case GDT_CFloat64:
4440 : {
4441 0 : const double dfReal =
4442 0 : static_cast<double *>(pData)[iOffset * 2];
4443 0 : const double dfImag =
4444 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4445 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4446 0 : continue;
4447 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4448 0 : break;
4449 : }
4450 0 : case GDT_Unknown:
4451 : case GDT_TypeCount:
4452 0 : CPLAssert(false);
4453 : }
4454 :
4455 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4456 0 : sNoDataValues.bGotNoDataValue &&
4457 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4458 0 : continue;
4459 :
4460 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4461 : // finite, the result of the multiplication cannot be NaN
4462 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4463 :
4464 0 : if (dfIndex < 0)
4465 : {
4466 0 : if (bIncludeOutOfRange)
4467 0 : panHistogram[0]++;
4468 : }
4469 0 : else if (dfIndex >= nBuckets)
4470 : {
4471 0 : if (bIncludeOutOfRange)
4472 0 : ++panHistogram[nBuckets - 1];
4473 : }
4474 : else
4475 : {
4476 0 : ++panHistogram[static_cast<int>(dfIndex)];
4477 : }
4478 : }
4479 : }
4480 :
4481 0 : CPLFree(pData);
4482 0 : CPLFree(pabyMaskData);
4483 : }
4484 : else // No arbitrary overviews.
4485 : {
4486 32 : if (!InitBlockInfo())
4487 0 : return CE_Failure;
4488 :
4489 : /* --------------------------------------------------------------------
4490 : */
4491 : /* Figure out the ratio of blocks we will read to get an */
4492 : /* approximate value. */
4493 : /* --------------------------------------------------------------------
4494 : */
4495 :
4496 32 : int nSampleRate = 1;
4497 32 : if (bApproxOK)
4498 : {
4499 8 : nSampleRate = static_cast<int>(std::max(
4500 16 : 1.0,
4501 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4502 : // We want to avoid probing only the first column of blocks for
4503 : // a square shaped raster, because it is not unlikely that it may
4504 : // be padding only (#6378).
4505 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4506 1 : nSampleRate += 1;
4507 : }
4508 :
4509 32 : GByte *pabyMaskData = nullptr;
4510 32 : if (poMaskBand)
4511 : {
4512 : pabyMaskData = static_cast<GByte *>(
4513 2 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4514 2 : if (!pabyMaskData)
4515 : {
4516 0 : return CE_Failure;
4517 : }
4518 : }
4519 :
4520 : /* --------------------------------------------------------------------
4521 : */
4522 : /* Read the blocks, and add to histogram. */
4523 : /* --------------------------------------------------------------------
4524 : */
4525 32 : for (GIntBig iSampleBlock = 0;
4526 154 : iSampleBlock <
4527 154 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4528 122 : iSampleBlock += nSampleRate)
4529 : {
4530 122 : if (!pfnProgress(
4531 122 : static_cast<double>(iSampleBlock) /
4532 122 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4533 : "Compute Histogram", pProgressData))
4534 : {
4535 0 : CPLFree(pabyMaskData);
4536 0 : return CE_Failure;
4537 : }
4538 :
4539 122 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4540 122 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4541 :
4542 122 : int nXCheck = 0, nYCheck = 0;
4543 122 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4544 :
4545 124 : if (poMaskBand &&
4546 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4547 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4548 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4549 2 : 0, nBlockXSize, nullptr) != CE_None)
4550 : {
4551 0 : CPLFree(pabyMaskData);
4552 0 : return CE_Failure;
4553 : }
4554 :
4555 122 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4556 122 : if (poBlock == nullptr)
4557 : {
4558 0 : CPLFree(pabyMaskData);
4559 0 : return CE_Failure;
4560 : }
4561 :
4562 122 : void *pData = poBlock->GetDataRef();
4563 :
4564 : // this is a special case for a common situation.
4565 122 : if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4566 86 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4567 83 : nXCheck == nBlockXSize && nBuckets == 256)
4568 : {
4569 83 : const GPtrDiff_t nPixels =
4570 83 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4571 83 : GByte *pabyData = static_cast<GByte *>(pData);
4572 :
4573 72137 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4574 : {
4575 72054 : if (pabyMaskData && pabyMaskData[i] == 0)
4576 0 : continue;
4577 72054 : if (!(sNoDataValues.bGotNoDataValue &&
4578 512 : (pabyData[i] ==
4579 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4580 : {
4581 71798 : panHistogram[pabyData[i]]++;
4582 : }
4583 : }
4584 :
4585 83 : poBlock->DropLock();
4586 83 : continue; // To next sample block.
4587 : }
4588 :
4589 : // This isn't the fastest way to do this, but is easier for now.
4590 257 : for (int iY = 0; iY < nYCheck; iY++)
4591 : {
4592 36389 : for (int iX = 0; iX < nXCheck; iX++)
4593 : {
4594 36171 : const GPtrDiff_t iOffset =
4595 36171 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4596 :
4597 36171 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4598 2 : continue;
4599 :
4600 36169 : double dfValue = 0.0;
4601 :
4602 36169 : switch (eDataType)
4603 : {
4604 19716 : case GDT_Byte:
4605 : {
4606 19716 : if (bSignedByte)
4607 0 : dfValue =
4608 0 : static_cast<signed char *>(pData)[iOffset];
4609 : else
4610 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4611 19716 : break;
4612 : }
4613 1 : case GDT_Int8:
4614 1 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4615 1 : break;
4616 16384 : case GDT_UInt16:
4617 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4618 16384 : break;
4619 3 : case GDT_Int16:
4620 3 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4621 3 : break;
4622 0 : case GDT_UInt32:
4623 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4624 0 : break;
4625 60 : case GDT_Int32:
4626 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4627 60 : break;
4628 0 : case GDT_UInt64:
4629 0 : dfValue = static_cast<double>(
4630 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4631 0 : break;
4632 0 : case GDT_Int64:
4633 0 : dfValue = static_cast<double>(
4634 0 : static_cast<GInt64 *>(pData)[iOffset]);
4635 0 : break;
4636 0 : case GDT_Float16:
4637 : {
4638 : using namespace std;
4639 0 : const GFloat16 hfValue =
4640 0 : static_cast<GFloat16 *>(pData)[iOffset];
4641 0 : if (isnan(hfValue) ||
4642 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4643 0 : ARE_REAL_EQUAL(hfValue,
4644 : sNoDataValues.hfNoDataValue)))
4645 0 : continue;
4646 0 : dfValue = hfValue;
4647 0 : break;
4648 : }
4649 3 : case GDT_Float32:
4650 : {
4651 3 : const float fValue =
4652 3 : static_cast<float *>(pData)[iOffset];
4653 6 : if (std::isnan(fValue) ||
4654 6 : (sNoDataValues.bGotFloatNoDataValue &&
4655 3 : ARE_REAL_EQUAL(fValue,
4656 : sNoDataValues.fNoDataValue)))
4657 0 : continue;
4658 3 : dfValue = double(fValue);
4659 3 : break;
4660 : }
4661 2 : case GDT_Float64:
4662 2 : dfValue = static_cast<double *>(pData)[iOffset];
4663 2 : if (std::isnan(dfValue))
4664 0 : continue;
4665 2 : break;
4666 0 : case GDT_CInt16:
4667 : {
4668 0 : double dfReal =
4669 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4670 0 : double dfImag =
4671 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4672 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4673 0 : break;
4674 : }
4675 0 : case GDT_CInt32:
4676 : {
4677 0 : double dfReal =
4678 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4679 0 : double dfImag =
4680 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4681 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4682 0 : break;
4683 : }
4684 0 : case GDT_CFloat16:
4685 : {
4686 : double dfReal =
4687 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4688 : double dfImag =
4689 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4690 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4691 0 : continue;
4692 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4693 0 : break;
4694 : }
4695 0 : case GDT_CFloat32:
4696 : {
4697 0 : double dfReal = double(
4698 0 : static_cast<float *>(pData)[iOffset * 2]);
4699 0 : double dfImag = double(
4700 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4701 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4702 0 : continue;
4703 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4704 0 : break;
4705 : }
4706 0 : case GDT_CFloat64:
4707 : {
4708 0 : double dfReal =
4709 0 : static_cast<double *>(pData)[iOffset * 2];
4710 0 : double dfImag =
4711 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4712 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4713 0 : continue;
4714 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4715 0 : break;
4716 : }
4717 0 : case GDT_Unknown:
4718 : case GDT_TypeCount:
4719 0 : CPLAssert(false);
4720 : CPLFree(pabyMaskData);
4721 : return CE_Failure;
4722 : }
4723 :
4724 36169 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4725 72338 : sNoDataValues.bGotNoDataValue &&
4726 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4727 0 : continue;
4728 :
4729 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4730 : // and finite, the result of the multiplication cannot be
4731 : // NaN
4732 36169 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4733 :
4734 36169 : if (dfIndex < 0)
4735 : {
4736 1 : if (bIncludeOutOfRange)
4737 1 : panHistogram[0]++;
4738 : }
4739 36168 : else if (dfIndex >= nBuckets)
4740 : {
4741 7 : if (bIncludeOutOfRange)
4742 4 : ++panHistogram[nBuckets - 1];
4743 : }
4744 : else
4745 : {
4746 36161 : ++panHistogram[static_cast<int>(dfIndex)];
4747 : }
4748 : }
4749 : }
4750 :
4751 39 : poBlock->DropLock();
4752 : }
4753 :
4754 32 : CPLFree(pabyMaskData);
4755 : }
4756 :
4757 32 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4758 :
4759 32 : return CE_None;
4760 : }
4761 :
4762 : /************************************************************************/
4763 : /* GDALGetRasterHistogram() */
4764 : /************************************************************************/
4765 :
4766 : /**
4767 : * \brief Compute raster histogram.
4768 : *
4769 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4770 : * exceeding 2 billion.
4771 : *
4772 : * @see GDALRasterBand::GetHistogram()
4773 : * @see GDALGetRasterHistogramEx()
4774 : */
4775 :
4776 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4777 : double dfMax, int nBuckets,
4778 : int *panHistogram,
4779 : int bIncludeOutOfRange, int bApproxOK,
4780 : GDALProgressFunc pfnProgress,
4781 : void *pProgressData)
4782 :
4783 : {
4784 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4785 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4786 :
4787 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4788 :
4789 : GUIntBig *panHistogramTemp =
4790 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4791 0 : if (panHistogramTemp == nullptr)
4792 : {
4793 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4794 : "Out of memory in GDALGetRasterHistogram().");
4795 0 : return CE_Failure;
4796 : }
4797 :
4798 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4799 : bIncludeOutOfRange, bApproxOK,
4800 0 : pfnProgress, pProgressData);
4801 :
4802 0 : if (eErr == CE_None)
4803 : {
4804 0 : for (int i = 0; i < nBuckets; i++)
4805 : {
4806 0 : if (panHistogramTemp[i] > INT_MAX)
4807 : {
4808 0 : CPLError(CE_Warning, CPLE_AppDefined,
4809 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4810 : " exceeds maximum 32 bit value",
4811 0 : i, panHistogramTemp[i]);
4812 0 : panHistogram[i] = INT_MAX;
4813 : }
4814 : else
4815 : {
4816 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4817 : }
4818 : }
4819 : }
4820 :
4821 0 : CPLFree(panHistogramTemp);
4822 :
4823 0 : return eErr;
4824 : }
4825 :
4826 : /************************************************************************/
4827 : /* GDALGetRasterHistogramEx() */
4828 : /************************************************************************/
4829 :
4830 : /**
4831 : * \brief Compute raster histogram.
4832 : *
4833 : * @see GDALRasterBand::GetHistogram()
4834 : *
4835 : * @since GDAL 2.0
4836 : */
4837 :
4838 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4839 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4840 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4841 : GDALProgressFunc pfnProgress, void *pProgressData)
4842 :
4843 : {
4844 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4845 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4846 :
4847 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4848 :
4849 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4850 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4851 26 : pProgressData);
4852 : }
4853 :
4854 : /************************************************************************/
4855 : /* GetDefaultHistogram() */
4856 : /************************************************************************/
4857 :
4858 : /**
4859 : * \brief Fetch default raster histogram.
4860 : *
4861 : * The default method in GDALRasterBand will compute a default histogram. This
4862 : * method is overridden by derived classes (such as GDALPamRasterBand,
4863 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4864 : * stored histogram.
4865 : *
4866 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4867 : * GDALGetDefaultHistogramEx().
4868 : *
4869 : * @param pdfMin pointer to double value that will contain the lower bound of
4870 : * the histogram.
4871 : * @param pdfMax pointer to double value that will contain the upper bound of
4872 : * the histogram.
4873 : * @param pnBuckets pointer to int value that will contain the number of buckets
4874 : * in *ppanHistogram.
4875 : * @param ppanHistogram pointer to array into which the histogram totals are
4876 : * placed. To be freed with VSIFree
4877 : * @param bForce TRUE to force the computation. If FALSE and no default
4878 : * histogram is available, the method will return CE_Warning
4879 : * @param pfnProgress function to report progress to completion.
4880 : * @param pProgressData application data to pass to pfnProgress.
4881 : *
4882 : * @return CE_None on success, CE_Failure if something goes wrong, or
4883 : * CE_Warning if no default histogram is available.
4884 : */
4885 :
4886 24 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4887 : int *pnBuckets,
4888 : GUIntBig **ppanHistogram, int bForce,
4889 : GDALProgressFunc pfnProgress,
4890 : void *pProgressData)
4891 :
4892 : {
4893 24 : CPLAssert(nullptr != pnBuckets);
4894 24 : CPLAssert(nullptr != ppanHistogram);
4895 24 : CPLAssert(nullptr != pdfMin);
4896 24 : CPLAssert(nullptr != pdfMax);
4897 :
4898 24 : *pnBuckets = 0;
4899 24 : *ppanHistogram = nullptr;
4900 :
4901 24 : if (!bForce)
4902 5 : return CE_Warning;
4903 :
4904 19 : int nBuckets = 256;
4905 :
4906 19 : bool bSignedByte = false;
4907 19 : if (eDataType == GDT_Byte)
4908 : {
4909 17 : EnablePixelTypeSignedByteWarning(false);
4910 : const char *pszPixelType =
4911 17 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4912 17 : EnablePixelTypeSignedByteWarning(true);
4913 17 : bSignedByte =
4914 17 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4915 : }
4916 :
4917 19 : if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4918 : {
4919 17 : *pdfMin = -0.5;
4920 17 : *pdfMax = 255.5;
4921 : }
4922 2 : else if (GetRasterDataType() == GDT_Int8)
4923 : {
4924 1 : *pdfMin = -128 - 0.5;
4925 1 : *pdfMax = 127 + 0.5;
4926 : }
4927 : else
4928 : {
4929 :
4930 : const CPLErr eErr =
4931 1 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4932 1 : if (eErr != CE_None)
4933 0 : return eErr;
4934 1 : if (*pdfMin == *pdfMax)
4935 : {
4936 1 : nBuckets = 1;
4937 1 : *pdfMin -= 0.5;
4938 1 : *pdfMax += 0.5;
4939 : }
4940 : else
4941 : {
4942 0 : const double dfHalfBucket =
4943 0 : (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4944 0 : *pdfMin -= dfHalfBucket;
4945 0 : *pdfMax += dfHalfBucket;
4946 : }
4947 : }
4948 :
4949 19 : *ppanHistogram =
4950 19 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4951 19 : if (*ppanHistogram == nullptr)
4952 : {
4953 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4954 : "Out of memory in InitBlockInfo().");
4955 0 : return CE_Failure;
4956 : }
4957 :
4958 19 : *pnBuckets = nBuckets;
4959 38 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4960 19 : TRUE, FALSE, pfnProgress, pProgressData);
4961 19 : if (eErr != CE_None)
4962 : {
4963 0 : *pnBuckets = 0;
4964 : }
4965 19 : return eErr;
4966 : }
4967 :
4968 : /************************************************************************/
4969 : /* GDALGetDefaultHistogram() */
4970 : /************************************************************************/
4971 :
4972 : /**
4973 : * \brief Fetch default raster histogram.
4974 : *
4975 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4976 : * exceeding 2 billion.
4977 : *
4978 : * @see GDALRasterBand::GDALGetDefaultHistogram()
4979 : * @see GDALGetRasterHistogramEx()
4980 : */
4981 :
4982 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4983 : double *pdfMin, double *pdfMax,
4984 : int *pnBuckets, int **ppanHistogram,
4985 : int bForce,
4986 : GDALProgressFunc pfnProgress,
4987 : void *pProgressData)
4988 :
4989 : {
4990 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4991 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4992 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4993 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4994 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4995 :
4996 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4997 0 : GUIntBig *panHistogramTemp = nullptr;
4998 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
4999 : &panHistogramTemp, bForce,
5000 0 : pfnProgress, pProgressData);
5001 0 : if (eErr == CE_None)
5002 : {
5003 0 : const int nBuckets = *pnBuckets;
5004 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5005 0 : if (*ppanHistogram == nullptr)
5006 : {
5007 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5008 : "Out of memory in GDALGetDefaultHistogram().");
5009 0 : VSIFree(panHistogramTemp);
5010 0 : return CE_Failure;
5011 : }
5012 :
5013 0 : for (int i = 0; i < nBuckets; ++i)
5014 : {
5015 0 : if (panHistogramTemp[i] > INT_MAX)
5016 : {
5017 0 : CPLError(CE_Warning, CPLE_AppDefined,
5018 : "Count for bucket %d, which is " CPL_FRMT_GUIB
5019 : " exceeds maximum 32 bit value",
5020 0 : i, panHistogramTemp[i]);
5021 0 : (*ppanHistogram)[i] = INT_MAX;
5022 : }
5023 : else
5024 : {
5025 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5026 : }
5027 : }
5028 :
5029 0 : CPLFree(panHistogramTemp);
5030 : }
5031 : else
5032 : {
5033 0 : *ppanHistogram = nullptr;
5034 : }
5035 :
5036 0 : return eErr;
5037 : }
5038 :
5039 : /************************************************************************/
5040 : /* GDALGetDefaultHistogramEx() */
5041 : /************************************************************************/
5042 :
5043 : /**
5044 : * \brief Fetch default raster histogram.
5045 : *
5046 : * @see GDALRasterBand::GetDefaultHistogram()
5047 : *
5048 : * @since GDAL 2.0
5049 : */
5050 :
5051 : CPLErr CPL_STDCALL
5052 30 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5053 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5054 : GDALProgressFunc pfnProgress, void *pProgressData)
5055 :
5056 : {
5057 30 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5058 30 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5059 30 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5060 30 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5061 30 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5062 :
5063 30 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5064 30 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5065 30 : bForce, pfnProgress, pProgressData);
5066 : }
5067 :
5068 : /************************************************************************/
5069 : /* AdviseRead() */
5070 : /************************************************************************/
5071 :
5072 : /**
5073 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5074 : * \brief Advise driver of upcoming read requests.
5075 : *
5076 : * Some GDAL drivers operate more efficiently if they know in advance what
5077 : * set of upcoming read requests will be made. The AdviseRead() method allows
5078 : * an application to notify the driver of the region of interest,
5079 : * and at what resolution the region will be read.
5080 : *
5081 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
5082 : * accelerate access via some drivers.
5083 : *
5084 : * Depending on call paths, drivers might receive several calls to
5085 : * AdviseRead() with the same parameters.
5086 : *
5087 : * @param nXOff The pixel offset to the top left corner of the region
5088 : * of the band to be accessed. This would be zero to start from the left side.
5089 : *
5090 : * @param nYOff The line offset to the top left corner of the region
5091 : * of the band to be accessed. This would be zero to start from the top.
5092 : *
5093 : * @param nXSize The width of the region of the band to be accessed in pixels.
5094 : *
5095 : * @param nYSize The height of the region of the band to be accessed in lines.
5096 : *
5097 : * @param nBufXSize the width of the buffer image into which the desired region
5098 : * is to be read, or from which it is to be written.
5099 : *
5100 : * @param nBufYSize the height of the buffer image into which the desired
5101 : * region is to be read, or from which it is to be written.
5102 : *
5103 : * @param eBufType the type of the pixel values in the pData data buffer. The
5104 : * pixel values will automatically be translated to/from the GDALRasterBand
5105 : * data type as needed.
5106 : *
5107 : * @param papszOptions a list of name=value strings with special control
5108 : * options. Normally this is NULL.
5109 : *
5110 : * @return CE_Failure if the request is invalid and CE_None if it works or
5111 : * is ignored.
5112 : */
5113 :
5114 : /**/
5115 : /**/
5116 :
5117 113664 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5118 : int /*nYSize*/, int /*nBufXSize*/,
5119 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5120 : char ** /*papszOptions*/)
5121 : {
5122 113664 : return CE_None;
5123 : }
5124 :
5125 : /************************************************************************/
5126 : /* GDALRasterAdviseRead() */
5127 : /************************************************************************/
5128 :
5129 : /**
5130 : * \brief Advise driver of upcoming read requests.
5131 : *
5132 : * @see GDALRasterBand::AdviseRead()
5133 : */
5134 :
5135 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5136 : int nYOff, int nXSize, int nYSize,
5137 : int nBufXSize, int nBufYSize,
5138 : GDALDataType eDT,
5139 : CSLConstList papszOptions)
5140 :
5141 : {
5142 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5143 :
5144 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5145 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5146 : nBufYSize, eDT,
5147 2 : const_cast<char **>(papszOptions));
5148 : }
5149 :
5150 : /************************************************************************/
5151 : /* GetStatistics() */
5152 : /************************************************************************/
5153 :
5154 : /**
5155 : * \brief Fetch image statistics.
5156 : *
5157 : * Returns the minimum, maximum, mean and standard deviation of all
5158 : * pixel values in this band. If approximate statistics are sufficient,
5159 : * the bApproxOK flag can be set to true in which case overviews, or a
5160 : * subset of image tiles may be used in computing the statistics.
5161 : *
5162 : * If bForce is FALSE results will only be returned if it can be done
5163 : * quickly (i.e. without scanning the image, typically by using pre-existing
5164 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5165 : * returned efficiently, the method will return CE_Warning but no warning will
5166 : * be issued. This is a non-standard use of the CE_Warning return value
5167 : * to indicate "nothing done".
5168 : *
5169 : * If bForce is TRUE, and results are quickly available without scanning the
5170 : * image, they will be used. If bForce is TRUE and results are not quickly
5171 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5172 : * which will scan the image.
5173 : *
5174 : * To always force recomputation of statistics, use ComputeStatistics() instead
5175 : * of this method.
5176 : *
5177 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5178 : * will generally cache statistics in the .pam file allowing fast fetch
5179 : * after the first request.
5180 : *
5181 : * This method is the same as the C function GDALGetRasterStatistics().
5182 : *
5183 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5184 : * or a subset of all tiles.
5185 : *
5186 : * @param bForce If FALSE statistics will only be returned if it can
5187 : * be done without rescanning the image. If TRUE, statistics computation will
5188 : * be forced if pre-existing values are not quickly available.
5189 : *
5190 : * @param pdfMin Location into which to load image minimum (may be NULL).
5191 : *
5192 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5193 : *
5194 : * @param pdfMean Location into which to load image mean (may be NULL).
5195 : *
5196 : * @param pdfStdDev Location into which to load image standard deviation
5197 : * (may be NULL).
5198 : *
5199 : * @return CE_None on success, CE_Warning if no values returned,
5200 : * CE_Failure if an error occurs.
5201 : */
5202 :
5203 628 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5204 : double *pdfMax, double *pdfMean,
5205 : double *pdfStdDev)
5206 :
5207 : {
5208 : /* -------------------------------------------------------------------- */
5209 : /* Do we already have metadata items for the requested values? */
5210 : /* -------------------------------------------------------------------- */
5211 1256 : if ((pdfMin == nullptr ||
5212 628 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5213 203 : (pdfMax == nullptr ||
5214 203 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5215 1459 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5216 203 : (pdfStdDev == nullptr ||
5217 203 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5218 : {
5219 203 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5220 : {
5221 196 : if (pdfMin != nullptr)
5222 196 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5223 196 : if (pdfMax != nullptr)
5224 196 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5225 196 : if (pdfMean != nullptr)
5226 196 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5227 196 : if (pdfStdDev != nullptr)
5228 196 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5229 :
5230 196 : return CE_None;
5231 : }
5232 : }
5233 :
5234 : /* -------------------------------------------------------------------- */
5235 : /* Does the driver already know the min/max? */
5236 : /* -------------------------------------------------------------------- */
5237 432 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5238 : {
5239 1 : int bSuccessMin = FALSE;
5240 1 : int bSuccessMax = FALSE;
5241 :
5242 1 : const double dfMin = GetMinimum(&bSuccessMin);
5243 1 : const double dfMax = GetMaximum(&bSuccessMax);
5244 :
5245 1 : if (bSuccessMin && bSuccessMax)
5246 : {
5247 0 : if (pdfMin != nullptr)
5248 0 : *pdfMin = dfMin;
5249 0 : if (pdfMax != nullptr)
5250 0 : *pdfMax = dfMax;
5251 0 : return CE_None;
5252 : }
5253 : }
5254 :
5255 : /* -------------------------------------------------------------------- */
5256 : /* Either return without results, or force computation. */
5257 : /* -------------------------------------------------------------------- */
5258 432 : if (!bForce)
5259 176 : return CE_Warning;
5260 : else
5261 256 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5262 256 : GDALDummyProgress, nullptr);
5263 : }
5264 :
5265 : /************************************************************************/
5266 : /* GDALGetRasterStatistics() */
5267 : /************************************************************************/
5268 :
5269 : /**
5270 : * \brief Fetch image statistics.
5271 : *
5272 : * @see GDALRasterBand::GetStatistics()
5273 : */
5274 :
5275 276 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5276 : int bForce, double *pdfMin,
5277 : double *pdfMax, double *pdfMean,
5278 : double *pdfStdDev)
5279 :
5280 : {
5281 276 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5282 :
5283 276 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5284 276 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5285 276 : pdfStdDev);
5286 : }
5287 :
5288 : /************************************************************************/
5289 : /* GDALUInt128 */
5290 : /************************************************************************/
5291 :
5292 : #ifdef HAVE_UINT128_T
5293 : class GDALUInt128
5294 : {
5295 : __uint128_t val;
5296 :
5297 645 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5298 : {
5299 645 : }
5300 :
5301 : public:
5302 430 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5303 : {
5304 : // Evaluates to just a single mul on x86_64
5305 430 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5306 : }
5307 :
5308 215 : GDALUInt128 operator-(const GDALUInt128 &other) const
5309 : {
5310 215 : return GDALUInt128(val - other.val);
5311 : }
5312 :
5313 206 : operator double() const
5314 : {
5315 206 : return static_cast<double>(val);
5316 : }
5317 : };
5318 : #else
5319 :
5320 : #if defined(_MSC_VER) && defined(_M_X64)
5321 : #include <intrin.h>
5322 : #endif
5323 :
5324 : class GDALUInt128
5325 : {
5326 : GUIntBig low, high;
5327 :
5328 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5329 : {
5330 : }
5331 :
5332 : public:
5333 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5334 : {
5335 : #if defined(_MSC_VER) && defined(_M_X64)
5336 : GUIntBig highRes;
5337 : GUIntBig lowRes = _umul128(first, second, &highRes);
5338 : return GDALUInt128(lowRes, highRes);
5339 : #else
5340 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5341 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5342 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5343 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5344 : GUIntBig highRes = 0;
5345 : const GUIntBig firstLowSecondHigh =
5346 : static_cast<GUIntBig>(firstLow) * secondHigh;
5347 : const GUIntBig firstHighSecondLow =
5348 : static_cast<GUIntBig>(firstHigh) * secondLow;
5349 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5350 : if (middleTerm < firstLowSecondHigh) // check for overflow
5351 : highRes += static_cast<GUIntBig>(1) << 32;
5352 : const GUIntBig firstLowSecondLow =
5353 : static_cast<GUIntBig>(firstLow) * secondLow;
5354 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5355 : if (lowRes < firstLowSecondLow) // check for overflow
5356 : highRes++;
5357 : highRes +=
5358 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5359 : return GDALUInt128(lowRes, highRes);
5360 : #endif
5361 : }
5362 :
5363 : GDALUInt128 operator-(const GDALUInt128 &other) const
5364 : {
5365 : GUIntBig highRes = high - other.high;
5366 : GUIntBig lowRes = low - other.low;
5367 : if (lowRes > low) // check for underflow
5368 : --highRes;
5369 : return GDALUInt128(lowRes, highRes);
5370 : }
5371 :
5372 : operator double() const
5373 : {
5374 : const double twoPow64 = 18446744073709551616.0;
5375 : return high * twoPow64 + low;
5376 : }
5377 : };
5378 : #endif
5379 :
5380 : /************************************************************************/
5381 : /* ComputeStatisticsInternal() */
5382 : /************************************************************************/
5383 :
5384 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5385 : // not needed.
5386 : #define static_cast_for_coverity_scan static_cast
5387 :
5388 : // The rationale for below optimizations is detailed in statistics.txt
5389 :
5390 : // Use with T = GByte or GUInt16 only !
5391 : template <class T, bool COMPUTE_OTHER_STATS>
5392 : struct ComputeStatisticsInternalGeneric
5393 : {
5394 208 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5395 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5396 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5397 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5398 : {
5399 : static_assert(std::is_same<T, GByte>::value ||
5400 : std::is_same<T, GUInt16>::value,
5401 : "bad type for T");
5402 208 : if (bHasNoData)
5403 : {
5404 : // General case
5405 386 : for (int iY = 0; iY < nYCheck; iY++)
5406 : {
5407 81751 : for (int iX = 0; iX < nXCheck; iX++)
5408 : {
5409 81468 : const GPtrDiff_t iOffset =
5410 81468 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5411 81468 : const GUInt32 nValue = pData[iOffset];
5412 81468 : if (nValue == nNoDataValue)
5413 175 : continue;
5414 81293 : if (nValue < nMin)
5415 26 : nMin = nValue;
5416 81293 : if (nValue > nMax)
5417 57 : nMax = nValue;
5418 : if constexpr (COMPUTE_OTHER_STATS)
5419 : {
5420 79657 : nValidCount++;
5421 79657 : nSum += nValue;
5422 79657 : nSumSquare +=
5423 79657 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5424 79657 : nValue;
5425 : }
5426 : }
5427 : }
5428 : if constexpr (COMPUTE_OTHER_STATS)
5429 : {
5430 20 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5431 : }
5432 : }
5433 115 : else if (nMin == std::numeric_limits<T>::lowest() &&
5434 10 : nMax == std::numeric_limits<T>::max())
5435 : {
5436 : if constexpr (COMPUTE_OTHER_STATS)
5437 : {
5438 : // Optimization when there is no nodata and we know we have already
5439 : // reached the min and max
5440 208 : for (int iY = 0; iY < nYCheck; iY++)
5441 : {
5442 : int iX;
5443 1002 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5444 : {
5445 800 : const GPtrDiff_t iOffset =
5446 800 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5447 800 : const GUIntBig nValue = pData[iOffset];
5448 800 : const GUIntBig nValue2 = pData[iOffset + 1];
5449 800 : const GUIntBig nValue3 = pData[iOffset + 2];
5450 800 : const GUIntBig nValue4 = pData[iOffset + 3];
5451 800 : nSum += nValue;
5452 800 : nSumSquare += nValue * nValue;
5453 800 : nSum += nValue2;
5454 800 : nSumSquare += nValue2 * nValue2;
5455 800 : nSum += nValue3;
5456 800 : nSumSquare += nValue3 * nValue3;
5457 800 : nSum += nValue4;
5458 800 : nSumSquare += nValue4 * nValue4;
5459 : }
5460 207 : for (; iX < nXCheck; ++iX)
5461 : {
5462 5 : const GPtrDiff_t iOffset =
5463 5 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5464 5 : const GUIntBig nValue = pData[iOffset];
5465 5 : nSum += nValue;
5466 5 : nSumSquare += nValue * nValue;
5467 : }
5468 : }
5469 6 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5470 6 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5471 : }
5472 : }
5473 : else
5474 : {
5475 3434 : for (int iY = 0; iY < nYCheck; iY++)
5476 : {
5477 : int iX;
5478 643297 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5479 : {
5480 639962 : const GPtrDiff_t iOffset =
5481 639962 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5482 639962 : const GUInt32 nValue = pData[iOffset];
5483 639962 : const GUInt32 nValue2 = pData[iOffset + 1];
5484 639962 : if (nValue < nValue2)
5485 : {
5486 2320 : if (nValue < nMin)
5487 48 : nMin = nValue;
5488 2320 : if (nValue2 > nMax)
5489 116 : nMax = nValue2;
5490 : }
5491 : else
5492 : {
5493 637642 : if (nValue2 < nMin)
5494 66 : nMin = nValue2;
5495 637642 : if (nValue > nMax)
5496 215 : nMax = nValue;
5497 : }
5498 : if constexpr (COMPUTE_OTHER_STATS)
5499 : {
5500 632911 : nSum += nValue;
5501 632911 : nSumSquare +=
5502 632911 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5503 632911 : nValue;
5504 632911 : nSum += nValue2;
5505 632911 : nSumSquare +=
5506 632911 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5507 632911 : nValue2;
5508 : }
5509 : }
5510 3335 : if (iX < nXCheck)
5511 : {
5512 18 : const GPtrDiff_t iOffset =
5513 18 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5514 18 : const GUInt32 nValue = pData[iOffset];
5515 18 : if (nValue < nMin)
5516 13 : nMin = nValue;
5517 18 : if (nValue > nMax)
5518 14 : nMax = nValue;
5519 : if (COMPUTE_OTHER_STATS)
5520 : {
5521 9 : nSum += nValue;
5522 9 : nSumSquare +=
5523 9 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5524 9 : nValue;
5525 : }
5526 : }
5527 : }
5528 : if constexpr (COMPUTE_OTHER_STATS)
5529 : {
5530 44 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5531 44 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5532 : }
5533 : }
5534 208 : }
5535 : };
5536 :
5537 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5538 : // using 64bit accumulators in internal loops. This also slightly helps in
5539 : // 64bit mode.
5540 : template <bool COMPUTE_OTHER_STATS>
5541 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5542 : {
5543 13716 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5544 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5545 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5546 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5547 : {
5548 13716 : int nOuterLoops = nXCheck / 65536;
5549 13716 : if (nXCheck % 65536)
5550 13717 : nOuterLoops++;
5551 :
5552 13716 : if (bHasNoData)
5553 : {
5554 : // General case
5555 23475 : for (int iY = 0; iY < nYCheck; iY++)
5556 : {
5557 12901 : int iX = 0;
5558 25802 : for (int k = 0; k < nOuterLoops; k++)
5559 : {
5560 12901 : int iMax = iX + 65536;
5561 12901 : if (iMax > nXCheck)
5562 12901 : iMax = nXCheck;
5563 12901 : GUInt32 nSum32bit = 0;
5564 12901 : GUInt32 nSumSquare32bit = 0;
5565 12901 : GUInt32 nValidCount32bit = 0;
5566 12901 : GUInt32 nSampleCount32bit = 0;
5567 20707180 : for (; iX < iMax; iX++)
5568 : {
5569 20694328 : const GPtrDiff_t iOffset =
5570 20694328 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5571 20694328 : const GUInt32 nValue = pData[iOffset];
5572 :
5573 20694328 : nSampleCount32bit++;
5574 20694328 : if (nValue == nNoDataValue)
5575 20353462 : continue;
5576 340811 : if (nValue < nMin)
5577 357 : nMin = nValue;
5578 340811 : if (nValue > nMax)
5579 813 : nMax = nValue;
5580 : if constexpr (COMPUTE_OTHER_STATS)
5581 : {
5582 17066 : nValidCount32bit++;
5583 17066 : nSum32bit += nValue;
5584 17066 : nSumSquare32bit += nValue * nValue;
5585 : }
5586 : }
5587 : if constexpr (COMPUTE_OTHER_STATS)
5588 : {
5589 652 : nSampleCount += nSampleCount32bit;
5590 652 : nValidCount += nValidCount32bit;
5591 652 : nSum += nSum32bit;
5592 652 : nSumSquare += nSumSquare32bit;
5593 : }
5594 : }
5595 : }
5596 : }
5597 3142 : else if (nMin == 0 && nMax == 255)
5598 : {
5599 : if constexpr (COMPUTE_OTHER_STATS)
5600 : {
5601 : // Optimization when there is no nodata and we know we have already
5602 : // reached the min and max
5603 2644 : for (int iY = 0; iY < nYCheck; iY++)
5604 : {
5605 2617 : int iX = 0;
5606 5234 : for (int k = 0; k < nOuterLoops; k++)
5607 : {
5608 2617 : int iMax = iX + 65536;
5609 2617 : if (iMax > nXCheck)
5610 2617 : iMax = nXCheck;
5611 2617 : GUInt32 nSum32bit = 0;
5612 2617 : GUInt32 nSumSquare32bit = 0;
5613 176297 : for (; iX + 3 < iMax; iX += 4)
5614 : {
5615 173680 : const GPtrDiff_t iOffset =
5616 173680 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5617 173680 : const GUInt32 nValue = pData[iOffset];
5618 173680 : const GUInt32 nValue2 = pData[iOffset + 1];
5619 173680 : const GUInt32 nValue3 = pData[iOffset + 2];
5620 173680 : const GUInt32 nValue4 = pData[iOffset + 3];
5621 173680 : nSum32bit += nValue;
5622 173680 : nSumSquare32bit += nValue * nValue;
5623 173680 : nSum32bit += nValue2;
5624 173680 : nSumSquare32bit += nValue2 * nValue2;
5625 173680 : nSum32bit += nValue3;
5626 173680 : nSumSquare32bit += nValue3 * nValue3;
5627 173680 : nSum32bit += nValue4;
5628 173680 : nSumSquare32bit += nValue4 * nValue4;
5629 : }
5630 2617 : nSum += nSum32bit;
5631 2617 : nSumSquare += nSumSquare32bit;
5632 : }
5633 2620 : for (; iX < nXCheck; ++iX)
5634 : {
5635 3 : const GPtrDiff_t iOffset =
5636 3 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5637 3 : const GUIntBig nValue = pData[iOffset];
5638 3 : nSum += nValue;
5639 3 : nSumSquare += nValue * nValue;
5640 : }
5641 : }
5642 27 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5643 27 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5644 27 : }
5645 : }
5646 : else
5647 : {
5648 7922 : for (int iY = 0; iY < nYCheck; iY++)
5649 : {
5650 4807 : int iX = 0;
5651 9614 : for (int k = 0; k < nOuterLoops; k++)
5652 : {
5653 4807 : int iMax = iX + 65536;
5654 4807 : if (iMax > nXCheck)
5655 4807 : iMax = nXCheck;
5656 4807 : GUInt32 nSum32bit = 0;
5657 4807 : GUInt32 nSumSquare32bit = 0;
5658 159555 : for (; iX + 1 < iMax; iX += 2)
5659 : {
5660 154748 : const GPtrDiff_t iOffset =
5661 154748 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5662 154748 : const GUInt32 nValue = pData[iOffset];
5663 154748 : const GUInt32 nValue2 = pData[iOffset + 1];
5664 154748 : if (nValue < nValue2)
5665 : {
5666 8100 : if (nValue < nMin)
5667 232 : nMin = nValue;
5668 8100 : if (nValue2 > nMax)
5669 219 : nMax = nValue2;
5670 : }
5671 : else
5672 : {
5673 146648 : if (nValue2 < nMin)
5674 362 : nMin = nValue2;
5675 146648 : if (nValue > nMax)
5676 832 : nMax = nValue;
5677 : }
5678 : if constexpr (COMPUTE_OTHER_STATS)
5679 : {
5680 132611 : nSum32bit += nValue;
5681 132611 : nSumSquare32bit += nValue * nValue;
5682 132611 : nSum32bit += nValue2;
5683 132611 : nSumSquare32bit += nValue2 * nValue2;
5684 : }
5685 : }
5686 : if constexpr (COMPUTE_OTHER_STATS)
5687 : {
5688 1630 : nSum += nSum32bit;
5689 1630 : nSumSquare += nSumSquare32bit;
5690 : }
5691 : }
5692 4807 : if (iX < nXCheck)
5693 : {
5694 1515 : const GPtrDiff_t iOffset =
5695 1515 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5696 1515 : const GUInt32 nValue = pData[iOffset];
5697 1515 : if (nValue < nMin)
5698 108 : nMin = nValue;
5699 1515 : if (nValue > nMax)
5700 95 : nMax = nValue;
5701 : if constexpr (COMPUTE_OTHER_STATS)
5702 : {
5703 313 : nSum += nValue;
5704 313 : nSumSquare +=
5705 313 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5706 313 : nValue;
5707 : }
5708 : }
5709 : }
5710 : if constexpr (COMPUTE_OTHER_STATS)
5711 : {
5712 928 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5713 928 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5714 : }
5715 : }
5716 13716 : }
5717 : };
5718 :
5719 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5720 : {
5721 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5722 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5723 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5724 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5725 : {
5726 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5727 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5728 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5729 : }
5730 : };
5731 :
5732 : #if (defined(__x86_64__) || defined(_M_X64)) && \
5733 : (defined(__GNUC__) || defined(_MSC_VER))
5734 :
5735 : #include "gdal_avx2_emulation.hpp"
5736 :
5737 : #define ZERO256 GDALmm256_setzero_si256()
5738 :
5739 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5740 : static void
5741 21318 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5742 : // assumed to be aligned on 256 bits
5743 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5744 : GUIntBig &nSum, GUIntBig &nSumSquare,
5745 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5746 : {
5747 : // 32-byte alignment may not be enforced by linker, so do it at hand
5748 : GByte
5749 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5750 21318 : GByte *paby32ByteAligned =
5751 : aby32ByteUnaligned +
5752 21318 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5753 21318 : GByte *pabyMin = paby32ByteAligned;
5754 21318 : GByte *pabyMax = paby32ByteAligned + 32;
5755 21318 : GUInt32 *panSum =
5756 : COMPUTE_OTHER_STATS
5757 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5758 : : nullptr;
5759 21318 : GUInt32 *panSumSquare =
5760 : COMPUTE_OTHER_STATS
5761 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5762 : : nullptr;
5763 :
5764 21318 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5765 :
5766 21318 : GPtrDiff_t i = 0;
5767 : // Make sure that sumSquare can fit on uint32
5768 : // * 8 since we can hold 8 sums per vector register
5769 21318 : const int nMaxIterationsPerInnerLoop =
5770 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5771 21318 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5772 21318 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5773 21318 : nOuterLoops++;
5774 :
5775 : GDALm256i ymm_min =
5776 21318 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5777 21318 : GDALm256i ymm_max = ymm_min;
5778 21318 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5779 :
5780 42636 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5781 : {
5782 21318 : const auto iMax =
5783 21318 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5784 :
5785 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5786 21318 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5787 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5788 21318 : ZERO256; // holds 8 uint32 sums
5789 714085 : for (; i + 31 < iMax; i += 32)
5790 : {
5791 692767 : const GDALm256i ymm = GDALmm256_load_si256(
5792 692767 : reinterpret_cast<const GDALm256i *>(pData + i));
5793 : if (COMPUTE_MIN)
5794 : {
5795 234930 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5796 : }
5797 : if (COMPUTE_MAX)
5798 : {
5799 603612 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5800 : }
5801 :
5802 : if constexpr (COMPUTE_OTHER_STATS)
5803 : {
5804 : // Extract even-8bit values
5805 : const GDALm256i ymm_even =
5806 493495 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5807 : // Compute square of those 16 values as 32 bit result
5808 : // and add adjacent pairs
5809 : const GDALm256i ymm_even_square =
5810 493495 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5811 : // Add to the sumsquare accumulator
5812 : ymm_sumsquare =
5813 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5814 :
5815 : // Extract odd-8bit values
5816 493495 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5817 : const GDALm256i ymm_odd_square =
5818 493495 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5819 : ymm_sumsquare =
5820 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5821 :
5822 : // Now compute the sums
5823 493495 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5824 : GDALmm256_sad_epu8(ymm, ZERO256));
5825 : }
5826 : }
5827 :
5828 : if constexpr (COMPUTE_OTHER_STATS)
5829 : {
5830 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5831 : ymm_sum);
5832 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5833 : ymm_sumsquare);
5834 :
5835 10649 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5836 10649 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5837 10649 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5838 10649 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5839 : panSumSquare[7];
5840 : }
5841 : }
5842 :
5843 : if constexpr (COMPUTE_MIN)
5844 : {
5845 8444 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5846 : }
5847 : if constexpr (COMPUTE_MAX)
5848 : {
5849 17328 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5850 : }
5851 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5852 : {
5853 589083 : for (int j = 0; j < 32; j++)
5854 : {
5855 : if constexpr (COMPUTE_MIN)
5856 : {
5857 270208 : if (pabyMin[j] < nMin)
5858 1231 : nMin = pabyMin[j];
5859 : }
5860 : if constexpr (COMPUTE_MAX)
5861 : {
5862 554496 : if (pabyMax[j] > nMax)
5863 1788 : nMax = pabyMax[j];
5864 : }
5865 : }
5866 : }
5867 :
5868 234312 : for (; i < nBlockPixels; i++)
5869 : {
5870 212994 : const GUInt32 nValue = pData[i];
5871 : if constexpr (COMPUTE_MIN)
5872 : {
5873 88318 : if (nValue < nMin)
5874 1 : nMin = nValue;
5875 : }
5876 : if constexpr (COMPUTE_MAX)
5877 : {
5878 210219 : if (nValue > nMax)
5879 1149 : nMax = nValue;
5880 : }
5881 : if constexpr (COMPUTE_OTHER_STATS)
5882 : {
5883 77195 : nSum += nValue;
5884 77195 : nSumSquare +=
5885 77195 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5886 : }
5887 : }
5888 :
5889 : if constexpr (COMPUTE_OTHER_STATS)
5890 : {
5891 10649 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5892 10649 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5893 : }
5894 21318 : }
5895 :
5896 : // SSE2/AVX2 optimization for GByte case
5897 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5898 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5899 : // there are strictly equivalent to 2 parallel SSE2 streams.
5900 : template <bool COMPUTE_OTHER_STATS>
5901 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5902 : {
5903 30170 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5904 : // assumed to be aligned on 256 bits
5905 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5906 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5907 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5908 : GUIntBig &nValidCount)
5909 : {
5910 30170 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5911 30170 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5912 11574 : nMin <= nMax)
5913 : {
5914 : // 32-byte alignment may not be enforced by linker, so do it at hand
5915 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5916 1459 : GByte *paby32ByteAligned =
5917 : aby32ByteUnaligned +
5918 1459 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5919 1459 : GByte *pabyMin = paby32ByteAligned;
5920 1459 : GByte *pabyMax = paby32ByteAligned + 32;
5921 1459 : GUInt32 *panSum =
5922 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5923 1459 : GUInt32 *panSumSquare =
5924 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5925 :
5926 1459 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5927 :
5928 1459 : GPtrDiff_t i = 0;
5929 : // Make sure that sumSquare can fit on uint32
5930 : // * 8 since we can hold 8 sums per vector register
5931 1459 : const int nMaxIterationsPerInnerLoop =
5932 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5933 1459 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5934 1459 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5935 1459 : nOuterLoops++;
5936 :
5937 : const GDALm256i ymm_nodata =
5938 1459 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5939 : // any non noData value in [min,max] would do.
5940 : const GDALm256i ymm_neutral =
5941 1459 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5942 1459 : GDALm256i ymm_min = ymm_neutral;
5943 1459 : GDALm256i ymm_max = ymm_neutral;
5944 : [[maybe_unused]] const auto ymm_mask_8bits =
5945 1459 : GDALmm256_set1_epi16(0xFF);
5946 :
5947 1459 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5948 1459 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5949 1459 : const bool bComputeMinMax =
5950 1459 : nMin > nMinThreshold || nMax < nMaxThreshold;
5951 :
5952 2918 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5953 : {
5954 1459 : const auto iMax =
5955 1459 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5956 :
5957 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5958 1459 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5959 : // holds 8 uint32 sums
5960 1459 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5961 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5962 1459 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5963 1459 : const auto iInit = i;
5964 14435 : for (; i + 31 < iMax; i += 32)
5965 : {
5966 12976 : const GDALm256i ymm = GDALmm256_load_si256(
5967 12976 : reinterpret_cast<const GDALm256i *>(pData + i));
5968 :
5969 : // Check which values are nodata
5970 : const GDALm256i ymm_eq_nodata =
5971 12976 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5972 : if constexpr (COMPUTE_OTHER_STATS)
5973 : {
5974 : // Count how many values are nodata (due to cmpeq
5975 : // putting 255 when condition is met, this will actually
5976 : // be 255 times the number of nodata value, spread in 4
5977 : // 64 bits words). We can use add_epi32 as the counter
5978 : // will not overflow uint32
5979 4634 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5980 : ymm_count_nodata_mul_255,
5981 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5982 : }
5983 : // Replace all nodata values by zero for the purpose of sum
5984 : // and sumquare.
5985 : const GDALm256i ymm_nodata_by_zero =
5986 12976 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5987 12976 : if (bComputeMinMax)
5988 : {
5989 : // Replace all nodata values by a neutral value for the
5990 : // purpose of min and max.
5991 : const GDALm256i ymm_nodata_by_neutral =
5992 8591 : GDALmm256_or_si256(
5993 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5994 : ymm_nodata_by_zero);
5995 :
5996 : ymm_min =
5997 8591 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5998 : ymm_max =
5999 8591 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6000 : }
6001 :
6002 : if constexpr (COMPUTE_OTHER_STATS)
6003 : {
6004 : // Extract even-8bit values
6005 4634 : const GDALm256i ymm_even = GDALmm256_and_si256(
6006 : ymm_nodata_by_zero, ymm_mask_8bits);
6007 : // Compute square of those 16 values as 32 bit result
6008 : // and add adjacent pairs
6009 : const GDALm256i ymm_even_square =
6010 4634 : GDALmm256_madd_epi16(ymm_even, ymm_even);
6011 : // Add to the sumsquare accumulator
6012 : ymm_sumsquare =
6013 4634 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6014 :
6015 : // Extract odd-8bit values
6016 : const GDALm256i ymm_odd =
6017 4634 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6018 : const GDALm256i ymm_odd_square =
6019 4634 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6020 : ymm_sumsquare =
6021 4634 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6022 :
6023 : // Now compute the sums
6024 4634 : ymm_sum = GDALmm256_add_epi32(
6025 : ymm_sum,
6026 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6027 : }
6028 : }
6029 :
6030 : if constexpr (COMPUTE_OTHER_STATS)
6031 : {
6032 153 : GUInt32 *panCoutNoDataMul255 = panSum;
6033 153 : GDALmm256_store_si256(
6034 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6035 : ymm_count_nodata_mul_255);
6036 :
6037 153 : nSampleCount += (i - iInit);
6038 :
6039 153 : nValidCount +=
6040 153 : (i - iInit) -
6041 153 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6042 153 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6043 : 255;
6044 :
6045 153 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6046 : ymm_sum);
6047 153 : GDALmm256_store_si256(
6048 : reinterpret_cast<GDALm256i *>(panSumSquare),
6049 : ymm_sumsquare);
6050 153 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6051 153 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6052 153 : panSumSquare[1] + panSumSquare[2] +
6053 153 : panSumSquare[3] + panSumSquare[4] +
6054 153 : panSumSquare[5] + panSumSquare[6] +
6055 : panSumSquare[7];
6056 : }
6057 : }
6058 :
6059 1459 : if (bComputeMinMax)
6060 : {
6061 1428 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6062 : ymm_min);
6063 1428 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6064 : ymm_max);
6065 47124 : for (int j = 0; j < 32; j++)
6066 : {
6067 45696 : if (pabyMin[j] < nMin)
6068 40 : nMin = pabyMin[j];
6069 45696 : if (pabyMax[j] > nMax)
6070 159 : nMax = pabyMax[j];
6071 : }
6072 : }
6073 :
6074 : if constexpr (COMPUTE_OTHER_STATS)
6075 : {
6076 153 : nSampleCount += nBlockPixels - i;
6077 : }
6078 33905 : for (; i < nBlockPixels; i++)
6079 : {
6080 32446 : const GUInt32 nValue = pData[i];
6081 32446 : if (nValue == nNoDataValue)
6082 24923 : continue;
6083 7523 : if (nValue < nMin)
6084 1 : nMin = nValue;
6085 7523 : if (nValue > nMax)
6086 13 : nMax = nValue;
6087 : if constexpr (COMPUTE_OTHER_STATS)
6088 : {
6089 3590 : nValidCount++;
6090 3590 : nSum += nValue;
6091 3590 : nSumSquare +=
6092 3590 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6093 3590 : nValue;
6094 : }
6095 1459 : }
6096 : }
6097 28711 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6098 : {
6099 14962 : if (nMin > 0)
6100 : {
6101 2088 : if (nMax < 255)
6102 : {
6103 : ComputeStatisticsByteNoNodata<true, true,
6104 1565 : COMPUTE_OTHER_STATS>(
6105 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6106 : nSampleCount, nValidCount);
6107 : }
6108 : else
6109 : {
6110 : ComputeStatisticsByteNoNodata<true, false,
6111 523 : COMPUTE_OTHER_STATS>(
6112 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6113 : nSampleCount, nValidCount);
6114 : }
6115 : }
6116 : else
6117 : {
6118 12874 : if (nMax < 255)
6119 : {
6120 : ComputeStatisticsByteNoNodata<false, true,
6121 9407 : COMPUTE_OTHER_STATS>(
6122 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6123 : nSampleCount, nValidCount);
6124 : }
6125 : else
6126 : {
6127 : ComputeStatisticsByteNoNodata<false, false,
6128 3467 : COMPUTE_OTHER_STATS>(
6129 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6130 : nSampleCount, nValidCount);
6131 : }
6132 : }
6133 : }
6134 12475 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6135 33 : (nBlockXSize % 32) == 0)
6136 : {
6137 6389 : for (int iY = 0; iY < nYCheck; iY++)
6138 : {
6139 6356 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6140 6356 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6141 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6142 33 : }
6143 : }
6144 : else
6145 : {
6146 13716 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6147 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6148 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6149 : }
6150 30170 : }
6151 : };
6152 :
6153 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6154 400 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6155 : GUIntBig i)
6156 : {
6157 400 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6158 400 : }
6159 :
6160 : // AVX2/SSE2 optimization for GUInt16 case
6161 : template <bool COMPUTE_OTHER_STATS>
6162 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6163 : {
6164 1882 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
6165 : // assumed to be aligned on 128 bits
6166 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6167 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6168 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6169 : GUIntBig &nValidCount)
6170 : {
6171 1882 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6172 1882 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6173 : {
6174 1674 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6175 :
6176 1674 : GPtrDiff_t i = 0;
6177 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6178 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6179 : // Furthermore the shift is also needed to use madd_epi16
6180 1674 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6181 1674 : GDALm256i ymm_min = GDALmm256_load_si256(
6182 1674 : reinterpret_cast<const GDALm256i *>(pData + i));
6183 1674 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6184 1674 : GDALm256i ymm_max = ymm_min;
6185 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6186 1674 : ZERO256; // holds 4 uint64 sums
6187 :
6188 : // Make sure that sum can fit on uint32
6189 : // * 8 since we can hold 8 sums per vector register
6190 1674 : const int nMaxIterationsPerInnerLoop =
6191 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6192 1674 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6193 1674 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6194 1674 : nOuterLoops++;
6195 :
6196 1674 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6197 : [[maybe_unused]] const auto ymm_mask_16bits =
6198 1674 : GDALmm256_set1_epi32(0xFFFF);
6199 : [[maybe_unused]] const auto ymm_mask_32bits =
6200 1674 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6201 :
6202 1674 : GUIntBig nSumThis = 0;
6203 3372 : for (int k = 0; k < nOuterLoops; k++)
6204 : {
6205 1698 : const auto iMax =
6206 1698 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6207 :
6208 : [[maybe_unused]] GDALm256i ymm_sum =
6209 1698 : ZERO256; // holds 8 uint32 sums
6210 964126 : for (; i + 15 < iMax; i += 16)
6211 : {
6212 962428 : const GDALm256i ymm = GDALmm256_load_si256(
6213 962428 : reinterpret_cast<const GDALm256i *>(pData + i));
6214 : const GDALm256i ymm_shifted =
6215 962428 : GDALmm256_add_epi16(ymm, ymm_m32768);
6216 962428 : if (bComputeMinMax)
6217 : {
6218 953409 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6219 953409 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6220 : }
6221 :
6222 : if constexpr (COMPUTE_OTHER_STATS)
6223 : {
6224 : // Note: the int32 range can overflow for (0-32768)^2 +
6225 : // (0-32768)^2 = 0x80000000, but as we know the result
6226 : // is positive, this is OK as we interpret is a uint32.
6227 : const GDALm256i ymm_square =
6228 95410 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6229 95410 : ymm_sumsquare = GDALmm256_add_epi64(
6230 : ymm_sumsquare,
6231 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6232 95410 : ymm_sumsquare = GDALmm256_add_epi64(
6233 : ymm_sumsquare,
6234 : GDALmm256_srli_epi64(ymm_square, 32));
6235 :
6236 : // Now compute the sums
6237 95410 : ymm_sum = GDALmm256_add_epi32(
6238 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6239 95410 : ymm_sum = GDALmm256_add_epi32(
6240 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6241 : }
6242 : }
6243 :
6244 : if constexpr (COMPUTE_OTHER_STATS)
6245 : {
6246 : GUInt32 anSum[8];
6247 400 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6248 : ymm_sum);
6249 400 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6250 400 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6251 400 : anSum[6] + anSum[7];
6252 : }
6253 : }
6254 :
6255 1674 : if (bComputeMinMax)
6256 : {
6257 : GUInt16 anMin[16];
6258 : GUInt16 anMax[16];
6259 :
6260 : // Unshift the result
6261 1633 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6262 1633 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6263 1633 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6264 : ymm_min);
6265 1633 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6266 : ymm_max);
6267 27761 : for (int j = 0; j < 16; j++)
6268 : {
6269 26128 : if (anMin[j] < nMin)
6270 342 : nMin = anMin[j];
6271 26128 : if (anMax[j] > nMax)
6272 482 : nMax = anMax[j];
6273 : }
6274 : }
6275 :
6276 : if constexpr (COMPUTE_OTHER_STATS)
6277 : {
6278 : GUIntBig anSumSquare[4];
6279 400 : GDALmm256_storeu_si256(
6280 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6281 400 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6282 : anSumSquare[3];
6283 :
6284 : // Unshift the sum of squares
6285 400 : UnshiftSumSquare(nSumSquare, nSumThis,
6286 : static_cast<GUIntBig>(i));
6287 :
6288 400 : nSum += nSumThis;
6289 :
6290 722 : for (; i < nBlockPixels; i++)
6291 : {
6292 322 : const GUInt32 nValue = pData[i];
6293 322 : if (nValue < nMin)
6294 1 : nMin = nValue;
6295 322 : if (nValue > nMax)
6296 1 : nMax = nValue;
6297 322 : nSum += nValue;
6298 322 : nSumSquare +=
6299 322 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6300 322 : nValue;
6301 : }
6302 :
6303 400 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6304 400 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6305 1674 : }
6306 : }
6307 : else
6308 : {
6309 208 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6310 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6311 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6312 : }
6313 1882 : }
6314 : };
6315 :
6316 : #endif
6317 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6318 : // defined(_MSC_VER))
6319 :
6320 : /************************************************************************/
6321 : /* GetPixelValue() */
6322 : /************************************************************************/
6323 :
6324 23806300 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6325 : const void *pData, GPtrDiff_t iOffset,
6326 : const GDALNoDataValues &sNoDataValues,
6327 : bool &bValid)
6328 : {
6329 23806300 : bValid = true;
6330 23806300 : double dfValue = 0;
6331 23806300 : switch (eDataType)
6332 : {
6333 1400770 : case GDT_Byte:
6334 : {
6335 1400770 : if (bSignedByte)
6336 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6337 : else
6338 1400580 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6339 1400770 : break;
6340 : }
6341 10409 : case GDT_Int8:
6342 10409 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6343 10409 : break;
6344 200608 : case GDT_UInt16:
6345 200608 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6346 200608 : break;
6347 60193 : case GDT_Int16:
6348 60193 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6349 60193 : break;
6350 27600 : case GDT_UInt32:
6351 27600 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6352 27600 : break;
6353 456810 : case GDT_Int32:
6354 456810 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6355 456810 : break;
6356 2604 : case GDT_UInt64:
6357 2604 : dfValue = static_cast<double>(
6358 2604 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6359 2604 : break;
6360 7404 : case GDT_Int64:
6361 7404 : dfValue = static_cast<double>(
6362 7404 : static_cast<const std::int64_t *>(pData)[iOffset]);
6363 7404 : break;
6364 0 : case GDT_Float16:
6365 : {
6366 : using namespace std;
6367 0 : const GFloat16 hfValue =
6368 0 : static_cast<const GFloat16 *>(pData)[iOffset];
6369 0 : if (isnan(hfValue) ||
6370 0 : (sNoDataValues.bGotFloat16NoDataValue &&
6371 0 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6372 : {
6373 0 : bValid = false;
6374 0 : return 0.0;
6375 : }
6376 0 : dfValue = hfValue;
6377 0 : return dfValue;
6378 : }
6379 17933900 : case GDT_Float32:
6380 : {
6381 17933900 : const float fValue = static_cast<const float *>(pData)[iOffset];
6382 35841000 : if (std::isnan(fValue) ||
6383 31043800 : (sNoDataValues.bGotFloatNoDataValue &&
6384 13136700 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6385 : {
6386 26881 : bValid = false;
6387 26881 : return 0.0;
6388 : }
6389 17907100 : dfValue = double(fValue);
6390 17907100 : return dfValue;
6391 : }
6392 3688930 : case GDT_Float64:
6393 3688930 : dfValue = static_cast<const double *>(pData)[iOffset];
6394 3688930 : if (std::isnan(dfValue))
6395 : {
6396 52 : bValid = false;
6397 52 : return 0.0;
6398 : }
6399 3688880 : break;
6400 2692 : case GDT_CInt16:
6401 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6402 2692 : break;
6403 2692 : case GDT_CInt32:
6404 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6405 2692 : break;
6406 0 : case GDT_CFloat16:
6407 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6408 0 : if (std::isnan(dfValue))
6409 : {
6410 0 : bValid = false;
6411 0 : return 0.0;
6412 : }
6413 0 : break;
6414 5812 : case GDT_CFloat32:
6415 5812 : dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6416 5812 : if (std::isnan(dfValue))
6417 : {
6418 0 : bValid = false;
6419 0 : return 0.0;
6420 : }
6421 5812 : break;
6422 5892 : case GDT_CFloat64:
6423 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6424 5892 : if (std::isnan(dfValue))
6425 : {
6426 0 : bValid = false;
6427 0 : return 0.0;
6428 : }
6429 5892 : break;
6430 0 : case GDT_Unknown:
6431 : case GDT_TypeCount:
6432 0 : CPLAssert(false);
6433 : break;
6434 : }
6435 :
6436 9613360 : if (sNoDataValues.bGotNoDataValue &&
6437 3740990 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6438 : {
6439 3346220 : bValid = false;
6440 3346220 : return 0.0;
6441 : }
6442 2526140 : return dfValue;
6443 : }
6444 :
6445 : /************************************************************************/
6446 : /* SetValidPercent() */
6447 : /************************************************************************/
6448 :
6449 : //! @cond Doxygen_Suppress
6450 : /**
6451 : * \brief Set percentage of valid (not nodata) pixels.
6452 : *
6453 : * Stores the percentage of valid pixels in the metadata item
6454 : * STATISTICS_VALID_PERCENT
6455 : *
6456 : * @param nSampleCount Number of sampled pixels.
6457 : *
6458 : * @param nValidCount Number of valid pixels.
6459 : */
6460 :
6461 495 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6462 : GUIntBig nValidCount)
6463 : {
6464 495 : if (nValidCount == 0)
6465 : {
6466 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6467 : }
6468 483 : else if (nValidCount == nSampleCount)
6469 : {
6470 436 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6471 : }
6472 : else /* nValidCount < nSampleCount */
6473 : {
6474 47 : char szValue[128] = {0};
6475 :
6476 : /* percentage is only an indicator: limit precision */
6477 47 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6478 47 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6479 :
6480 47 : if (EQUAL(szValue, "100"))
6481 : {
6482 : /* don't set 100 percent valid
6483 : * because some of the sampled pixels were nodata */
6484 0 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6485 : }
6486 : else
6487 : {
6488 47 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6489 : }
6490 : }
6491 495 : }
6492 :
6493 : //! @endcond
6494 :
6495 : /************************************************************************/
6496 : /* ComputeStatistics() */
6497 : /************************************************************************/
6498 :
6499 : /**
6500 : * \brief Compute image statistics.
6501 : *
6502 : * Returns the minimum, maximum, mean and standard deviation of all
6503 : * pixel values in this band. If approximate statistics are sufficient,
6504 : * the bApproxOK flag can be set to true in which case overviews, or a
6505 : * subset of image tiles may be used in computing the statistics.
6506 : *
6507 : * Once computed, the statistics will generally be "set" back on the
6508 : * raster band using SetStatistics().
6509 : *
6510 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6511 : *
6512 : * This method is the same as the C function GDALComputeRasterStatistics().
6513 : *
6514 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6515 : * or a subset of all tiles.
6516 : *
6517 : * @param pdfMin Location into which to load image minimum (may be NULL).
6518 : *
6519 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6520 : *
6521 : * @param pdfMean Location into which to load image mean (may be NULL).
6522 : *
6523 : * @param pdfStdDev Location into which to load image standard deviation
6524 : * (may be NULL).
6525 : *
6526 : * @param pfnProgress a function to call to report progress, or NULL.
6527 : *
6528 : * @param pProgressData application data to pass to the progress function.
6529 : *
6530 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6531 : * is terminated by the user.
6532 : */
6533 :
6534 473 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6535 : double *pdfMax, double *pdfMean,
6536 : double *pdfStdDev,
6537 : GDALProgressFunc pfnProgress,
6538 : void *pProgressData)
6539 :
6540 : {
6541 473 : if (pfnProgress == nullptr)
6542 170 : pfnProgress = GDALDummyProgress;
6543 :
6544 : /* -------------------------------------------------------------------- */
6545 : /* If we have overview bands, use them for statistics. */
6546 : /* -------------------------------------------------------------------- */
6547 473 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6548 : {
6549 : GDALRasterBand *poBand =
6550 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6551 :
6552 3 : if (poBand != this)
6553 : {
6554 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6555 : pdfMean, pdfStdDev,
6556 3 : pfnProgress, pProgressData);
6557 3 : if (eErr == CE_None)
6558 : {
6559 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6560 : {
6561 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6562 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6563 : }
6564 :
6565 : /* transfer metadata from overview band to this */
6566 : const char *pszPercentValid =
6567 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6568 :
6569 3 : if (pszPercentValid != nullptr)
6570 : {
6571 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6572 3 : pszPercentValid);
6573 : }
6574 : }
6575 3 : return eErr;
6576 : }
6577 : }
6578 :
6579 470 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6580 : {
6581 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6582 0 : return CE_Failure;
6583 : }
6584 :
6585 : /* -------------------------------------------------------------------- */
6586 : /* Read actual data and compute statistics. */
6587 : /* -------------------------------------------------------------------- */
6588 : // Using Welford algorithm:
6589 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6590 : // to compute standard deviation in a more numerically robust way than
6591 : // the difference of the sum of square values with the square of the sum.
6592 : // dfMean and dfM2 are updated at each sample.
6593 : // dfM2 is the sum of square of differences to the current mean.
6594 469 : double dfMin = std::numeric_limits<double>::infinity();
6595 469 : double dfMax = -std::numeric_limits<double>::infinity();
6596 469 : double dfMean = 0.0;
6597 469 : double dfM2 = 0.0;
6598 :
6599 : GDALRasterIOExtraArg sExtraArg;
6600 469 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6601 :
6602 469 : GDALNoDataValues sNoDataValues(this, eDataType);
6603 470 : GDALRasterBand *poMaskBand = nullptr;
6604 470 : if (!sNoDataValues.bGotNoDataValue)
6605 : {
6606 443 : const int l_nMaskFlags = GetMaskFlags();
6607 487 : if (l_nMaskFlags != GMF_ALL_VALID &&
6608 44 : GetColorInterpretation() != GCI_AlphaBand)
6609 : {
6610 44 : poMaskBand = GetMaskBand();
6611 : }
6612 : }
6613 :
6614 470 : bool bSignedByte = false;
6615 470 : if (eDataType == GDT_Byte)
6616 : {
6617 203 : EnablePixelTypeSignedByteWarning(false);
6618 : const char *pszPixelType =
6619 203 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6620 203 : EnablePixelTypeSignedByteWarning(true);
6621 203 : bSignedByte =
6622 203 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6623 : }
6624 :
6625 470 : GUIntBig nSampleCount = 0;
6626 470 : GUIntBig nValidCount = 0;
6627 :
6628 470 : if (bApproxOK && HasArbitraryOverviews())
6629 : {
6630 : /* --------------------------------------------------------------------
6631 : */
6632 : /* Figure out how much the image should be reduced to get an */
6633 : /* approximate value. */
6634 : /* --------------------------------------------------------------------
6635 : */
6636 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6637 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6638 :
6639 0 : int nXReduced = nRasterXSize;
6640 0 : int nYReduced = nRasterYSize;
6641 0 : if (dfReduction > 1.0)
6642 : {
6643 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6644 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6645 :
6646 : // Catch the case of huge resizing ratios here
6647 0 : if (nXReduced == 0)
6648 0 : nXReduced = 1;
6649 0 : if (nYReduced == 0)
6650 0 : nYReduced = 1;
6651 : }
6652 :
6653 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
6654 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6655 :
6656 : const CPLErr eErr =
6657 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6658 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6659 0 : if (eErr != CE_None)
6660 : {
6661 0 : CPLFree(pData);
6662 0 : return eErr;
6663 : }
6664 :
6665 0 : GByte *pabyMaskData = nullptr;
6666 0 : if (poMaskBand)
6667 : {
6668 : pabyMaskData =
6669 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6670 0 : if (!pabyMaskData)
6671 : {
6672 0 : CPLFree(pData);
6673 0 : return CE_Failure;
6674 : }
6675 :
6676 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6677 : pabyMaskData, nXReduced, nYReduced,
6678 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
6679 : {
6680 0 : CPLFree(pData);
6681 0 : CPLFree(pabyMaskData);
6682 0 : return CE_Failure;
6683 : }
6684 : }
6685 :
6686 : /* this isn't the fastest way to do this, but is easier for now */
6687 0 : for (int iY = 0; iY < nYReduced; iY++)
6688 : {
6689 0 : for (int iX = 0; iX < nXReduced; iX++)
6690 : {
6691 0 : const int iOffset = iX + iY * nXReduced;
6692 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6693 0 : continue;
6694 :
6695 0 : bool bValid = true;
6696 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
6697 0 : iOffset, sNoDataValues, bValid);
6698 0 : if (!bValid)
6699 0 : continue;
6700 :
6701 0 : dfMin = std::min(dfMin, dfValue);
6702 0 : dfMax = std::max(dfMax, dfValue);
6703 :
6704 0 : nValidCount++;
6705 0 : if (dfMin == dfMax)
6706 : {
6707 0 : if (nValidCount == 1)
6708 0 : dfMean = dfMin;
6709 : }
6710 : else
6711 : {
6712 0 : const double dfDelta = dfValue - dfMean;
6713 0 : dfMean += dfDelta / nValidCount;
6714 0 : dfM2 += dfDelta * (dfValue - dfMean);
6715 : }
6716 : }
6717 : }
6718 :
6719 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6720 :
6721 0 : CPLFree(pData);
6722 0 : CPLFree(pabyMaskData);
6723 : }
6724 :
6725 : else // No arbitrary overviews.
6726 : {
6727 470 : if (!InitBlockInfo())
6728 0 : return CE_Failure;
6729 :
6730 : /* --------------------------------------------------------------------
6731 : */
6732 : /* Figure out the ratio of blocks we will read to get an */
6733 : /* approximate value. */
6734 : /* --------------------------------------------------------------------
6735 : */
6736 470 : int nSampleRate = 1;
6737 470 : if (bApproxOK)
6738 : {
6739 43 : nSampleRate = static_cast<int>(std::max(
6740 86 : 1.0,
6741 43 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6742 : // We want to avoid probing only the first column of blocks for
6743 : // a square shaped raster, because it is not unlikely that it may
6744 : // be padding only (#6378)
6745 43 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6746 1 : nSampleRate += 1;
6747 : }
6748 470 : if (nSampleRate == 1)
6749 436 : bApproxOK = false;
6750 :
6751 : // Particular case for GDT_Byte that only use integral types for all
6752 : // intermediate computations. Only possible if the number of pixels
6753 : // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6754 : // can fit on a uint64. Should be 99.99999% of cases.
6755 : // For GUInt16, this limits to raster of 4 giga pixels
6756 470 : if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6757 186 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6758 186 : nSampleRate <
6759 186 : GUINTBIG_MAX / (255U * 255U) /
6760 186 : (static_cast<GUInt64>(nBlockXSize) *
6761 186 : static_cast<GUInt64>(nBlockYSize))) ||
6762 284 : (eDataType == GDT_UInt16 &&
6763 29 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6764 29 : nSampleRate <
6765 29 : GUINTBIG_MAX / (65535U * 65535U) /
6766 29 : (static_cast<GUInt64>(nBlockXSize) *
6767 29 : static_cast<GUInt64>(nBlockYSize))))
6768 : {
6769 215 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6770 215 : GUInt32 nMin = nMaxValueType;
6771 215 : GUInt32 nMax = 0;
6772 215 : GUIntBig nSum = 0;
6773 215 : GUIntBig nSumSquare = 0;
6774 : // If no valid nodata, map to invalid value (256 for Byte)
6775 215 : const GUInt32 nNoDataValue =
6776 238 : (sNoDataValues.bGotNoDataValue &&
6777 23 : sNoDataValues.dfNoDataValue >= 0 &&
6778 23 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
6779 23 : fabs(sNoDataValues.dfNoDataValue -
6780 23 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
6781 : 1e-10)) < 1e-10)
6782 238 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
6783 : : nMaxValueType + 1;
6784 :
6785 215 : for (GIntBig iSampleBlock = 0;
6786 12762 : iSampleBlock <
6787 12762 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6788 12547 : iSampleBlock += nSampleRate)
6789 : {
6790 12547 : const int iYBlock =
6791 12547 : static_cast<int>(iSampleBlock / nBlocksPerRow);
6792 12547 : const int iXBlock =
6793 12547 : static_cast<int>(iSampleBlock % nBlocksPerRow);
6794 :
6795 : GDALRasterBlock *const poBlock =
6796 12547 : GetLockedBlockRef(iXBlock, iYBlock);
6797 12547 : if (poBlock == nullptr)
6798 0 : return CE_Failure;
6799 :
6800 12547 : void *const pData = poBlock->GetDataRef();
6801 :
6802 12546 : int nXCheck = 0, nYCheck = 0;
6803 12546 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6804 :
6805 12547 : if (eDataType == GDT_Byte)
6806 : {
6807 : ComputeStatisticsInternal<
6808 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
6809 12077 : f(nXCheck, nBlockXSize, nYCheck,
6810 : static_cast<const GByte *>(pData),
6811 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6812 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6813 : }
6814 : else
6815 : {
6816 : ComputeStatisticsInternal<
6817 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6818 470 : f(nXCheck, nBlockXSize, nYCheck,
6819 : static_cast<const GUInt16 *>(pData),
6820 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6821 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6822 : }
6823 :
6824 12545 : poBlock->DropLock();
6825 :
6826 12547 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
6827 12546 : (static_cast<double>(nBlocksPerRow) *
6828 12546 : nBlocksPerColumn),
6829 : "Compute Statistics", pProgressData))
6830 : {
6831 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
6832 : "User terminated");
6833 0 : return CE_Failure;
6834 : }
6835 : }
6836 :
6837 215 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6838 : {
6839 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6840 0 : return CE_Failure;
6841 : }
6842 :
6843 : /* --------------------------------------------------------------------
6844 : */
6845 : /* Save computed information. */
6846 : /* --------------------------------------------------------------------
6847 : */
6848 215 : if (nValidCount)
6849 206 : dfMean = static_cast<double>(nSum) / nValidCount;
6850 :
6851 : // To avoid potential precision issues when doing the difference,
6852 : // we need to do that computation on 128 bit rather than casting
6853 : // to double
6854 : const GDALUInt128 nTmpForStdDev(
6855 215 : GDALUInt128::Mul(nSumSquare, nValidCount) -
6856 430 : GDALUInt128::Mul(nSum, nSum));
6857 : const double dfStdDev =
6858 215 : nValidCount > 0
6859 215 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6860 215 : : 0.0;
6861 :
6862 215 : if (nValidCount > 0)
6863 : {
6864 206 : if (bApproxOK)
6865 : {
6866 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6867 : }
6868 182 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6869 : {
6870 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6871 : }
6872 206 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
6873 : }
6874 :
6875 215 : SetValidPercent(nSampleCount, nValidCount);
6876 :
6877 : /* --------------------------------------------------------------------
6878 : */
6879 : /* Record results. */
6880 : /* --------------------------------------------------------------------
6881 : */
6882 215 : if (pdfMin != nullptr)
6883 212 : *pdfMin = nValidCount ? nMin : 0;
6884 215 : if (pdfMax != nullptr)
6885 212 : *pdfMax = nValidCount ? nMax : 0;
6886 :
6887 215 : if (pdfMean != nullptr)
6888 208 : *pdfMean = dfMean;
6889 :
6890 215 : if (pdfStdDev != nullptr)
6891 208 : *pdfStdDev = dfStdDev;
6892 :
6893 215 : if (nValidCount > 0)
6894 206 : return CE_None;
6895 :
6896 9 : ReportError(CE_Failure, CPLE_AppDefined,
6897 : "Failed to compute statistics, no valid pixels found "
6898 : "in sampling.");
6899 9 : return CE_Failure;
6900 : }
6901 :
6902 255 : GByte *pabyMaskData = nullptr;
6903 255 : if (poMaskBand)
6904 : {
6905 : pabyMaskData = static_cast<GByte *>(
6906 44 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6907 44 : if (!pabyMaskData)
6908 : {
6909 0 : return CE_Failure;
6910 : }
6911 : }
6912 :
6913 255 : for (GIntBig iSampleBlock = 0;
6914 5870 : iSampleBlock <
6915 5870 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6916 5615 : iSampleBlock += nSampleRate)
6917 : {
6918 5615 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6919 5615 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6920 :
6921 5615 : int nXCheck = 0, nYCheck = 0;
6922 5615 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6923 :
6924 6180 : if (poMaskBand &&
6925 565 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6926 565 : iYBlock * nBlockYSize, nXCheck, nYCheck,
6927 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6928 565 : 0, nBlockXSize, nullptr) != CE_None)
6929 : {
6930 0 : CPLFree(pabyMaskData);
6931 0 : return CE_Failure;
6932 : }
6933 :
6934 : GDALRasterBlock *const poBlock =
6935 5615 : GetLockedBlockRef(iXBlock, iYBlock);
6936 5615 : if (poBlock == nullptr)
6937 : {
6938 0 : CPLFree(pabyMaskData);
6939 0 : return CE_Failure;
6940 : }
6941 :
6942 5615 : void *const pData = poBlock->GetDataRef();
6943 :
6944 : // This isn't the fastest way to do this, but is easier for now.
6945 13454 : for (int iY = 0; iY < nYCheck; iY++)
6946 : {
6947 4890780 : for (int iX = 0; iX < nXCheck; iX++)
6948 : {
6949 4882940 : const GPtrDiff_t iOffset =
6950 4882940 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6951 4882940 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6952 111829 : continue;
6953 :
6954 4778680 : bool bValid = true;
6955 : double dfValue =
6956 4778680 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6957 4778680 : sNoDataValues, bValid);
6958 :
6959 4778680 : if (!bValid)
6960 7574 : continue;
6961 :
6962 4771110 : dfMin = std::min(dfMin, dfValue);
6963 4771110 : dfMax = std::max(dfMax, dfValue);
6964 :
6965 4771110 : nValidCount++;
6966 4771110 : if (dfMin == dfMax)
6967 : {
6968 2173320 : if (nValidCount == 1)
6969 254 : dfMean = dfMin;
6970 : }
6971 : else
6972 : {
6973 2597780 : const double dfDelta = dfValue - dfMean;
6974 2597780 : dfMean += dfDelta / nValidCount;
6975 2597780 : dfM2 += dfDelta * (dfValue - dfMean);
6976 : }
6977 : }
6978 : }
6979 :
6980 5615 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6981 :
6982 5615 : poBlock->DropLock();
6983 :
6984 5615 : if (!pfnProgress(
6985 5615 : static_cast<double>(iSampleBlock) /
6986 5615 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6987 : "Compute Statistics", pProgressData))
6988 : {
6989 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6990 0 : CPLFree(pabyMaskData);
6991 0 : return CE_Failure;
6992 : }
6993 : }
6994 :
6995 255 : CPLFree(pabyMaskData);
6996 : }
6997 :
6998 255 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6999 : {
7000 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7001 0 : return CE_Failure;
7002 : }
7003 :
7004 : /* -------------------------------------------------------------------- */
7005 : /* Save computed information. */
7006 : /* -------------------------------------------------------------------- */
7007 255 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
7008 :
7009 255 : if (nValidCount > 0)
7010 : {
7011 254 : if (bApproxOK)
7012 : {
7013 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7014 : }
7015 246 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7016 : {
7017 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7018 : }
7019 254 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7020 : }
7021 : else
7022 : {
7023 1 : dfMin = 0.0;
7024 1 : dfMax = 0.0;
7025 : }
7026 :
7027 255 : SetValidPercent(nSampleCount, nValidCount);
7028 :
7029 : /* -------------------------------------------------------------------- */
7030 : /* Record results. */
7031 : /* -------------------------------------------------------------------- */
7032 255 : if (pdfMin != nullptr)
7033 252 : *pdfMin = dfMin;
7034 255 : if (pdfMax != nullptr)
7035 252 : *pdfMax = dfMax;
7036 :
7037 255 : if (pdfMean != nullptr)
7038 249 : *pdfMean = dfMean;
7039 :
7040 255 : if (pdfStdDev != nullptr)
7041 249 : *pdfStdDev = dfStdDev;
7042 :
7043 255 : if (nValidCount > 0)
7044 254 : return CE_None;
7045 :
7046 1 : ReportError(
7047 : CE_Failure, CPLE_AppDefined,
7048 : "Failed to compute statistics, no valid pixels found in sampling.");
7049 1 : return CE_Failure;
7050 : }
7051 :
7052 : /************************************************************************/
7053 : /* GDALComputeRasterStatistics() */
7054 : /************************************************************************/
7055 :
7056 : /**
7057 : * \brief Compute image statistics.
7058 : *
7059 : * @see GDALRasterBand::ComputeStatistics()
7060 : */
7061 :
7062 156 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7063 : int bApproxOK, double *pdfMin,
7064 : double *pdfMax, double *pdfMean,
7065 : double *pdfStdDev,
7066 : GDALProgressFunc pfnProgress,
7067 : void *pProgressData)
7068 :
7069 : {
7070 156 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7071 :
7072 156 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7073 :
7074 156 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7075 156 : pdfStdDev, pfnProgress, pProgressData);
7076 : }
7077 :
7078 : /************************************************************************/
7079 : /* SetStatistics() */
7080 : /************************************************************************/
7081 :
7082 : /**
7083 : * \brief Set statistics on band.
7084 : *
7085 : * This method can be used to store min/max/mean/standard deviation
7086 : * statistics on a raster band.
7087 : *
7088 : * The default implementation stores them as metadata, and will only work
7089 : * on formats that can save arbitrary metadata. This method cannot detect
7090 : * whether metadata will be properly saved and so may return CE_None even
7091 : * if the statistics will never be saved.
7092 : *
7093 : * This method is the same as the C function GDALSetRasterStatistics().
7094 : *
7095 : * @param dfMin minimum pixel value.
7096 : *
7097 : * @param dfMax maximum pixel value.
7098 : *
7099 : * @param dfMean mean (average) of all pixel values.
7100 : *
7101 : * @param dfStdDev Standard deviation of all pixel values.
7102 : *
7103 : * @return CE_None on success or CE_Failure on failure.
7104 : */
7105 :
7106 493 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7107 : double dfStdDev)
7108 :
7109 : {
7110 493 : char szValue[128] = {0};
7111 :
7112 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7113 493 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
7114 :
7115 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7116 493 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7117 :
7118 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7119 493 : SetMetadataItem("STATISTICS_MEAN", szValue);
7120 :
7121 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7122 493 : SetMetadataItem("STATISTICS_STDDEV", szValue);
7123 :
7124 493 : return CE_None;
7125 : }
7126 :
7127 : /************************************************************************/
7128 : /* GDALSetRasterStatistics() */
7129 : /************************************************************************/
7130 :
7131 : /**
7132 : * \brief Set statistics on band.
7133 : *
7134 : * @see GDALRasterBand::SetStatistics()
7135 : */
7136 :
7137 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7138 : double dfMax, double dfMean,
7139 : double dfStdDev)
7140 :
7141 : {
7142 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7143 :
7144 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7145 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7146 : }
7147 :
7148 : /************************************************************************/
7149 : /* ComputeRasterMinMax() */
7150 : /************************************************************************/
7151 :
7152 : template <class T, bool HAS_NODATA>
7153 120995 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7154 : T *pMax)
7155 : {
7156 120995 : T min0 = *pMin;
7157 120995 : T max0 = *pMax;
7158 120995 : T min1 = *pMin;
7159 120995 : T max1 = *pMax;
7160 : size_t i;
7161 215473 : for (i = 0; i + 1 < nElts; i += 2)
7162 : {
7163 81892 : if (!HAS_NODATA || buffer[i] != nodataValue)
7164 : {
7165 94478 : min0 = std::min(min0, buffer[i]);
7166 94478 : max0 = std::max(max0, buffer[i]);
7167 : }
7168 81892 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7169 : {
7170 94478 : min1 = std::min(min1, buffer[i + 1]);
7171 94478 : max1 = std::max(max1, buffer[i + 1]);
7172 : }
7173 : }
7174 120995 : T min = std::min(min0, min1);
7175 120995 : T max = std::max(max0, max1);
7176 120995 : if (i < nElts)
7177 : {
7178 119260 : if (!HAS_NODATA || buffer[i] != nodataValue)
7179 : {
7180 119280 : min = std::min(min, buffer[i]);
7181 119280 : max = std::max(max, buffer[i]);
7182 : }
7183 : }
7184 120995 : *pMin = min;
7185 120995 : *pMax = max;
7186 120995 : }
7187 :
7188 : template <GDALDataType eDataType, bool bSignedByte>
7189 : static void
7190 12301 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7191 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7192 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
7193 : {
7194 12301 : double dfLocalMin = dfMin;
7195 12301 : double dfLocalMax = dfMax;
7196 :
7197 44951 : for (int iY = 0; iY < nYCheck; iY++)
7198 : {
7199 19143299 : for (int iX = 0; iX < nXCheck; iX++)
7200 : {
7201 19110603 : const GPtrDiff_t iOffset =
7202 19110603 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7203 19110603 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7204 3448532 : continue;
7205 19027640 : bool bValid = true;
7206 19027640 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7207 : iOffset, sNoDataValues, bValid);
7208 19027640 : if (!bValid)
7209 3365580 : continue;
7210 :
7211 15662033 : dfLocalMin = std::min(dfLocalMin, dfValue);
7212 15662033 : dfLocalMax = std::max(dfLocalMax, dfValue);
7213 : }
7214 : }
7215 :
7216 12301 : dfMin = dfLocalMin;
7217 12301 : dfMax = dfLocalMax;
7218 12301 : }
7219 :
7220 12301 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
7221 : bool bSignedByte, int nXCheck, int nYCheck,
7222 : int nBlockXSize,
7223 : const GDALNoDataValues &sNoDataValues,
7224 : const GByte *pabyMaskData, double &dfMin,
7225 : double &dfMax)
7226 : {
7227 12301 : switch (eDataType)
7228 : {
7229 0 : case GDT_Unknown:
7230 0 : CPLAssert(false);
7231 : break;
7232 659 : case GDT_Byte:
7233 659 : if (bSignedByte)
7234 : {
7235 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
7236 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7237 : pabyMaskData, dfMin, dfMax);
7238 : }
7239 : else
7240 : {
7241 656 : ComputeMinMaxGeneric<GDT_Byte, false>(
7242 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7243 : pabyMaskData, dfMin, dfMax);
7244 : }
7245 659 : break;
7246 106 : case GDT_Int8:
7247 106 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
7248 : nBlockXSize, sNoDataValues,
7249 : pabyMaskData, dfMin, dfMax);
7250 106 : break;
7251 968 : case GDT_UInt16:
7252 968 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
7253 : nBlockXSize, sNoDataValues,
7254 : pabyMaskData, dfMin, dfMax);
7255 968 : break;
7256 1 : case GDT_Int16:
7257 1 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
7258 : nBlockXSize, sNoDataValues,
7259 : pabyMaskData, dfMin, dfMax);
7260 1 : break;
7261 201 : case GDT_UInt32:
7262 201 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
7263 : nBlockXSize, sNoDataValues,
7264 : pabyMaskData, dfMin, dfMax);
7265 201 : break;
7266 1089 : case GDT_Int32:
7267 1089 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
7268 : nBlockXSize, sNoDataValues,
7269 : pabyMaskData, dfMin, dfMax);
7270 1089 : break;
7271 17 : case GDT_UInt64:
7272 17 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
7273 : nBlockXSize, sNoDataValues,
7274 : pabyMaskData, dfMin, dfMax);
7275 17 : break;
7276 29 : case GDT_Int64:
7277 29 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
7278 : nBlockXSize, sNoDataValues,
7279 : pabyMaskData, dfMin, dfMax);
7280 29 : break;
7281 0 : case GDT_Float16:
7282 0 : ComputeMinMaxGeneric<GDT_Float16, false>(
7283 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7284 : pabyMaskData, dfMin, dfMax);
7285 0 : break;
7286 5634 : case GDT_Float32:
7287 5634 : ComputeMinMaxGeneric<GDT_Float32, false>(
7288 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7289 : pabyMaskData, dfMin, dfMax);
7290 5634 : break;
7291 3487 : case GDT_Float64:
7292 3487 : ComputeMinMaxGeneric<GDT_Float64, false>(
7293 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7294 : pabyMaskData, dfMin, dfMax);
7295 3487 : break;
7296 9 : case GDT_CInt16:
7297 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
7298 : nBlockXSize, sNoDataValues,
7299 : pabyMaskData, dfMin, dfMax);
7300 9 : break;
7301 9 : case GDT_CInt32:
7302 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
7303 : nBlockXSize, sNoDataValues,
7304 : pabyMaskData, dfMin, dfMax);
7305 9 : break;
7306 0 : case GDT_CFloat16:
7307 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
7308 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7309 : pabyMaskData, dfMin, dfMax);
7310 0 : break;
7311 75 : case GDT_CFloat32:
7312 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
7313 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7314 : pabyMaskData, dfMin, dfMax);
7315 75 : break;
7316 17 : case GDT_CFloat64:
7317 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
7318 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7319 : pabyMaskData, dfMin, dfMax);
7320 17 : break;
7321 0 : case GDT_TypeCount:
7322 0 : CPLAssert(false);
7323 : break;
7324 : }
7325 12301 : }
7326 :
7327 783 : static bool ComputeMinMaxGenericIterBlocks(
7328 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
7329 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
7330 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
7331 : double &dfMin, double &dfMax)
7332 :
7333 : {
7334 783 : GByte *pabyMaskData = nullptr;
7335 : int nBlockXSize, nBlockYSize;
7336 783 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7337 :
7338 783 : if (poMaskBand)
7339 : {
7340 : pabyMaskData =
7341 112 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7342 112 : if (!pabyMaskData)
7343 : {
7344 0 : return false;
7345 : }
7346 : }
7347 :
7348 13084 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7349 12301 : iSampleBlock += nSampleRate)
7350 : {
7351 12301 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7352 12301 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7353 :
7354 12301 : int nXCheck = 0, nYCheck = 0;
7355 12301 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7356 :
7357 18868 : if (poMaskBand &&
7358 6567 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7359 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7360 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7361 : nBlockXSize, nullptr) != CE_None)
7362 : {
7363 0 : CPLFree(pabyMaskData);
7364 0 : return false;
7365 : }
7366 :
7367 12301 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7368 12301 : if (poBlock == nullptr)
7369 : {
7370 0 : CPLFree(pabyMaskData);
7371 0 : return false;
7372 : }
7373 :
7374 12301 : void *const pData = poBlock->GetDataRef();
7375 :
7376 12301 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7377 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
7378 : dfMax);
7379 :
7380 12301 : poBlock->DropLock();
7381 : }
7382 :
7383 783 : CPLFree(pabyMaskData);
7384 783 : return true;
7385 : }
7386 :
7387 : /**
7388 : * \brief Compute the min/max values for a band.
7389 : *
7390 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7391 : * be trusted. If it doesn't work, a subsample of blocks will be read to
7392 : * get an approximate min/max. If the band has a nodata value it will
7393 : * be excluded from the minimum and maximum.
7394 : *
7395 : * If bApprox is FALSE, then all pixels will be read and used to compute
7396 : * an exact range.
7397 : *
7398 : * This method is the same as the C function GDALComputeRasterMinMax().
7399 : *
7400 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7401 : * FALSE.
7402 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7403 : * maximum (adfMinMax[1]) are returned.
7404 : *
7405 : * @return CE_None on success or CE_Failure on failure.
7406 : */
7407 :
7408 1767 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7409 : {
7410 : /* -------------------------------------------------------------------- */
7411 : /* Does the driver already know the min/max? */
7412 : /* -------------------------------------------------------------------- */
7413 1767 : if (bApproxOK)
7414 : {
7415 23 : int bSuccessMin = FALSE;
7416 23 : int bSuccessMax = FALSE;
7417 :
7418 23 : double dfMin = GetMinimum(&bSuccessMin);
7419 23 : double dfMax = GetMaximum(&bSuccessMax);
7420 :
7421 23 : if (bSuccessMin && bSuccessMax)
7422 : {
7423 1 : adfMinMax[0] = dfMin;
7424 1 : adfMinMax[1] = dfMax;
7425 1 : return CE_None;
7426 : }
7427 : }
7428 :
7429 : /* -------------------------------------------------------------------- */
7430 : /* If we have overview bands, use them for min/max. */
7431 : /* -------------------------------------------------------------------- */
7432 : // cppcheck-suppress knownConditionTrueFalse
7433 1766 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7434 : {
7435 : GDALRasterBand *poBand =
7436 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7437 :
7438 0 : if (poBand != this)
7439 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7440 : }
7441 :
7442 : /* -------------------------------------------------------------------- */
7443 : /* Read actual data and compute minimum and maximum. */
7444 : /* -------------------------------------------------------------------- */
7445 1766 : GDALNoDataValues sNoDataValues(this, eDataType);
7446 1766 : GDALRasterBand *poMaskBand = nullptr;
7447 1766 : if (!sNoDataValues.bGotNoDataValue)
7448 : {
7449 1513 : const int l_nMaskFlags = GetMaskFlags();
7450 1625 : if (l_nMaskFlags != GMF_ALL_VALID &&
7451 112 : GetColorInterpretation() != GCI_AlphaBand)
7452 : {
7453 112 : poMaskBand = GetMaskBand();
7454 : }
7455 : }
7456 :
7457 1766 : bool bSignedByte = false;
7458 1766 : if (eDataType == GDT_Byte)
7459 : {
7460 768 : EnablePixelTypeSignedByteWarning(false);
7461 : const char *pszPixelType =
7462 768 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7463 768 : EnablePixelTypeSignedByteWarning(true);
7464 768 : bSignedByte =
7465 768 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7466 : }
7467 :
7468 : GDALRasterIOExtraArg sExtraArg;
7469 1766 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7470 :
7471 3532 : GUInt32 nMin = (eDataType == GDT_Byte)
7472 1766 : ? 255
7473 : : 65535; // used for GByte & GUInt16 cases
7474 1766 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
7475 1766 : GInt16 nMinInt16 =
7476 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
7477 1766 : GInt16 nMaxInt16 =
7478 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
7479 1766 : double dfMin =
7480 : std::numeric_limits<double>::infinity(); // used for generic code path
7481 1766 : double dfMax =
7482 : -std::numeric_limits<double>::infinity(); // used for generic code path
7483 1766 : const bool bUseOptimizedPath =
7484 2682 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7485 916 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7486 :
7487 : const auto ComputeMinMaxForBlock =
7488 20935 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
7489 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
7490 243429 : int nYCheck)
7491 : {
7492 20935 : if (eDataType == GDT_Byte && !bSignedByte)
7493 : {
7494 : const bool bHasNoData =
7495 11561 : sNoDataValues.bGotNoDataValue &&
7496 29655 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
7497 11561 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
7498 11561 : sNoDataValues.dfNoDataValue;
7499 18094 : const GUInt32 nNoDataValue =
7500 18094 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
7501 : : 0;
7502 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7503 : ComputeStatisticsInternal<GByte,
7504 : /* COMPUTE_OTHER_STATS = */ false>::
7505 18094 : f(nXCheck, nBufferWidth, nYCheck,
7506 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7507 18094 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7508 : }
7509 2841 : else if (eDataType == GDT_UInt16)
7510 : {
7511 : const bool bHasNoData =
7512 83 : sNoDataValues.bGotNoDataValue &&
7513 1495 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
7514 83 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
7515 83 : sNoDataValues.dfNoDataValue;
7516 1412 : const GUInt32 nNoDataValue =
7517 1412 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
7518 : : 0;
7519 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7520 : ComputeStatisticsInternal<GUInt16,
7521 : /* COMPUTE_OTHER_STATS = */ false>::
7522 1412 : f(nXCheck, nBufferWidth, nYCheck,
7523 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7524 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7525 : }
7526 1429 : else if (eDataType == GDT_Int16)
7527 : {
7528 : const bool bHasNoData =
7529 1254 : sNoDataValues.bGotNoDataValue &&
7530 2683 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
7531 1254 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
7532 1254 : sNoDataValues.dfNoDataValue;
7533 1429 : if (bHasNoData)
7534 : {
7535 1254 : const int16_t nNoDataValue =
7536 1254 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
7537 120957 : for (int iY = 0; iY < nYCheck; iY++)
7538 : {
7539 119703 : ComputeMinMax<int16_t, true>(
7540 119703 : static_cast<const int16_t *>(pData) +
7541 119703 : static_cast<size_t>(iY) * nBufferWidth,
7542 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7543 : }
7544 : }
7545 : else
7546 : {
7547 1467 : for (int iY = 0; iY < nYCheck; iY++)
7548 : {
7549 1292 : ComputeMinMax<int16_t, false>(
7550 1292 : static_cast<const int16_t *>(pData) +
7551 1292 : static_cast<size_t>(iY) * nBufferWidth,
7552 : nXCheck, 0, &nMinInt16, &nMaxInt16);
7553 : }
7554 : }
7555 : }
7556 20935 : };
7557 :
7558 1766 : if (bApproxOK && HasArbitraryOverviews())
7559 : {
7560 : /* --------------------------------------------------------------------
7561 : */
7562 : /* Figure out how much the image should be reduced to get an */
7563 : /* approximate value. */
7564 : /* --------------------------------------------------------------------
7565 : */
7566 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7567 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7568 :
7569 0 : int nXReduced = nRasterXSize;
7570 0 : int nYReduced = nRasterYSize;
7571 0 : if (dfReduction > 1.0)
7572 : {
7573 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7574 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7575 :
7576 : // Catch the case of huge resizing ratios here
7577 0 : if (nXReduced == 0)
7578 0 : nXReduced = 1;
7579 0 : if (nYReduced == 0)
7580 0 : nYReduced = 1;
7581 : }
7582 :
7583 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
7584 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7585 :
7586 : const CPLErr eErr =
7587 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7588 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7589 0 : if (eErr != CE_None)
7590 : {
7591 0 : CPLFree(pData);
7592 0 : return eErr;
7593 : }
7594 :
7595 0 : GByte *pabyMaskData = nullptr;
7596 0 : if (poMaskBand)
7597 : {
7598 : pabyMaskData =
7599 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7600 0 : if (!pabyMaskData)
7601 : {
7602 0 : CPLFree(pData);
7603 0 : return CE_Failure;
7604 : }
7605 :
7606 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7607 : pabyMaskData, nXReduced, nYReduced,
7608 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
7609 : {
7610 0 : CPLFree(pData);
7611 0 : CPLFree(pabyMaskData);
7612 0 : return CE_Failure;
7613 : }
7614 : }
7615 :
7616 0 : if (bUseOptimizedPath)
7617 : {
7618 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7619 : }
7620 : else
7621 : {
7622 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
7623 : nYReduced, nXReduced, sNoDataValues,
7624 : pabyMaskData, dfMin, dfMax);
7625 : }
7626 :
7627 0 : CPLFree(pData);
7628 0 : CPLFree(pabyMaskData);
7629 : }
7630 :
7631 : else // No arbitrary overviews
7632 : {
7633 1766 : if (!InitBlockInfo())
7634 0 : return CE_Failure;
7635 :
7636 : /* --------------------------------------------------------------------
7637 : */
7638 : /* Figure out the ratio of blocks we will read to get an */
7639 : /* approximate value. */
7640 : /* --------------------------------------------------------------------
7641 : */
7642 1766 : int nSampleRate = 1;
7643 :
7644 1766 : if (bApproxOK)
7645 : {
7646 22 : nSampleRate = static_cast<int>(std::max(
7647 44 : 1.0,
7648 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7649 : // We want to avoid probing only the first column of blocks for
7650 : // a square shaped raster, because it is not unlikely that it may
7651 : // be padding only (#6378).
7652 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7653 0 : nSampleRate += 1;
7654 : }
7655 :
7656 1766 : if (bUseOptimizedPath)
7657 : {
7658 983 : for (GIntBig iSampleBlock = 0;
7659 21844 : iSampleBlock <
7660 21844 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7661 20861 : iSampleBlock += nSampleRate)
7662 : {
7663 20936 : const int iYBlock =
7664 20936 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7665 20936 : const int iXBlock =
7666 20936 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7667 :
7668 20936 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7669 20936 : if (poBlock == nullptr)
7670 1 : return CE_Failure;
7671 :
7672 20935 : void *const pData = poBlock->GetDataRef();
7673 :
7674 20935 : int nXCheck = 0, nYCheck = 0;
7675 20935 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7676 :
7677 20935 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7678 :
7679 20935 : poBlock->DropLock();
7680 :
7681 20935 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7682 4104 : nMax == 255)
7683 74 : break;
7684 : }
7685 : }
7686 : else
7687 : {
7688 783 : const GIntBig nTotalBlocks =
7689 783 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7690 783 : if (!ComputeMinMaxGenericIterBlocks(
7691 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7692 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
7693 : {
7694 0 : return CE_Failure;
7695 : }
7696 : }
7697 : }
7698 :
7699 1765 : if (bUseOptimizedPath)
7700 : {
7701 982 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7702 : {
7703 877 : dfMin = nMin;
7704 877 : dfMax = nMax;
7705 : }
7706 105 : else if (eDataType == GDT_Int16)
7707 : {
7708 105 : dfMin = nMinInt16;
7709 105 : dfMax = nMaxInt16;
7710 : }
7711 : }
7712 :
7713 1765 : if (dfMin > dfMax)
7714 : {
7715 9 : adfMinMax[0] = 0;
7716 9 : adfMinMax[1] = 0;
7717 9 : ReportError(
7718 : CE_Failure, CPLE_AppDefined,
7719 : "Failed to compute min/max, no valid pixels found in sampling.");
7720 9 : return CE_Failure;
7721 : }
7722 :
7723 1756 : adfMinMax[0] = dfMin;
7724 1756 : adfMinMax[1] = dfMax;
7725 :
7726 1756 : return CE_None;
7727 : }
7728 :
7729 : /************************************************************************/
7730 : /* GDALComputeRasterMinMax() */
7731 : /************************************************************************/
7732 :
7733 : /**
7734 : * \brief Compute the min/max values for a band.
7735 : *
7736 : * @see GDALRasterBand::ComputeRasterMinMax()
7737 : *
7738 : * @note Prior to GDAL 3.6, this function returned void
7739 : */
7740 :
7741 1616 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7742 : double adfMinMax[2])
7743 :
7744 : {
7745 1616 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7746 :
7747 1616 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7748 1616 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7749 : }
7750 :
7751 : /************************************************************************/
7752 : /* ComputeRasterMinMaxLocation() */
7753 : /************************************************************************/
7754 :
7755 : /**
7756 : * \brief Compute the min/max values for a band, and their location.
7757 : *
7758 : * Pixels whose value matches the nodata value or are masked by the mask
7759 : * band are ignored.
7760 : *
7761 : * If the minimum or maximum value is hit in several locations, it is not
7762 : * specified which one will be returned.
7763 : *
7764 : * @param[out] pdfMin Pointer to the minimum value.
7765 : * @param[out] pdfMax Pointer to the maximum value.
7766 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7767 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7768 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7769 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7770 : *
7771 : * @return CE_None in case of success, CE_Warning if there are no valid values,
7772 : * CE_Failure in case of error.
7773 : *
7774 : * @since GDAL 3.11
7775 : */
7776 :
7777 8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7778 : double *pdfMax, int *pnMinX,
7779 : int *pnMinY, int *pnMaxX,
7780 : int *pnMaxY)
7781 : {
7782 8 : int nMinX = -1;
7783 8 : int nMinY = -1;
7784 8 : int nMaxX = -1;
7785 8 : int nMaxY = -1;
7786 8 : double dfMin = std::numeric_limits<double>::infinity();
7787 8 : double dfMax = -std::numeric_limits<double>::infinity();
7788 8 : if (pdfMin)
7789 5 : *pdfMin = dfMin;
7790 8 : if (pdfMax)
7791 5 : *pdfMax = dfMax;
7792 8 : if (pnMinX)
7793 6 : *pnMinX = nMinX;
7794 8 : if (pnMinY)
7795 6 : *pnMinY = nMinY;
7796 8 : if (pnMaxX)
7797 6 : *pnMaxX = nMaxX;
7798 8 : if (pnMaxY)
7799 6 : *pnMaxY = nMaxY;
7800 :
7801 8 : if (GDALDataTypeIsComplex(eDataType))
7802 : {
7803 0 : CPLError(CE_Failure, CPLE_NotSupported,
7804 : "Complex data type not supported");
7805 0 : return CE_Failure;
7806 : }
7807 :
7808 8 : if (!InitBlockInfo())
7809 0 : return CE_Failure;
7810 :
7811 8 : GDALNoDataValues sNoDataValues(this, eDataType);
7812 8 : GDALRasterBand *poMaskBand = nullptr;
7813 8 : if (!sNoDataValues.bGotNoDataValue)
7814 : {
7815 8 : const int l_nMaskFlags = GetMaskFlags();
7816 9 : if (l_nMaskFlags != GMF_ALL_VALID &&
7817 1 : GetColorInterpretation() != GCI_AlphaBand)
7818 : {
7819 1 : poMaskBand = GetMaskBand();
7820 : }
7821 : }
7822 :
7823 8 : bool bSignedByte = false;
7824 8 : if (eDataType == GDT_Byte)
7825 : {
7826 7 : EnablePixelTypeSignedByteWarning(false);
7827 : const char *pszPixelType =
7828 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7829 7 : EnablePixelTypeSignedByteWarning(true);
7830 7 : bSignedByte =
7831 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7832 : }
7833 :
7834 8 : GByte *pabyMaskData = nullptr;
7835 8 : if (poMaskBand)
7836 : {
7837 : pabyMaskData =
7838 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7839 1 : if (!pabyMaskData)
7840 : {
7841 0 : return CE_Failure;
7842 : }
7843 : }
7844 :
7845 8 : const GIntBig nTotalBlocks =
7846 8 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7847 8 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7848 8 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7849 16 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7850 : {
7851 11 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7852 11 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7853 :
7854 11 : int nXCheck = 0, nYCheck = 0;
7855 11 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7856 :
7857 13 : if (poMaskBand &&
7858 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7859 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7860 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7861 2 : nBlockXSize, nullptr) != CE_None)
7862 : {
7863 0 : CPLFree(pabyMaskData);
7864 0 : return CE_Failure;
7865 : }
7866 :
7867 11 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7868 11 : if (poBlock == nullptr)
7869 : {
7870 0 : CPLFree(pabyMaskData);
7871 0 : return CE_Failure;
7872 : }
7873 :
7874 11 : void *const pData = poBlock->GetDataRef();
7875 :
7876 11 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7877 : {
7878 4 : for (int iY = 0; iY < nYCheck; ++iY)
7879 : {
7880 6 : for (int iX = 0; iX < nXCheck; ++iX)
7881 : {
7882 4 : const GPtrDiff_t iOffset =
7883 4 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7884 4 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7885 2 : continue;
7886 2 : bool bValid = true;
7887 : double dfValue =
7888 2 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
7889 : sNoDataValues, bValid);
7890 2 : if (!bValid)
7891 0 : continue;
7892 2 : if (dfValue < dfMin)
7893 : {
7894 2 : dfMin = dfValue;
7895 2 : nMinX = iXBlock * nBlockXSize + iX;
7896 2 : nMinY = iYBlock * nBlockYSize + iY;
7897 : }
7898 2 : if (dfValue > dfMax)
7899 : {
7900 1 : dfMax = dfValue;
7901 1 : nMaxX = iXBlock * nBlockXSize + iX;
7902 1 : nMaxY = iYBlock * nBlockYSize + iY;
7903 : }
7904 : }
7905 2 : }
7906 : }
7907 : else
7908 : {
7909 9 : size_t pos_min = 0;
7910 9 : size_t pos_max = 0;
7911 9 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7912 9 : if (bNeedsMin && bNeedsMax)
7913 : {
7914 10 : std::tie(pos_min, pos_max) = gdal::minmax_element(
7915 5 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7916 5 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7917 10 : sNoDataValues.dfNoDataValue);
7918 : }
7919 4 : else if (bNeedsMin)
7920 : {
7921 1 : pos_min = gdal::min_element(
7922 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7923 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7924 : sNoDataValues.dfNoDataValue);
7925 : }
7926 3 : else if (bNeedsMax)
7927 : {
7928 2 : pos_max = gdal::max_element(
7929 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7930 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7931 : sNoDataValues.dfNoDataValue);
7932 : }
7933 :
7934 9 : if (bNeedsMin)
7935 : {
7936 6 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7937 6 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7938 6 : bool bValid = true;
7939 : const double dfMinValueBlock =
7940 6 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
7941 : sNoDataValues, bValid);
7942 6 : if (bValid && dfMinValueBlock < dfMin)
7943 : {
7944 5 : dfMin = dfMinValueBlock;
7945 5 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
7946 5 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
7947 : }
7948 : }
7949 :
7950 9 : if (bNeedsMax)
7951 : {
7952 7 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7953 7 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7954 7 : bool bValid = true;
7955 : const double dfMaxValueBlock =
7956 7 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
7957 : sNoDataValues, bValid);
7958 7 : if (bValid && dfMaxValueBlock > dfMax)
7959 : {
7960 5 : dfMax = dfMaxValueBlock;
7961 5 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7962 5 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7963 : }
7964 : }
7965 : }
7966 :
7967 11 : poBlock->DropLock();
7968 :
7969 11 : if (eDataType == GDT_Byte)
7970 : {
7971 10 : if (bNeedsMin && dfMin == 0)
7972 : {
7973 1 : bNeedsMin = false;
7974 : }
7975 10 : if (bNeedsMax && dfMax == 255)
7976 : {
7977 4 : bNeedsMax = false;
7978 : }
7979 10 : if (!bNeedsMin && !bNeedsMax)
7980 : {
7981 3 : break;
7982 : }
7983 : }
7984 : }
7985 :
7986 8 : CPLFree(pabyMaskData);
7987 :
7988 8 : if (pdfMin)
7989 5 : *pdfMin = dfMin;
7990 8 : if (pdfMax)
7991 5 : *pdfMax = dfMax;
7992 8 : if (pnMinX)
7993 6 : *pnMinX = nMinX;
7994 8 : if (pnMinY)
7995 6 : *pnMinY = nMinY;
7996 8 : if (pnMaxX)
7997 6 : *pnMaxX = nMaxX;
7998 8 : if (pnMaxY)
7999 6 : *pnMaxY = nMaxY;
8000 8 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
8001 8 : : CE_None;
8002 : }
8003 :
8004 : /************************************************************************/
8005 : /* GDALComputeRasterMinMaxLocation() */
8006 : /************************************************************************/
8007 :
8008 : /**
8009 : * \brief Compute the min/max values for a band, and their location.
8010 : *
8011 : * @see GDALRasterBand::ComputeRasterMinMax()
8012 : * @since GDAL 3.11
8013 : */
8014 :
8015 6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
8016 : double *pdfMax, int *pnMinX, int *pnMinY,
8017 : int *pnMaxX, int *pnMaxY)
8018 :
8019 : {
8020 6 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
8021 :
8022 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8023 6 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
8024 6 : pnMaxX, pnMaxY);
8025 : }
8026 :
8027 : /************************************************************************/
8028 : /* SetDefaultHistogram() */
8029 : /************************************************************************/
8030 :
8031 : /* FIXME : add proper documentation */
8032 : /**
8033 : * \brief Set default histogram.
8034 : *
8035 : * This method is the same as the C function GDALSetDefaultHistogram() and
8036 : * GDALSetDefaultHistogramEx()
8037 : */
8038 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
8039 : double /* dfMax */,
8040 : int /* nBuckets */,
8041 : GUIntBig * /* panHistogram */)
8042 :
8043 : {
8044 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8045 0 : ReportError(CE_Failure, CPLE_NotSupported,
8046 : "SetDefaultHistogram() not implemented for this format.");
8047 :
8048 0 : return CE_Failure;
8049 : }
8050 :
8051 : /************************************************************************/
8052 : /* GDALSetDefaultHistogram() */
8053 : /************************************************************************/
8054 :
8055 : /**
8056 : * \brief Set default histogram.
8057 : *
8058 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8059 : * 2 billion.
8060 : *
8061 : * @see GDALRasterBand::SetDefaultHistogram()
8062 : * @see GDALSetRasterHistogramEx()
8063 : */
8064 :
8065 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8066 : double dfMax, int nBuckets,
8067 : int *panHistogram)
8068 :
8069 : {
8070 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8071 :
8072 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8073 :
8074 : GUIntBig *panHistogramTemp =
8075 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8076 0 : if (panHistogramTemp == nullptr)
8077 : {
8078 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8079 : "Out of memory in GDALSetDefaultHistogram().");
8080 0 : return CE_Failure;
8081 : }
8082 :
8083 0 : for (int i = 0; i < nBuckets; ++i)
8084 : {
8085 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8086 : }
8087 :
8088 : const CPLErr eErr =
8089 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8090 :
8091 0 : CPLFree(panHistogramTemp);
8092 :
8093 0 : return eErr;
8094 : }
8095 :
8096 : /************************************************************************/
8097 : /* GDALSetDefaultHistogramEx() */
8098 : /************************************************************************/
8099 :
8100 : /**
8101 : * \brief Set default histogram.
8102 : *
8103 : * @see GDALRasterBand::SetDefaultHistogram()
8104 : *
8105 : * @since GDAL 2.0
8106 : */
8107 :
8108 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8109 : double dfMin, double dfMax,
8110 : int nBuckets,
8111 : GUIntBig *panHistogram)
8112 :
8113 : {
8114 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8115 :
8116 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8117 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8118 : }
8119 :
8120 : /************************************************************************/
8121 : /* GetDefaultRAT() */
8122 : /************************************************************************/
8123 :
8124 : /**
8125 : * \brief Fetch default Raster Attribute Table.
8126 : *
8127 : * A RAT will be returned if there is a default one associated with the
8128 : * band, otherwise NULL is returned. The returned RAT is owned by the
8129 : * band and should not be deleted by the application.
8130 : *
8131 : * This method is the same as the C function GDALGetDefaultRAT().
8132 : *
8133 : * @return NULL, or a pointer to an internal RAT owned by the band.
8134 : */
8135 :
8136 176 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8137 :
8138 : {
8139 176 : return nullptr;
8140 : }
8141 :
8142 : /************************************************************************/
8143 : /* GDALGetDefaultRAT() */
8144 : /************************************************************************/
8145 :
8146 : /**
8147 : * \brief Fetch default Raster Attribute Table.
8148 : *
8149 : * @see GDALRasterBand::GetDefaultRAT()
8150 : */
8151 :
8152 1113 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8153 :
8154 : {
8155 1113 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8156 :
8157 1113 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8158 1113 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8159 : }
8160 :
8161 : /************************************************************************/
8162 : /* SetDefaultRAT() */
8163 : /************************************************************************/
8164 :
8165 : /**
8166 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8167 : * \brief Set default Raster Attribute Table.
8168 : *
8169 : * Associates a default RAT with the band. If not implemented for the
8170 : * format a CPLE_NotSupported error will be issued. If successful a copy
8171 : * of the RAT is made, the original remains owned by the caller.
8172 : *
8173 : * This method is the same as the C function GDALSetDefaultRAT().
8174 : *
8175 : * @param poRAT the RAT to assign to the band.
8176 : *
8177 : * @return CE_None on success or CE_Failure if unsupported or otherwise
8178 : * failing.
8179 : */
8180 :
8181 : /**/
8182 : /**/
8183 :
8184 : CPLErr
8185 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8186 : {
8187 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8188 : {
8189 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
8190 0 : ReportError(CE_Failure, CPLE_NotSupported,
8191 : "SetDefaultRAT() not implemented for this format.");
8192 0 : CPLPopErrorHandler();
8193 : }
8194 0 : return CE_Failure;
8195 : }
8196 :
8197 : /************************************************************************/
8198 : /* GDALSetDefaultRAT() */
8199 : /************************************************************************/
8200 :
8201 : /**
8202 : * \brief Set default Raster Attribute Table.
8203 : *
8204 : * @see GDALRasterBand::GDALSetDefaultRAT()
8205 : */
8206 :
8207 18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
8208 : GDALRasterAttributeTableH hRAT)
8209 :
8210 : {
8211 18 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
8212 :
8213 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8214 :
8215 18 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
8216 : }
8217 :
8218 : /************************************************************************/
8219 : /* GetMaskBand() */
8220 : /************************************************************************/
8221 :
8222 : /**
8223 : * \brief Return the mask band associated with the band.
8224 : *
8225 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8226 : * that returns one of four default implementations :
8227 : * <ul>
8228 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8229 : * </li>
8230 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8231 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8232 : * GMF_NODATA | GMF_PER_DATASET.
8233 : * </li>
8234 : * <li>If the band has a nodata value set, an instance of the new
8235 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8236 : * GMF_NODATA.
8237 : * </li>
8238 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
8239 : * to apply to this band (specific rules yet to be determined) and that is of
8240 : * type GDT_Byte then that alpha band will be returned, and the flags
8241 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8242 : * </li>
8243 : * <li>If neither of the above apply, an instance of the new
8244 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8245 : * pixels. The null flags will return GMF_ALL_VALID.
8246 : * </li>
8247 : * </ul>
8248 : *
8249 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
8250 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
8251 : *
8252 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8253 : * dataset, with the same name as the main dataset and suffixed with .msk,
8254 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8255 : * main dataset.
8256 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8257 : * level, where xx matches the band number of a band of the main dataset. The
8258 : * value of those items is a combination of the flags GMF_ALL_VALID,
8259 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8260 : * a band, then the other rules explained above will be used to generate a
8261 : * on-the-fly mask band.
8262 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8263 : *
8264 : * This method is the same as the C function GDALGetMaskBand().
8265 : *
8266 : * @return a valid mask band.
8267 : *
8268 : * @since GDAL 1.5.0
8269 : *
8270 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8271 : *
8272 : */
8273 767057 : GDALRasterBand *GDALRasterBand::GetMaskBand()
8274 :
8275 : {
8276 392588 : const auto HasNoData = [this]()
8277 : {
8278 130570 : int bHaveNoDataRaw = FALSE;
8279 130570 : bool bHaveNoData = false;
8280 130570 : if (eDataType == GDT_Int64)
8281 : {
8282 203 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
8283 203 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8284 : }
8285 130367 : else if (eDataType == GDT_UInt64)
8286 : {
8287 151 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
8288 151 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8289 : }
8290 : else
8291 : {
8292 130216 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
8293 129954 : if (bHaveNoDataRaw &&
8294 129954 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
8295 : {
8296 1040 : bHaveNoData = true;
8297 : }
8298 : }
8299 130057 : return bHaveNoData;
8300 767057 : };
8301 :
8302 767057 : if (poMask != nullptr)
8303 : {
8304 646818 : if (poMask.IsOwned())
8305 : {
8306 297932 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
8307 : {
8308 33043 : if (HasNoData())
8309 : {
8310 9 : InvalidateMaskBand();
8311 : }
8312 : }
8313 275138 : else if (auto poNoDataMaskBand =
8314 271040 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
8315 : {
8316 392 : int bHaveNoDataRaw = FALSE;
8317 392 : bool bIsSame = false;
8318 392 : if (eDataType == GDT_Int64)
8319 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
8320 27 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
8321 10 : bHaveNoDataRaw;
8322 375 : else if (eDataType == GDT_UInt64)
8323 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8324 27 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8325 10 : bHaveNoDataRaw;
8326 : else
8327 : {
8328 : const double dfNoDataValue =
8329 358 : GetNoDataValue(&bHaveNoDataRaw);
8330 358 : if (bHaveNoDataRaw)
8331 : {
8332 355 : bIsSame =
8333 355 : std::isnan(dfNoDataValue)
8334 355 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8335 320 : : poNoDataMaskBand->m_dfNoDataValue ==
8336 : dfNoDataValue;
8337 : }
8338 : }
8339 392 : if (!bIsSame)
8340 23 : InvalidateMaskBand();
8341 : }
8342 : }
8343 :
8344 685750 : if (poMask)
8345 684309 : return poMask.get();
8346 : }
8347 :
8348 : /* -------------------------------------------------------------------- */
8349 : /* Check for a mask in a .msk file. */
8350 : /* -------------------------------------------------------------------- */
8351 97695 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8352 : {
8353 47 : poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
8354 47 : if (poMask != nullptr)
8355 : {
8356 45 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8357 45 : return poMask.get();
8358 : }
8359 : }
8360 :
8361 : /* -------------------------------------------------------------------- */
8362 : /* Check for NODATA_VALUES metadata. */
8363 : /* -------------------------------------------------------------------- */
8364 97650 : if (poDS != nullptr)
8365 : {
8366 : const char *pszGDALNoDataValues =
8367 97634 : poDS->GetMetadataItem("NODATA_VALUES");
8368 97633 : if (pszGDALNoDataValues != nullptr)
8369 : {
8370 68 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
8371 : pszGDALNoDataValues, " ", FALSE, FALSE);
8372 :
8373 : // Make sure we have as many values as bands.
8374 136 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
8375 68 : poDS->GetRasterCount() != 0)
8376 : {
8377 : // Make sure that all bands have the same data type
8378 : // This is clearly not a fundamental condition, just a
8379 : // condition to make implementation easier.
8380 68 : GDALDataType eDT = GDT_Unknown;
8381 68 : int i = 0; // Used after for.
8382 270 : for (; i < poDS->GetRasterCount(); ++i)
8383 : {
8384 202 : if (i == 0)
8385 68 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8386 134 : else if (eDT !=
8387 134 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
8388 : {
8389 0 : break;
8390 : }
8391 : }
8392 68 : if (i == poDS->GetRasterCount())
8393 : {
8394 68 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8395 : try
8396 : {
8397 68 : poMask.reset(
8398 136 : std::make_unique<GDALNoDataValuesMaskBand>(poDS));
8399 : }
8400 0 : catch (const std::bad_alloc &)
8401 : {
8402 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8403 0 : poMask.reset();
8404 : }
8405 68 : CSLDestroy(papszGDALNoDataValues);
8406 68 : return poMask.get();
8407 : }
8408 : else
8409 : {
8410 0 : ReportError(CE_Warning, CPLE_AppDefined,
8411 : "All bands should have the same type in "
8412 : "order the NODATA_VALUES metadata item "
8413 : "to be used as a mask.");
8414 : }
8415 : }
8416 : else
8417 : {
8418 0 : ReportError(
8419 : CE_Warning, CPLE_AppDefined,
8420 : "NODATA_VALUES metadata item doesn't have the same number "
8421 : "of values as the number of bands. "
8422 : "Ignoring it for mask.");
8423 : }
8424 :
8425 0 : CSLDestroy(papszGDALNoDataValues);
8426 : }
8427 : }
8428 :
8429 : /* -------------------------------------------------------------------- */
8430 : /* Check for nodata case. */
8431 : /* -------------------------------------------------------------------- */
8432 97581 : if (HasNoData())
8433 : {
8434 1066 : nMaskFlags = GMF_NODATA;
8435 : try
8436 : {
8437 1066 : poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
8438 : }
8439 0 : catch (const std::bad_alloc &)
8440 : {
8441 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8442 0 : poMask.reset();
8443 : }
8444 1066 : return poMask.get();
8445 : }
8446 :
8447 : /* -------------------------------------------------------------------- */
8448 : /* Check for alpha case. */
8449 : /* -------------------------------------------------------------------- */
8450 96498 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8451 193601 : this == poDS->GetRasterBand(1) &&
8452 589 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8453 : {
8454 223 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8455 : {
8456 179 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8457 179 : poMask.resetNotOwned(poDS->GetRasterBand(2));
8458 179 : return poMask.get();
8459 : }
8460 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8461 : {
8462 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8463 : try
8464 : {
8465 23 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
8466 46 : poDS->GetRasterBand(2)));
8467 : }
8468 0 : catch (const std::bad_alloc &)
8469 : {
8470 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8471 0 : poMask.reset();
8472 : }
8473 23 : return poMask.get();
8474 : }
8475 : }
8476 :
8477 96297 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8478 3032 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8479 193334 : this == poDS->GetRasterBand(3)) &&
8480 2362 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8481 : {
8482 1479 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8483 : {
8484 1430 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8485 1430 : poMask.resetNotOwned(poDS->GetRasterBand(4));
8486 1431 : return poMask.get();
8487 : }
8488 51 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8489 : {
8490 38 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8491 : try
8492 : {
8493 38 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
8494 76 : poDS->GetRasterBand(4)));
8495 : }
8496 0 : catch (const std::bad_alloc &)
8497 : {
8498 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8499 0 : poMask.reset();
8500 : }
8501 38 : return poMask.get();
8502 : }
8503 : }
8504 :
8505 : /* -------------------------------------------------------------------- */
8506 : /* Fallback to all valid case. */
8507 : /* -------------------------------------------------------------------- */
8508 94843 : nMaskFlags = GMF_ALL_VALID;
8509 : try
8510 : {
8511 94843 : poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
8512 : }
8513 0 : catch (const std::bad_alloc &)
8514 : {
8515 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8516 0 : poMask.reset();
8517 : }
8518 :
8519 94842 : return poMask.get();
8520 : }
8521 :
8522 : /************************************************************************/
8523 : /* GDALGetMaskBand() */
8524 : /************************************************************************/
8525 :
8526 : /**
8527 : * \brief Return the mask band associated with the band.
8528 : *
8529 : * @see GDALRasterBand::GetMaskBand()
8530 : */
8531 :
8532 11043 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8533 :
8534 : {
8535 11043 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8536 :
8537 11043 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8538 11043 : return poBand->GetMaskBand();
8539 : }
8540 :
8541 : /************************************************************************/
8542 : /* GetMaskFlags() */
8543 : /************************************************************************/
8544 :
8545 : /**
8546 : * \brief Return the status flags of the mask band associated with the band.
8547 : *
8548 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8549 : * the following available definitions that may be extended in the future:
8550 : * <ul>
8551 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8552 : * 255. When used this will normally be the only flag set.
8553 : * </li>
8554 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8555 : * dataset.
8556 : * </li>
8557 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8558 : * and may have values other than 0 and 255.
8559 : * </li>
8560 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8561 : * nodata values. (mutually exclusive of GMF_ALPHA)
8562 : * </li>
8563 : * </ul>
8564 : *
8565 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8566 : * that returns one of four default implementations:
8567 : * <ul>
8568 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8569 : * </li>
8570 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8571 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8572 : * GMF_NODATA | GMF_PER_DATASET.
8573 : * </li>
8574 : * <li>If the band has a nodata value set, an instance of the new
8575 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8576 : * GMF_NODATA.
8577 : * </li>
8578 : * <li>If there is no nodata value, but the dataset has an alpha band that
8579 : * seems to apply to this band (specific rules yet to be determined) and that is
8580 : * of type GDT_Byte then that alpha band will be returned, and the flags
8581 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8582 : * </li>
8583 : * <li>If neither of the above apply, an instance of the new
8584 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8585 : * pixels. The null flags will return GMF_ALL_VALID.
8586 : * </li>
8587 : * </ul>
8588 : *
8589 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8590 : * dataset, with the same name as the main dataset and suffixed with .msk,
8591 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8592 : * main dataset.
8593 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8594 : * level, where xx matches the band number of a band of the main dataset. The
8595 : * value of those items is a combination of the flags GMF_ALL_VALID,
8596 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8597 : * a band, then the other rules explained above will be used to generate a
8598 : * on-the-fly mask band.
8599 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8600 : *
8601 : * This method is the same as the C function GDALGetMaskFlags().
8602 : *
8603 : * @since GDAL 1.5.0
8604 : *
8605 : * @return a valid mask band.
8606 : *
8607 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8608 : *
8609 : */
8610 154433 : int GDALRasterBand::GetMaskFlags()
8611 :
8612 : {
8613 : // If we don't have a band yet, force this now so that the masks value
8614 : // will be initialized.
8615 :
8616 154433 : if (poMask == nullptr)
8617 96160 : GetMaskBand();
8618 :
8619 154435 : return nMaskFlags;
8620 : }
8621 :
8622 : /************************************************************************/
8623 : /* GDALGetMaskFlags() */
8624 : /************************************************************************/
8625 :
8626 : /**
8627 : * \brief Return the status flags of the mask band associated with the band.
8628 : *
8629 : * @see GDALRasterBand::GetMaskFlags()
8630 : */
8631 :
8632 7076 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8633 :
8634 : {
8635 7076 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8636 :
8637 7076 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8638 7076 : return poBand->GetMaskFlags();
8639 : }
8640 :
8641 : /************************************************************************/
8642 : /* InvalidateMaskBand() */
8643 : /************************************************************************/
8644 :
8645 : //! @cond Doxygen_Suppress
8646 1917370 : void GDALRasterBand::InvalidateMaskBand()
8647 : {
8648 1917370 : poMask.reset();
8649 1917340 : nMaskFlags = 0;
8650 1917340 : }
8651 :
8652 : //! @endcond
8653 :
8654 : /************************************************************************/
8655 : /* CreateMaskBand() */
8656 : /************************************************************************/
8657 :
8658 : /**
8659 : * \brief Adds a mask band to the current band
8660 : *
8661 : * The default implementation of the CreateMaskBand() method is implemented
8662 : * based on similar rules to the .ovr handling implemented using the
8663 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8664 : * be created with the same basename as the original file, and it will have
8665 : * as many bands as the original image (or just one for GMF_PER_DATASET).
8666 : * The mask images will be deflate compressed tiled images with the same
8667 : * block size as the original image if possible.
8668 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8669 : * level, where xx matches the band number of a band of the main dataset. The
8670 : * value of those items will be the one of the nFlagsIn parameter.
8671 : *
8672 : * Note that if you got a mask band with a previous call to GetMaskBand(),
8673 : * it might be invalidated by CreateMaskBand(). So you have to call
8674 : * GetMaskBand() again.
8675 : *
8676 : * This method is the same as the C function GDALCreateMaskBand().
8677 : *
8678 : * @since GDAL 1.5.0
8679 : *
8680 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8681 : *
8682 : * @return CE_None on success or CE_Failure on an error.
8683 : *
8684 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8685 : * @see GDALDataset::CreateMaskBand()
8686 : *
8687 : */
8688 :
8689 10 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8690 :
8691 : {
8692 10 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8693 : {
8694 10 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8695 10 : if (eErr != CE_None)
8696 1 : return eErr;
8697 :
8698 9 : InvalidateMaskBand();
8699 :
8700 9 : return CE_None;
8701 : }
8702 :
8703 0 : ReportError(CE_Failure, CPLE_NotSupported,
8704 : "CreateMaskBand() not supported for this band.");
8705 :
8706 0 : return CE_Failure;
8707 : }
8708 :
8709 : /************************************************************************/
8710 : /* GDALCreateMaskBand() */
8711 : /************************************************************************/
8712 :
8713 : /**
8714 : * \brief Adds a mask band to the current band
8715 : *
8716 : * @see GDALRasterBand::CreateMaskBand()
8717 : */
8718 :
8719 33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8720 :
8721 : {
8722 33 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8723 :
8724 33 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8725 33 : return poBand->CreateMaskBand(nFlags);
8726 : }
8727 :
8728 : /************************************************************************/
8729 : /* IsMaskBand() */
8730 : /************************************************************************/
8731 :
8732 : /**
8733 : * \brief Returns whether a band is a mask band.
8734 : *
8735 : * Mask band must be understood in the broad term: it can be a per-dataset
8736 : * mask band, an alpha band, or an implicit mask band.
8737 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8738 : *
8739 : * This method is the same as the C function GDALIsMaskBand().
8740 : *
8741 : * @return true if the band is a mask band.
8742 : *
8743 : * @see GDALDataset::CreateMaskBand()
8744 : *
8745 : * @since GDAL 3.5.0
8746 : *
8747 : */
8748 :
8749 444 : bool GDALRasterBand::IsMaskBand() const
8750 : {
8751 : // The GeoTIFF driver, among others, override this method to
8752 : // also handle external .msk bands.
8753 444 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8754 444 : GCI_AlphaBand;
8755 : }
8756 :
8757 : /************************************************************************/
8758 : /* GDALIsMaskBand() */
8759 : /************************************************************************/
8760 :
8761 : /**
8762 : * \brief Returns whether a band is a mask band.
8763 : *
8764 : * Mask band must be understood in the broad term: it can be a per-dataset
8765 : * mask band, an alpha band, or an implicit mask band.
8766 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8767 : *
8768 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8769 : *
8770 : * @return true if the band is a mask band.
8771 : *
8772 : * @see GDALRasterBand::IsMaskBand()
8773 : *
8774 : * @since GDAL 3.5.0
8775 : *
8776 : */
8777 :
8778 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
8779 :
8780 : {
8781 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8782 :
8783 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8784 37 : return poBand->IsMaskBand();
8785 : }
8786 :
8787 : /************************************************************************/
8788 : /* GetMaskValueRange() */
8789 : /************************************************************************/
8790 :
8791 : /**
8792 : * \brief Returns the range of values that a mask band can take.
8793 : *
8794 : * @return the range of values that a mask band can take.
8795 : *
8796 : * @since GDAL 3.5.0
8797 : *
8798 : */
8799 :
8800 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8801 : {
8802 0 : return GMVR_UNKNOWN;
8803 : }
8804 :
8805 : /************************************************************************/
8806 : /* GetIndexColorTranslationTo() */
8807 : /************************************************************************/
8808 :
8809 : /**
8810 : * \brief Compute translation table for color tables.
8811 : *
8812 : * When the raster band has a palette index, it may be useful to compute
8813 : * the "translation" of this palette to the palette of another band.
8814 : * The translation tries to do exact matching first, and then approximate
8815 : * matching if no exact matching is possible.
8816 : * This method returns a table such that table[i] = j where i is an index
8817 : * of the 'this' rasterband and j the corresponding index for the reference
8818 : * rasterband.
8819 : *
8820 : * This method is thought as internal to GDAL and is used for drivers
8821 : * like RPFTOC.
8822 : *
8823 : * The implementation only supports 1-byte palette rasterbands.
8824 : *
8825 : * @param poReferenceBand the raster band
8826 : * @param pTranslationTable an already allocated translation table (at least 256
8827 : * bytes), or NULL to let the method allocate it
8828 : * @param pApproximateMatching a pointer to a flag that is set if the matching
8829 : * is approximate. May be NULL.
8830 : *
8831 : * @return a translation table if the two bands are palette index and that they
8832 : * do not match or NULL in other cases. The table must be freed with CPLFree if
8833 : * NULL was passed for pTranslationTable.
8834 : */
8835 :
8836 : unsigned char *
8837 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8838 : unsigned char *pTranslationTable,
8839 : int *pApproximateMatching)
8840 : {
8841 4 : if (poReferenceBand == nullptr)
8842 0 : return nullptr;
8843 :
8844 : // cppcheck-suppress knownConditionTrueFalse
8845 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8846 : // cppcheck-suppress knownConditionTrueFalse
8847 4 : GetColorInterpretation() == GCI_PaletteIndex &&
8848 12 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
8849 4 : GetRasterDataType() == GDT_Byte)
8850 : {
8851 4 : const GDALColorTable *srcColorTable = GetColorTable();
8852 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8853 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
8854 : {
8855 4 : const int nEntries = srcColorTable->GetColorEntryCount();
8856 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
8857 :
8858 4 : int bHasNoDataValueSrc = FALSE;
8859 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8860 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8861 4 : dfNoDataValueSrc <= 255 &&
8862 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8863 0 : bHasNoDataValueSrc = FALSE;
8864 4 : const int noDataValueSrc =
8865 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8866 :
8867 4 : int bHasNoDataValueRef = FALSE;
8868 : const double dfNoDataValueRef =
8869 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8870 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8871 3 : dfNoDataValueRef <= 255 &&
8872 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8873 1 : bHasNoDataValueRef = FALSE;
8874 4 : const int noDataValueRef =
8875 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8876 :
8877 4 : bool samePalette = false;
8878 :
8879 4 : if (pApproximateMatching)
8880 3 : *pApproximateMatching = FALSE;
8881 :
8882 4 : if (nEntries == nRefEntries &&
8883 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
8884 3 : (bHasNoDataValueSrc == FALSE ||
8885 : noDataValueSrc == noDataValueRef))
8886 : {
8887 3 : samePalette = true;
8888 654 : for (int i = 0; i < nEntries; ++i)
8889 : {
8890 651 : if (noDataValueSrc == i)
8891 3 : continue;
8892 : const GDALColorEntry *entry =
8893 648 : srcColorTable->GetColorEntry(i);
8894 : const GDALColorEntry *entryRef =
8895 648 : destColorTable->GetColorEntry(i);
8896 648 : if (entry->c1 != entryRef->c1 ||
8897 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8898 : {
8899 0 : samePalette = false;
8900 : }
8901 : }
8902 : }
8903 :
8904 4 : if (!samePalette)
8905 : {
8906 1 : if (pTranslationTable == nullptr)
8907 : {
8908 : pTranslationTable = static_cast<unsigned char *>(
8909 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8910 1 : if (pTranslationTable == nullptr)
8911 1 : return nullptr;
8912 : }
8913 :
8914 : // Trying to remap the product palette on the subdataset
8915 : // palette.
8916 5 : for (int i = 0; i < nEntries; ++i)
8917 : {
8918 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8919 : noDataValueSrc == i)
8920 0 : continue;
8921 : const GDALColorEntry *entry =
8922 4 : srcColorTable->GetColorEntry(i);
8923 4 : bool bMatchFound = false;
8924 13 : for (int j = 0; j < nRefEntries; ++j)
8925 : {
8926 10 : if (bHasNoDataValueRef && noDataValueRef == j)
8927 0 : continue;
8928 : const GDALColorEntry *entryRef =
8929 10 : destColorTable->GetColorEntry(j);
8930 10 : if (entry->c1 == entryRef->c1 &&
8931 2 : entry->c2 == entryRef->c2 &&
8932 2 : entry->c3 == entryRef->c3)
8933 : {
8934 1 : pTranslationTable[i] =
8935 : static_cast<unsigned char>(j);
8936 1 : bMatchFound = true;
8937 1 : break;
8938 : }
8939 : }
8940 4 : if (!bMatchFound)
8941 : {
8942 : // No exact match. Looking for closest color now.
8943 3 : int best_j = 0;
8944 3 : int best_distance = 0;
8945 3 : if (pApproximateMatching)
8946 0 : *pApproximateMatching = TRUE;
8947 12 : for (int j = 0; j < nRefEntries; ++j)
8948 : {
8949 : const GDALColorEntry *entryRef =
8950 9 : destColorTable->GetColorEntry(j);
8951 9 : int distance = (entry->c1 - entryRef->c1) *
8952 9 : (entry->c1 - entryRef->c1) +
8953 9 : (entry->c2 - entryRef->c2) *
8954 9 : (entry->c2 - entryRef->c2) +
8955 9 : (entry->c3 - entryRef->c3) *
8956 9 : (entry->c3 - entryRef->c3);
8957 9 : if (j == 0 || distance < best_distance)
8958 : {
8959 7 : best_j = j;
8960 7 : best_distance = distance;
8961 : }
8962 : }
8963 3 : pTranslationTable[i] =
8964 : static_cast<unsigned char>(best_j);
8965 : }
8966 : }
8967 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
8968 0 : pTranslationTable[noDataValueSrc] =
8969 : static_cast<unsigned char>(noDataValueRef);
8970 :
8971 1 : return pTranslationTable;
8972 : }
8973 : }
8974 : }
8975 3 : return nullptr;
8976 : }
8977 :
8978 : /************************************************************************/
8979 : /* SetFlushBlockErr() */
8980 : /************************************************************************/
8981 :
8982 : /**
8983 : * \brief Store that an error occurred while writing a dirty block.
8984 : *
8985 : * This function stores the fact that an error occurred while writing a dirty
8986 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8987 : * flushed when the block cache get full, it is not convenient/possible to
8988 : * report that a dirty block could not be written correctly. This function
8989 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8990 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8991 : * places where the user can easily match the error with the relevant dataset.
8992 : */
8993 :
8994 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8995 : {
8996 0 : eFlushBlockErr = eErr;
8997 0 : }
8998 :
8999 : /************************************************************************/
9000 : /* IncDirtyBlocks() */
9001 : /************************************************************************/
9002 :
9003 : /**
9004 : * \brief Increment/decrement the number of dirty blocks
9005 : */
9006 :
9007 794605 : void GDALRasterBand::IncDirtyBlocks(int nInc)
9008 : {
9009 794605 : if (poBandBlockCache)
9010 794605 : poBandBlockCache->IncDirtyBlocks(nInc);
9011 794603 : }
9012 :
9013 : /************************************************************************/
9014 : /* ReportError() */
9015 : /************************************************************************/
9016 :
9017 : #ifndef DOXYGEN_XML
9018 : /**
9019 : * \brief Emits an error related to a raster band.
9020 : *
9021 : * This function is a wrapper for regular CPLError(). The only difference
9022 : * with CPLError() is that it prepends the error message with the dataset
9023 : * name and the band number.
9024 : *
9025 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
9026 : * @param err_no the error number (CPLE_*) from cpl_error.h.
9027 : * @param fmt a printf() style format string. Any additional arguments
9028 : * will be treated as arguments to fill in this format in a manner
9029 : * similar to printf().
9030 : *
9031 : * @since GDAL 1.9.0
9032 : */
9033 :
9034 2475 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
9035 : const char *fmt, ...) const
9036 : {
9037 : va_list args;
9038 :
9039 2475 : va_start(args, fmt);
9040 :
9041 2475 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
9042 2475 : pszDSName = CPLGetFilename(pszDSName);
9043 2475 : if (pszDSName[0] != '\0')
9044 : {
9045 2402 : CPLError(eErrClass, err_no, "%s",
9046 4804 : CPLString()
9047 2402 : .Printf("%s, band %d: ", pszDSName, GetBand())
9048 4804 : .append(CPLString().vPrintf(fmt, args))
9049 : .c_str());
9050 : }
9051 : else
9052 : {
9053 73 : CPLErrorV(eErrClass, err_no, fmt, args);
9054 : }
9055 :
9056 2475 : va_end(args);
9057 2475 : }
9058 : #endif
9059 :
9060 : /************************************************************************/
9061 : /* GetVirtualMemAuto() */
9062 : /************************************************************************/
9063 :
9064 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9065 : *
9066 : * Only supported on Linux and Unix systems with mmap() for now.
9067 : *
9068 : * This method allows creating a virtual memory object for a GDALRasterBand,
9069 : * that exposes the whole image data as a virtual array.
9070 : *
9071 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9072 : * specialized implementation, such as for raw files, may also directly use
9073 : * mechanisms of the operating system to create a view of the underlying file
9074 : * into virtual memory ( CPLVirtualMemFileMapNew() )
9075 : *
9076 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9077 : * offer a specialized implementation with direct file mapping, provided that
9078 : * some requirements are met :
9079 : * - for all drivers, the dataset must be backed by a "real" file in the file
9080 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9081 : * must match the native ordering of the CPU.
9082 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9083 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9084 : * the file in sequential order, and be equally spaced (which is generally the
9085 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9086 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9087 : *
9088 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
9089 : * CPLVirtualMemFree() must be called before the raster band object is
9090 : * destroyed.
9091 : *
9092 : * If p is such a pointer and base_type the type matching
9093 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9094 : * accessed with
9095 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9096 : *
9097 : * This method is the same as the C GDALGetVirtualMemAuto() function.
9098 : *
9099 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9100 : * read/write the band.
9101 : *
9102 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
9103 : * one pixel value in the buffer to the start of the next pixel value within a
9104 : * scanline.
9105 : *
9106 : * @param pnLineSpace Output parameter giving the byte offset from the start of
9107 : * one scanline in the buffer to the start of the next.
9108 : *
9109 : * @param papszOptions NULL terminated list of options.
9110 : * If a specialized implementation exists, defining
9111 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9112 : * used. On the contrary, starting with GDAL 2.2, defining
9113 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9114 : * being used (thus only allowing efficient implementations to be used). When
9115 : * requiring or falling back to the default implementation, the following
9116 : * options are available : CACHE_SIZE (in bytes, defaults to
9117 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9118 : * to FALSE)
9119 : *
9120 : * @return a virtual memory object that must be unreferenced by
9121 : * CPLVirtualMemFree(), or NULL in case of failure.
9122 : *
9123 : * @since GDAL 1.11
9124 : */
9125 :
9126 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9127 : int *pnPixelSpace,
9128 : GIntBig *pnLineSpace,
9129 : char **papszOptions)
9130 : {
9131 9 : const char *pszImpl = CSLFetchNameValueDef(
9132 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9133 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9134 8 : EQUAL(pszImpl, "FALSE"))
9135 : {
9136 1 : return nullptr;
9137 : }
9138 :
9139 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9140 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9141 8 : if (pnPixelSpace)
9142 8 : *pnPixelSpace = nPixelSpace;
9143 8 : if (pnLineSpace)
9144 8 : *pnLineSpace = nLineSpace;
9145 : const size_t nCacheSize =
9146 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9147 : const size_t nPageSizeHint =
9148 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9149 8 : const bool bSingleThreadUsage = CPLTestBool(
9150 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9151 8 : return GDALRasterBandGetVirtualMem(
9152 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9153 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9154 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9155 8 : papszOptions);
9156 : }
9157 :
9158 : /************************************************************************/
9159 : /* GDALGetVirtualMemAuto() */
9160 : /************************************************************************/
9161 :
9162 : /**
9163 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9164 : *
9165 : * @see GDALRasterBand::GetVirtualMemAuto()
9166 : */
9167 :
9168 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9169 : int *pnPixelSpace, GIntBig *pnLineSpace,
9170 : CSLConstList papszOptions)
9171 : {
9172 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9173 :
9174 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9175 :
9176 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9177 31 : const_cast<char **>(papszOptions));
9178 : }
9179 :
9180 : /************************************************************************/
9181 : /* GDALGetDataCoverageStatus() */
9182 : /************************************************************************/
9183 :
9184 : /**
9185 : * \brief Get the coverage status of a sub-window of the raster.
9186 : *
9187 : * Returns whether a sub-window of the raster contains only data, only empty
9188 : * blocks or a mix of both. This function can be used to determine quickly
9189 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9190 : * be sparse.
9191 : *
9192 : * Empty blocks are blocks that are generally not physically present in the
9193 : * file, and when read through GDAL, contain only pixels whose value is the
9194 : * nodata value when it is set, or whose value is 0 when the nodata value is
9195 : * not set.
9196 : *
9197 : * The query is done in an efficient way without reading the actual pixel
9198 : * values. If not possible, or not implemented at all by the driver,
9199 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9200 : * be returned.
9201 : *
9202 : * The values that can be returned by the function are the following,
9203 : * potentially combined with the binary or operator :
9204 : * <ul>
9205 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9206 : * GetDataCoverageStatus(). This flag should be returned together with
9207 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9208 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9209 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9210 : * the queried window. This is typically identified by the concept of missing
9211 : * block in formats that supports it.
9212 : * </li>
9213 : * </ul>
9214 : *
9215 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9216 : * should be interpreted more as hint of potential presence of data. For example
9217 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9218 : * nodata value), instead of using the missing block mechanism,
9219 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9220 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9221 : *
9222 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9223 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9224 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9225 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9226 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9227 : * the function will exit, so that you can potentially refine the requested area
9228 : * to find which particular region(s) have missing blocks.
9229 : *
9230 : * @see GDALRasterBand::GetDataCoverageStatus()
9231 : *
9232 : * @param hBand raster band
9233 : *
9234 : * @param nXOff The pixel offset to the top left corner of the region
9235 : * of the band to be queried. This would be zero to start from the left side.
9236 : *
9237 : * @param nYOff The line offset to the top left corner of the region
9238 : * of the band to be queried. This would be zero to start from the top.
9239 : *
9240 : * @param nXSize The width of the region of the band to be queried in pixels.
9241 : *
9242 : * @param nYSize The height of the region of the band to be queried in lines.
9243 : *
9244 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9245 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9246 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9247 : * as the computation of the coverage matches the mask, the computation will be
9248 : * stopped. *pdfDataPct will not be valid in that case.
9249 : *
9250 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9251 : * to the (approximate) percentage in [0,100] of pixels in the queried
9252 : * sub-window that have valid values. The implementation might not always be
9253 : * able to compute it, in which case it will be set to a negative value.
9254 : *
9255 : * @return a binary-or'ed combination of possible values
9256 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9257 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9258 : *
9259 : * @note Added in GDAL 2.2
9260 : */
9261 :
9262 26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
9263 : int nYOff, int nXSize, int nYSize,
9264 : int nMaskFlagStop, double *pdfDataPct)
9265 : {
9266 26 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
9267 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
9268 :
9269 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9270 :
9271 26 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
9272 26 : nMaskFlagStop, pdfDataPct);
9273 : }
9274 :
9275 : /************************************************************************/
9276 : /* GetDataCoverageStatus() */
9277 : /************************************************************************/
9278 :
9279 : /**
9280 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
9281 : * int nYOff,
9282 : * int nXSize,
9283 : * int nYSize,
9284 : * int nMaskFlagStop,
9285 : * double* pdfDataPct)
9286 : * \brief Get the coverage status of a sub-window of the raster.
9287 : *
9288 : * Returns whether a sub-window of the raster contains only data, only empty
9289 : * blocks or a mix of both. This function can be used to determine quickly
9290 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9291 : * be sparse.
9292 : *
9293 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9294 : * value when it is set, or whose value is 0 when the nodata value is not set.
9295 : *
9296 : * The query is done in an efficient way without reading the actual pixel
9297 : * values. If not possible, or not implemented at all by the driver,
9298 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9299 : * be returned.
9300 : *
9301 : * The values that can be returned by the function are the following,
9302 : * potentially combined with the binary or operator :
9303 : * <ul>
9304 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9305 : * GetDataCoverageStatus(). This flag should be returned together with
9306 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9307 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9308 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9309 : * the queried window. This is typically identified by the concept of missing
9310 : * block in formats that supports it.
9311 : * </li>
9312 : * </ul>
9313 : *
9314 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9315 : * should be interpreted more as hint of potential presence of data. For example
9316 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9317 : * nodata value), instead of using the missing block mechanism,
9318 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9319 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9320 : *
9321 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9322 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9323 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9324 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9325 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9326 : * the function will exit, so that you can potentially refine the requested area
9327 : * to find which particular region(s) have missing blocks.
9328 : *
9329 : * @see GDALGetDataCoverageStatus()
9330 : *
9331 : * @param nXOff The pixel offset to the top left corner of the region
9332 : * of the band to be queried. This would be zero to start from the left side.
9333 : *
9334 : * @param nYOff The line offset to the top left corner of the region
9335 : * of the band to be queried. This would be zero to start from the top.
9336 : *
9337 : * @param nXSize The width of the region of the band to be queried in pixels.
9338 : *
9339 : * @param nYSize The height of the region of the band to be queried in lines.
9340 : *
9341 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9342 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9343 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9344 : * as the computation of the coverage matches the mask, the computation will be
9345 : * stopped. *pdfDataPct will not be valid in that case.
9346 : *
9347 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9348 : * to the (approximate) percentage in [0,100] of pixels in the queried
9349 : * sub-window that have valid values. The implementation might not always be
9350 : * able to compute it, in which case it will be set to a negative value.
9351 : *
9352 : * @return a binary-or'ed combination of possible values
9353 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9354 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9355 : *
9356 : * @note Added in GDAL 2.2
9357 : */
9358 :
9359 : /**
9360 : * \brief Get the coverage status of a sub-window of the raster.
9361 : *
9362 : * Returns whether a sub-window of the raster contains only data, only empty
9363 : * blocks or a mix of both. This function can be used to determine quickly
9364 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9365 : * be sparse.
9366 : *
9367 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9368 : * value when it is set, or whose value is 0 when the nodata value is not set.
9369 : *
9370 : * The query is done in an efficient way without reading the actual pixel
9371 : * values. If not possible, or not implemented at all by the driver,
9372 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9373 : * be returned.
9374 : *
9375 : * The values that can be returned by the function are the following,
9376 : * potentially combined with the binary or operator :
9377 : * <ul>
9378 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9379 : * GetDataCoverageStatus(). This flag should be returned together with
9380 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9381 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9382 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9383 : * the queried window. This is typically identified by the concept of missing
9384 : * block in formats that supports it.
9385 : * </li>
9386 : * </ul>
9387 : *
9388 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9389 : * should be interpreted more as hint of potential presence of data. For example
9390 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9391 : * nodata value), instead of using the missing block mechanism,
9392 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9393 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9394 : *
9395 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9396 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9397 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9398 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9399 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9400 : * the function will exit, so that you can potentially refine the requested area
9401 : * to find which particular region(s) have missing blocks.
9402 : *
9403 : * @see GDALGetDataCoverageStatus()
9404 : *
9405 : * @param nXOff The pixel offset to the top left corner of the region
9406 : * of the band to be queried. This would be zero to start from the left side.
9407 : *
9408 : * @param nYOff The line offset to the top left corner of the region
9409 : * of the band to be queried. This would be zero to start from the top.
9410 : *
9411 : * @param nXSize The width of the region of the band to be queried in pixels.
9412 : *
9413 : * @param nYSize The height of the region of the band to be queried in lines.
9414 : *
9415 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9416 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9417 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9418 : * as the computation of the coverage matches the mask, the computation will be
9419 : * stopped. *pdfDataPct will not be valid in that case.
9420 : *
9421 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9422 : * to the (approximate) percentage in [0,100] of pixels in the queried
9423 : * sub-window that have valid values. The implementation might not always be
9424 : * able to compute it, in which case it will be set to a negative value.
9425 : *
9426 : * @return a binary-or'ed combination of possible values
9427 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9428 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9429 : *
9430 : * @note Added in GDAL 2.2
9431 : */
9432 :
9433 4658 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9434 : int nYSize, int nMaskFlagStop,
9435 : double *pdfDataPct)
9436 : {
9437 4658 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9438 4658 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9439 4658 : nYOff + nYSize > nRasterYSize)
9440 : {
9441 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9442 0 : if (pdfDataPct)
9443 0 : *pdfDataPct = 0.0;
9444 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9445 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
9446 : }
9447 4658 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9448 4658 : pdfDataPct);
9449 : }
9450 :
9451 : /************************************************************************/
9452 : /* IGetDataCoverageStatus() */
9453 : /************************************************************************/
9454 :
9455 684 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9456 : int /*nXSize*/, int /*nYSize*/,
9457 : int /*nMaskFlagStop*/,
9458 : double *pdfDataPct)
9459 : {
9460 684 : if (pdfDataPct != nullptr)
9461 0 : *pdfDataPct = 100.0;
9462 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9463 684 : GDAL_DATA_COVERAGE_STATUS_DATA;
9464 : }
9465 :
9466 : //! @cond Doxygen_Suppress
9467 : /************************************************************************/
9468 : /* EnterReadWrite() */
9469 : /************************************************************************/
9470 :
9471 7771060 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9472 : {
9473 7771060 : if (poDS != nullptr)
9474 7025170 : return poDS->EnterReadWrite(eRWFlag);
9475 745890 : return FALSE;
9476 : }
9477 :
9478 : /************************************************************************/
9479 : /* LeaveReadWrite() */
9480 : /************************************************************************/
9481 :
9482 1128660 : void GDALRasterBand::LeaveReadWrite()
9483 : {
9484 1128660 : if (poDS != nullptr)
9485 1128660 : poDS->LeaveReadWrite();
9486 1128630 : }
9487 :
9488 : /************************************************************************/
9489 : /* InitRWLock() */
9490 : /************************************************************************/
9491 :
9492 3977190 : void GDALRasterBand::InitRWLock()
9493 : {
9494 3977190 : if (poDS != nullptr)
9495 3976790 : poDS->InitRWLock();
9496 3977190 : }
9497 :
9498 : //! @endcond
9499 :
9500 : // clang-format off
9501 :
9502 : /**
9503 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9504 : * \brief Set metadata.
9505 : *
9506 : * CAUTION: depending on the format, older values of the updated information
9507 : * might still be found in the file in a "ghost" state, even if no longer
9508 : * accessible through the GDAL API. This is for example the case of the GTiff
9509 : * format (this is not a exhaustive list)
9510 : *
9511 : * The C function GDALSetMetadata() does the same thing as this method.
9512 : *
9513 : * @param papszMetadata the metadata in name=value string list format to
9514 : * apply.
9515 : * @param pszDomain the domain of interest. Use "" or NULL for the default
9516 : * domain.
9517 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9518 : * metadata has been accepted, but is likely not maintained persistently
9519 : * by the underlying object between sessions.
9520 : */
9521 :
9522 : /**
9523 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9524 : * \brief Set single metadata item.
9525 : *
9526 : * CAUTION: depending on the format, older values of the updated information
9527 : * might still be found in the file in a "ghost" state, even if no longer
9528 : * accessible through the GDAL API. This is for example the case of the GTiff
9529 : * format (this is not a exhaustive list)
9530 : *
9531 : * The C function GDALSetMetadataItem() does the same thing as this method.
9532 : *
9533 : * @param pszName the key for the metadata item to fetch.
9534 : * @param pszValue the value to assign to the key.
9535 : * @param pszDomain the domain to set within, use NULL for the default domain.
9536 : *
9537 : * @return CE_None on success, or an error code on failure.
9538 : */
9539 :
9540 : // clang-format on
9541 :
9542 : //! @cond Doxygen_Suppress
9543 : /************************************************************************/
9544 : /* EnablePixelTypeSignedByteWarning() */
9545 : /************************************************************************/
9546 :
9547 156757 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9548 : {
9549 156757 : m_bEnablePixelTypeSignedByteWarning = b;
9550 156757 : }
9551 :
9552 4884 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9553 : {
9554 4884 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9555 4884 : }
9556 :
9557 : //! @endcond
9558 :
9559 : /************************************************************************/
9560 : /* GetMetadataItem() */
9561 : /************************************************************************/
9562 :
9563 620065 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9564 : const char *pszDomain)
9565 : {
9566 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9567 620065 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9568 462119 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9569 321700 : EQUAL(pszName, "PIXELTYPE"))
9570 : {
9571 2 : CPLError(CE_Warning, CPLE_AppDefined,
9572 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9573 : "used to signal signed 8-bit raster. Change your code to "
9574 : "test for the new GDT_Int8 data type instead.");
9575 : }
9576 620065 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9577 : }
9578 :
9579 : /************************************************************************/
9580 : /* WindowIterator */
9581 : /************************************************************************/
9582 :
9583 : //! @cond Doxygen_Suppress
9584 :
9585 442 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
9586 : int nRasterYSize,
9587 : int nBlockXSize, int nBlockYSize,
9588 442 : int nRow, int nCol)
9589 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
9590 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
9591 442 : m_col(nCol)
9592 : {
9593 442 : }
9594 :
9595 553 : bool GDALRasterBand::WindowIterator::operator==(
9596 : const WindowIterator &other) const
9597 : {
9598 192 : return m_row == other.m_row && m_col == other.m_col &&
9599 192 : m_nRasterXSize == other.m_nRasterXSize &&
9600 192 : m_nRasterYSize == other.m_nRasterYSize &&
9601 937 : m_nBlockXSize == other.m_nBlockXSize &&
9602 745 : m_nBlockYSize == other.m_nBlockYSize;
9603 : }
9604 :
9605 527 : bool GDALRasterBand::WindowIterator::operator!=(
9606 : const WindowIterator &other) const
9607 : {
9608 527 : return !(*this == other);
9609 : }
9610 :
9611 : GDALRasterBand::WindowIterator::value_type
9612 360 : GDALRasterBand::WindowIterator::operator*() const
9613 : {
9614 : GDALRasterWindow ret;
9615 360 : ret.nXOff = m_col * m_nBlockXSize;
9616 360 : ret.nYOff = m_row * m_nBlockYSize;
9617 360 : ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
9618 360 : ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
9619 :
9620 360 : return ret;
9621 : }
9622 :
9623 358 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
9624 : {
9625 358 : m_col++;
9626 358 : if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
9627 : {
9628 352 : m_col = 0;
9629 352 : m_row++;
9630 : }
9631 358 : return *this;
9632 : }
9633 :
9634 234 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
9635 234 : const GDALRasterBand &band)
9636 234 : : m_nRasterXSize(band.GetXSize()), m_nRasterYSize(band.GetYSize()),
9637 234 : m_nBlockXSize(-1), m_nBlockYSize(-1)
9638 : {
9639 : // If invalid block size is reported, just use a value of 1.
9640 234 : CPLErrorStateBackuper state(CPLQuietErrorHandler);
9641 : #ifdef CSA_BUILD
9642 : assert(this);
9643 : #endif
9644 234 : band.GetBlockSize(&m_nBlockXSize, &m_nBlockYSize);
9645 234 : m_nBlockXSize = std::max<int>(m_nBlockXSize, 1);
9646 234 : m_nBlockYSize = std::max<int>(m_nBlockYSize, 1);
9647 234 : }
9648 :
9649 : GDALRasterBand::WindowIterator
9650 207 : GDALRasterBand::WindowIteratorWrapper::begin() const
9651 : {
9652 207 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
9653 207 : m_nBlockYSize, 0, 0);
9654 : }
9655 :
9656 : GDALRasterBand::WindowIterator
9657 207 : GDALRasterBand::WindowIteratorWrapper::end() const
9658 : {
9659 207 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
9660 207 : m_nBlockYSize,
9661 207 : DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
9662 : }
9663 :
9664 : //! @endcond
9665 :
9666 : /** Return an object whose begin() and end() methods can be used to iterate
9667 : * over a GDALRasterWindow for each block in this raster band. The iteration
9668 : * order is from left to right, then from top to bottom.
9669 : *
9670 : \code{.cpp}
9671 : std::vector<double> pixelValues;
9672 : for (const auto& window : poBand->IterateWindows()) {
9673 : CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
9674 : window.nXSize, window.nYSize);
9675 : // check eErr
9676 : }
9677 : \endcode
9678 : *
9679 : *
9680 : * @since GDAL 3.12
9681 : */
9682 234 : GDALRasterBand::WindowIteratorWrapper GDALRasterBand::IterateWindows() const
9683 : {
9684 234 : return WindowIteratorWrapper(*this);
9685 : }
9686 :
9687 : /************************************************************************/
9688 : /* GDALMDArrayFromRasterBand */
9689 : /************************************************************************/
9690 :
9691 : class GDALMDArrayFromRasterBand final : public GDALMDArray
9692 : {
9693 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9694 :
9695 : GDALDataset *m_poDS;
9696 : GDALRasterBand *m_poBand;
9697 : GDALExtendedDataType m_dt;
9698 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9699 : std::string m_osUnit;
9700 : std::vector<GByte> m_pabyNoData{};
9701 : std::shared_ptr<GDALMDArray> m_varX{};
9702 : std::shared_ptr<GDALMDArray> m_varY{};
9703 : std::string m_osFilename{};
9704 :
9705 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9706 : const size_t *count, const GInt64 *arrayStep,
9707 : const GPtrDiff_t *bufferStride,
9708 : const GDALExtendedDataType &bufferDataType,
9709 : void *pBuffer) const;
9710 :
9711 : protected:
9712 23 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9713 46 : : GDALAbstractMDArray(std::string(),
9714 46 : std::string(poDS->GetDescription()) +
9715 : CPLSPrintf(" band %d", poBand->GetBand())),
9716 46 : GDALMDArray(std::string(),
9717 46 : std::string(poDS->GetDescription()) +
9718 : CPLSPrintf(" band %d", poBand->GetBand())),
9719 : m_poDS(poDS), m_poBand(poBand),
9720 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9721 115 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9722 : {
9723 23 : m_poDS->Reference();
9724 :
9725 23 : int bHasNoData = false;
9726 23 : if (m_poBand->GetRasterDataType() == GDT_Int64)
9727 : {
9728 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9729 0 : if (bHasNoData)
9730 : {
9731 0 : m_pabyNoData.resize(m_dt.GetSize());
9732 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9733 : m_dt.GetNumericDataType(), 0, 1);
9734 : }
9735 : }
9736 23 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9737 : {
9738 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9739 0 : if (bHasNoData)
9740 : {
9741 0 : m_pabyNoData.resize(m_dt.GetSize());
9742 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9743 : m_dt.GetNumericDataType(), 0, 1);
9744 : }
9745 : }
9746 : else
9747 : {
9748 23 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9749 23 : if (bHasNoData)
9750 : {
9751 1 : m_pabyNoData.resize(m_dt.GetSize());
9752 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9753 : m_dt.GetNumericDataType(), 0, 1);
9754 : }
9755 : }
9756 :
9757 23 : const int nXSize = poBand->GetXSize();
9758 23 : const int nYSize = poBand->GetYSize();
9759 :
9760 23 : auto poSRS = m_poDS->GetSpatialRef();
9761 46 : std::string osTypeY;
9762 46 : std::string osTypeX;
9763 46 : std::string osDirectionY;
9764 46 : std::string osDirectionX;
9765 23 : if (poSRS && poSRS->GetAxesCount() == 2)
9766 : {
9767 21 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9768 21 : OGRAxisOrientation eOrientation1 = OAO_Other;
9769 21 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
9770 21 : OGRAxisOrientation eOrientation2 = OAO_Other;
9771 21 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
9772 21 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9773 : {
9774 5 : if (mapping == std::vector<int>{1, 2})
9775 : {
9776 5 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9777 5 : osDirectionY = "NORTH";
9778 5 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9779 5 : osDirectionX = "EAST";
9780 : }
9781 : }
9782 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9783 : {
9784 16 : if (mapping == std::vector<int>{2, 1})
9785 : {
9786 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9787 16 : osDirectionY = "NORTH";
9788 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9789 16 : osDirectionX = "EAST";
9790 : }
9791 : }
9792 : }
9793 :
9794 115 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9795 : "/", "Y", osTypeY, osDirectionY, nYSize),
9796 46 : std::make_shared<GDALDimensionWeakIndexingVar>(
9797 69 : "/", "X", osTypeX, osDirectionX, nXSize)};
9798 :
9799 23 : GDALGeoTransform gt;
9800 23 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
9801 : {
9802 44 : m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
9803 44 : gt[0], gt[1], 0.5);
9804 22 : m_dims[1]->SetIndexingVariable(m_varX);
9805 :
9806 44 : m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
9807 44 : gt[3], gt[5], 0.5);
9808 22 : m_dims[0]->SetIndexingVariable(m_varY);
9809 : }
9810 23 : }
9811 :
9812 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9813 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9814 : const GDALExtendedDataType &bufferDataType,
9815 : void *pDstBuffer) const override;
9816 :
9817 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9818 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9819 : const GDALExtendedDataType &bufferDataType,
9820 : const void *pSrcBuffer) override
9821 : {
9822 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9823 : bufferStride, bufferDataType,
9824 1 : const_cast<void *>(pSrcBuffer));
9825 : }
9826 :
9827 : public:
9828 46 : ~GDALMDArrayFromRasterBand() override
9829 23 : {
9830 23 : m_poDS->ReleaseRef();
9831 46 : }
9832 :
9833 23 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9834 : GDALRasterBand *poBand)
9835 : {
9836 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9837 46 : new GDALMDArrayFromRasterBand(poDS, poBand)));
9838 23 : array->SetSelf(array);
9839 46 : return array;
9840 : }
9841 :
9842 2 : bool IsWritable() const override
9843 : {
9844 2 : return m_poDS->GetAccess() == GA_Update;
9845 : }
9846 :
9847 97 : const std::string &GetFilename() const override
9848 : {
9849 97 : return m_osFilename;
9850 : }
9851 :
9852 : const std::vector<std::shared_ptr<GDALDimension>> &
9853 299 : GetDimensions() const override
9854 : {
9855 299 : return m_dims;
9856 : }
9857 :
9858 138 : const GDALExtendedDataType &GetDataType() const override
9859 : {
9860 138 : return m_dt;
9861 : }
9862 :
9863 3 : const std::string &GetUnit() const override
9864 : {
9865 3 : return m_osUnit;
9866 : }
9867 :
9868 29 : const void *GetRawNoDataValue() const override
9869 : {
9870 29 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9871 : }
9872 :
9873 2 : double GetOffset(bool *pbHasOffset,
9874 : GDALDataType *peStorageType) const override
9875 : {
9876 2 : int bHasOffset = false;
9877 2 : double dfRes = m_poBand->GetOffset(&bHasOffset);
9878 2 : if (pbHasOffset)
9879 2 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9880 2 : if (peStorageType)
9881 1 : *peStorageType = GDT_Unknown;
9882 2 : return dfRes;
9883 : }
9884 :
9885 2 : double GetScale(bool *pbHasScale,
9886 : GDALDataType *peStorageType) const override
9887 : {
9888 2 : int bHasScale = false;
9889 2 : double dfRes = m_poBand->GetScale(&bHasScale);
9890 2 : if (pbHasScale)
9891 2 : *pbHasScale = CPL_TO_BOOL(bHasScale);
9892 2 : if (peStorageType)
9893 1 : *peStorageType = GDT_Unknown;
9894 2 : return dfRes;
9895 : }
9896 :
9897 84 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9898 : {
9899 84 : auto poSrcSRS = m_poDS->GetSpatialRef();
9900 84 : if (!poSrcSRS)
9901 2 : return nullptr;
9902 164 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9903 :
9904 164 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9905 82 : constexpr int iYDim = 0;
9906 82 : constexpr int iXDim = 1;
9907 246 : for (auto &m : axisMapping)
9908 : {
9909 164 : if (m == 1)
9910 82 : m = iXDim + 1;
9911 82 : else if (m == 2)
9912 82 : m = iYDim + 1;
9913 : else
9914 0 : m = 0;
9915 : }
9916 82 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9917 82 : return poSRS;
9918 : }
9919 :
9920 29 : std::vector<GUInt64> GetBlockSize() const override
9921 : {
9922 29 : int nBlockXSize = 0;
9923 29 : int nBlockYSize = 0;
9924 29 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9925 29 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9926 29 : static_cast<GUInt64>(nBlockXSize)};
9927 : }
9928 :
9929 : class MDIAsAttribute final : public GDALAttribute
9930 : {
9931 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9932 : const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
9933 : std::string m_osValue;
9934 :
9935 : public:
9936 2 : MDIAsAttribute(const std::string &name, const std::string &value)
9937 2 : : GDALAbstractMDArray(std::string(), name),
9938 4 : GDALAttribute(std::string(), name), m_osValue(value)
9939 : {
9940 2 : }
9941 :
9942 : const std::vector<std::shared_ptr<GDALDimension>> &
9943 : GetDimensions() const override;
9944 :
9945 2 : const GDALExtendedDataType &GetDataType() const override
9946 : {
9947 2 : return m_dt;
9948 : }
9949 :
9950 1 : bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
9951 : const GPtrDiff_t *,
9952 : const GDALExtendedDataType &bufferDataType,
9953 : void *pDstBuffer) const override
9954 : {
9955 1 : const char *pszStr = m_osValue.c_str();
9956 1 : GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
9957 : bufferDataType);
9958 1 : return true;
9959 : }
9960 : };
9961 :
9962 : std::vector<std::shared_ptr<GDALAttribute>>
9963 14 : GetAttributes(CSLConstList) const override
9964 : {
9965 14 : std::vector<std::shared_ptr<GDALAttribute>> res;
9966 14 : auto papszMD = m_poBand->GetMetadata();
9967 16 : for (auto iter = papszMD; iter && iter[0]; ++iter)
9968 : {
9969 2 : char *pszKey = nullptr;
9970 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9971 2 : if (pszKey && pszValue)
9972 : {
9973 : res.emplace_back(
9974 2 : std::make_shared<MDIAsAttribute>(pszKey, pszValue));
9975 : }
9976 2 : CPLFree(pszKey);
9977 : }
9978 14 : return res;
9979 : }
9980 : };
9981 :
9982 31 : bool GDALMDArrayFromRasterBand::IRead(
9983 : const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
9984 : const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
9985 : void *pDstBuffer) const
9986 : {
9987 31 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9988 31 : bufferDataType, pDstBuffer);
9989 : }
9990 :
9991 : const std::vector<std::shared_ptr<GDALDimension>> &
9992 3 : GDALMDArrayFromRasterBand::MDIAsAttribute::GetDimensions() const
9993 : {
9994 3 : return m_dims;
9995 : }
9996 :
9997 : /************************************************************************/
9998 : /* ReadWrite() */
9999 : /************************************************************************/
10000 :
10001 32 : bool GDALMDArrayFromRasterBand::ReadWrite(
10002 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
10003 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10004 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
10005 : {
10006 32 : constexpr size_t iDimX = 1;
10007 32 : constexpr size_t iDimY = 0;
10008 32 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
10009 : arrayStartIdx, count, arrayStep, bufferStride,
10010 32 : bufferDataType, pBuffer);
10011 : }
10012 :
10013 : /************************************************************************/
10014 : /* GDALMDRasterIOFromBand() */
10015 : /************************************************************************/
10016 :
10017 65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
10018 : size_t iDimX, size_t iDimY,
10019 : const GUInt64 *arrayStartIdx, const size_t *count,
10020 : const GInt64 *arrayStep,
10021 : const GPtrDiff_t *bufferStride,
10022 : const GDALExtendedDataType &bufferDataType,
10023 : void *pBuffer)
10024 : {
10025 65 : const auto eDT(bufferDataType.GetNumericDataType());
10026 65 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
10027 65 : const int nX =
10028 65 : arrayStep[iDimX] > 0
10029 65 : ? static_cast<int>(arrayStartIdx[iDimX])
10030 2 : : static_cast<int>(arrayStartIdx[iDimX] -
10031 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
10032 65 : const int nY =
10033 65 : arrayStep[iDimY] > 0
10034 65 : ? static_cast<int>(arrayStartIdx[iDimY])
10035 2 : : static_cast<int>(arrayStartIdx[iDimY] -
10036 2 : (count[iDimY] - 1) * -arrayStep[iDimY]);
10037 65 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
10038 65 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
10039 65 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
10040 65 : int nStrideXSign = 1;
10041 65 : if (arrayStep[iDimX] < 0)
10042 : {
10043 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
10044 2 : nStrideXSign = -1;
10045 : }
10046 65 : int nStrideYSign = 1;
10047 65 : if (arrayStep[iDimY] < 0)
10048 : {
10049 2 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
10050 2 : nStrideYSign = -1;
10051 : }
10052 :
10053 130 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
10054 65 : static_cast<int>(count[iDimX]),
10055 65 : static_cast<int>(count[iDimY]), eDT,
10056 : static_cast<GSpacing>(
10057 65 : nStrideXSign * bufferStride[iDimX] * nDTSize),
10058 : static_cast<GSpacing>(
10059 65 : nStrideYSign * bufferStride[iDimY] * nDTSize),
10060 65 : nullptr) == CE_None;
10061 : }
10062 :
10063 : /************************************************************************/
10064 : /* AsMDArray() */
10065 : /************************************************************************/
10066 :
10067 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10068 : *
10069 : * The band must be linked to a GDALDataset. If this dataset is not already
10070 : * marked as shared, it will be, so that the returned array holds a reference
10071 : * to it.
10072 : *
10073 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10074 : * returned array will have an associated indexing variable.
10075 : *
10076 : * This is the same as the C function GDALRasterBandAsMDArray().
10077 : *
10078 : * The "reverse" method is GDALMDArray::AsClassicDataset().
10079 : *
10080 : * @return a new array, or nullptr.
10081 : *
10082 : * @since GDAL 3.1
10083 : */
10084 23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
10085 : {
10086 23 : if (!poDS)
10087 : {
10088 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
10089 0 : return nullptr;
10090 : }
10091 23 : if (!poDS->GetShared())
10092 : {
10093 23 : poDS->MarkAsShared();
10094 : }
10095 : return GDALMDArrayFromRasterBand::Create(
10096 23 : poDS, const_cast<GDALRasterBand *>(this));
10097 : }
10098 :
10099 : /************************************************************************/
10100 : /* InterpolateAtPoint() */
10101 : /************************************************************************/
10102 :
10103 : /**
10104 : * \brief Interpolates the value between pixels using a resampling algorithm,
10105 : * taking pixel/line coordinates as input.
10106 : *
10107 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
10108 : * @param dfLine line coordinate as a double, where interpolation should be done.
10109 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10110 : * @param pdfRealValue pointer to real part of interpolated value
10111 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10112 : *
10113 : * @return CE_None on success, or an error code on failure.
10114 : * @since GDAL 3.10
10115 : */
10116 :
10117 167 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
10118 : GDALRIOResampleAlg eInterpolation,
10119 : double *pdfRealValue,
10120 : double *pdfImagValue) const
10121 : {
10122 167 : if (eInterpolation != GRIORA_NearestNeighbour &&
10123 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
10124 : eInterpolation != GRIORA_CubicSpline)
10125 : {
10126 2 : CPLError(CE_Failure, CPLE_AppDefined,
10127 : "Only nearest, bilinear, cubic and cubicspline interpolation "
10128 : "methods "
10129 : "allowed");
10130 :
10131 2 : return CE_Failure;
10132 : }
10133 :
10134 165 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
10135 165 : if (!m_poPointsCache)
10136 85 : m_poPointsCache = new GDALDoublePointsCache();
10137 :
10138 : const bool res =
10139 165 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
10140 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
10141 :
10142 165 : return res ? CE_None : CE_Failure;
10143 : }
10144 :
10145 : /************************************************************************/
10146 : /* GDALRasterInterpolateAtPoint() */
10147 : /************************************************************************/
10148 :
10149 : /**
10150 : * \brief Interpolates the value between pixels using
10151 : * a resampling algorithm
10152 : *
10153 : * @see GDALRasterBand::InterpolateAtPoint()
10154 : * @since GDAL 3.10
10155 : */
10156 :
10157 144 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10158 : double dfLine,
10159 : GDALRIOResampleAlg eInterpolation,
10160 : double *pdfRealValue, double *pdfImagValue)
10161 : {
10162 144 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10163 :
10164 144 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10165 144 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10166 144 : pdfRealValue, pdfImagValue);
10167 : }
10168 :
10169 : /************************************************************************/
10170 : /* InterpolateAtGeolocation() */
10171 : /************************************************************************/
10172 :
10173 : /**
10174 : * \brief Interpolates the value between pixels using a resampling algorithm,
10175 : * taking georeferenced coordinates as input.
10176 : *
10177 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
10178 : * must be in the "natural" SRS of the dataset, that is the one returned by
10179 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
10180 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
10181 : * array (generally WGS 84) if there is a geolocation array.
10182 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10183 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10184 : * be a easting, and dfGeolocY a northing.
10185 : *
10186 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10187 : * expressed in that CRS, and that tuple must be conformant with the
10188 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10189 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10190 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10191 : * before calling this method, and in that case, dfGeolocX must be a longitude
10192 : * or an easting value, and dfGeolocX a latitude or a northing value.
10193 : *
10194 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
10195 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
10196 : * it for details on how that transformation is done.
10197 : *
10198 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
10199 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10200 : * where interpolation should be done.
10201 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
10202 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10203 : * where interpolation should be done.
10204 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
10205 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10206 : * @param pdfRealValue pointer to real part of interpolated value
10207 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10208 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
10209 : *
10210 : * @return CE_None on success, or an error code on failure.
10211 : * @since GDAL 3.11
10212 : */
10213 :
10214 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
10215 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
10216 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
10217 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
10218 : {
10219 : double dfPixel;
10220 : double dfLine;
10221 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
10222 : &dfLine,
10223 15 : papszTransformerOptions) != CE_None)
10224 : {
10225 1 : return CE_Failure;
10226 : }
10227 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
10228 14 : pdfImagValue);
10229 : }
10230 :
10231 : /************************************************************************/
10232 : /* GDALRasterInterpolateAtGeolocation() */
10233 : /************************************************************************/
10234 :
10235 : /**
10236 : * \brief Interpolates the value between pixels using a resampling algorithm,
10237 : * taking georeferenced coordinates as input.
10238 : *
10239 : * @see GDALRasterBand::InterpolateAtGeolocation()
10240 : * @since GDAL 3.11
10241 : */
10242 :
10243 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
10244 : double dfGeolocX, double dfGeolocY,
10245 : OGRSpatialReferenceH hSRS,
10246 : GDALRIOResampleAlg eInterpolation,
10247 : double *pdfRealValue,
10248 : double *pdfImagValue,
10249 : CSLConstList papszTransformerOptions)
10250 : {
10251 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
10252 :
10253 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10254 15 : return poBand->InterpolateAtGeolocation(
10255 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
10256 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
10257 : }
10258 :
10259 : /************************************************************************/
10260 : /* GDALRasterBand::SplitRasterIO() */
10261 : /************************************************************************/
10262 :
10263 : //! @cond Doxygen_Suppress
10264 :
10265 : /** Implements IRasterIO() by dividing the request in 2.
10266 : *
10267 : * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
10268 : *
10269 : * Return CE_Warning if the split could not be done, CE_None in case of
10270 : * success and CE_Failure in case of error.
10271 : *
10272 : * @since 3.12
10273 : */
10274 999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
10275 : [[maybe_unused]] int nXSize,
10276 : [[maybe_unused]] int nYSize, void *pData,
10277 : int nBufXSize, int nBufYSize,
10278 : GDALDataType eBufType,
10279 : GSpacing nPixelSpace, GSpacing nLineSpace,
10280 : GDALRasterIOExtraArg *psExtraArg)
10281 : {
10282 999 : CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
10283 :
10284 999 : GByte *pabyData = static_cast<GByte *>(pData);
10285 999 : if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
10286 : {
10287 : GDALRasterIOExtraArg sArg;
10288 499 : INIT_RASTERIO_EXTRA_ARG(sArg);
10289 499 : const int nHalfHeight = nBufYSize / 2;
10290 :
10291 499 : sArg.pfnProgress = GDALScaledProgress;
10292 499 : sArg.pProgressData = GDALCreateScaledProgress(
10293 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10294 499 : if (sArg.pProgressData == nullptr)
10295 499 : sArg.pfnProgress = nullptr;
10296 998 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
10297 : pabyData, nBufXSize, nHalfHeight, eBufType,
10298 499 : nPixelSpace, nLineSpace, &sArg);
10299 499 : GDALDestroyScaledProgress(sArg.pProgressData);
10300 :
10301 499 : if (eErr == CE_None)
10302 : {
10303 499 : sArg.pfnProgress = GDALScaledProgress;
10304 499 : sArg.pProgressData = GDALCreateScaledProgress(
10305 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10306 499 : if (sArg.pProgressData == nullptr)
10307 499 : sArg.pfnProgress = nullptr;
10308 998 : eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
10309 : nBufYSize - nHalfHeight,
10310 499 : pabyData + nHalfHeight * nLineSpace, nBufXSize,
10311 : nBufYSize - nHalfHeight, eBufType, nPixelSpace,
10312 499 : nLineSpace, &sArg);
10313 499 : GDALDestroyScaledProgress(sArg.pProgressData);
10314 : }
10315 499 : return eErr;
10316 : }
10317 500 : else if (nBufXSize >= 2)
10318 : {
10319 : GDALRasterIOExtraArg sArg;
10320 500 : INIT_RASTERIO_EXTRA_ARG(sArg);
10321 500 : const int nHalfWidth = nBufXSize / 2;
10322 :
10323 500 : sArg.pfnProgress = GDALScaledProgress;
10324 500 : sArg.pProgressData = GDALCreateScaledProgress(
10325 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10326 500 : if (sArg.pProgressData == nullptr)
10327 500 : sArg.pfnProgress = nullptr;
10328 1000 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
10329 : pabyData, nHalfWidth, nBufYSize, eBufType,
10330 500 : nPixelSpace, nLineSpace, &sArg);
10331 500 : GDALDestroyScaledProgress(sArg.pProgressData);
10332 :
10333 500 : if (eErr == CE_None)
10334 : {
10335 500 : sArg.pfnProgress = GDALScaledProgress;
10336 500 : sArg.pProgressData = GDALCreateScaledProgress(
10337 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10338 500 : if (sArg.pProgressData == nullptr)
10339 500 : sArg.pfnProgress = nullptr;
10340 1000 : eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
10341 : nBufXSize - nHalfWidth, nBufYSize,
10342 500 : pabyData + nHalfWidth * nPixelSpace,
10343 : nBufXSize - nHalfWidth, nBufYSize, eBufType,
10344 500 : nPixelSpace, nLineSpace, &sArg);
10345 500 : GDALDestroyScaledProgress(sArg.pProgressData);
10346 : }
10347 500 : return eErr;
10348 : }
10349 :
10350 0 : return CE_Warning;
10351 : }
10352 :
10353 : //! @endcond
10354 :
10355 : /************************************************************************/
10356 : /* ThrowIfNotSameDimensions() */
10357 : /************************************************************************/
10358 :
10359 : //! @cond Doxygen_Suppress
10360 : /* static */
10361 169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
10362 : const GDALRasterBand &second)
10363 : {
10364 320 : if (first.GetXSize() != second.GetXSize() ||
10365 151 : first.GetYSize() != second.GetYSize())
10366 : {
10367 36 : throw std::runtime_error("Bands do not have the same dimensions");
10368 : }
10369 133 : }
10370 :
10371 : //! @endcond
10372 :
10373 : /************************************************************************/
10374 : /* GDALRasterBandUnaryOp() */
10375 : /************************************************************************/
10376 :
10377 : /** Apply a unary operation on this band.
10378 : *
10379 : * The resulting band is lazy evaluated. A reference is taken on the input
10380 : * dataset.
10381 : *
10382 : * @since 3.12
10383 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10384 : */
10385 : GDALComputedRasterBandH
10386 6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
10387 : GDALRasterAlgebraUnaryOperation eOp)
10388 : {
10389 6 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10390 6 : GDALComputedRasterBand::Operation cppOp{};
10391 6 : switch (eOp)
10392 : {
10393 2 : case GRAUO_LOGICAL_NOT:
10394 : return new GDALComputedRasterBand(
10395 : GDALComputedRasterBand::Operation::OP_NE,
10396 2 : *(GDALRasterBand::FromHandle(hBand)), true);
10397 1 : case GRAUO_ABS:
10398 1 : cppOp = GDALComputedRasterBand::Operation::OP_ABS;
10399 1 : break;
10400 1 : case GRAUO_SQRT:
10401 1 : cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
10402 1 : break;
10403 1 : case GRAUO_LOG:
10404 : #ifndef HAVE_MUPARSER
10405 : CPLError(
10406 : CE_Failure, CPLE_NotSupported,
10407 : "log(band) not available on a GDAL build without muparser");
10408 : return nullptr;
10409 : #else
10410 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG;
10411 1 : break;
10412 : #endif
10413 1 : case GRAUO_LOG10:
10414 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
10415 1 : break;
10416 : }
10417 : return new GDALComputedRasterBand(cppOp,
10418 4 : *(GDALRasterBand::FromHandle(hBand)));
10419 : }
10420 :
10421 : /************************************************************************/
10422 : /* ConvertGDALRasterAlgebraBinaryOperationToCpp() */
10423 : /************************************************************************/
10424 :
10425 : static GDALComputedRasterBand::Operation
10426 120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
10427 : GDALRasterAlgebraBinaryOperation eOp)
10428 : {
10429 120 : switch (eOp)
10430 : {
10431 26 : case GRABO_ADD:
10432 26 : return GDALComputedRasterBand::Operation::OP_ADD;
10433 2 : case GRABO_SUB:
10434 2 : return GDALComputedRasterBand::Operation::OP_SUBTRACT;
10435 24 : case GRABO_MUL:
10436 24 : return GDALComputedRasterBand::Operation::OP_MULTIPLY;
10437 3 : case GRABO_DIV:
10438 3 : return GDALComputedRasterBand::Operation::OP_DIVIDE;
10439 6 : case GRABO_GT:
10440 6 : return GDALComputedRasterBand::Operation::OP_GT;
10441 8 : case GRABO_GE:
10442 8 : return GDALComputedRasterBand::Operation::OP_GE;
10443 6 : case GRABO_LT:
10444 6 : return GDALComputedRasterBand::Operation::OP_LT;
10445 6 : case GRABO_LE:
10446 6 : return GDALComputedRasterBand::Operation::OP_LE;
10447 6 : case GRABO_EQ:
10448 6 : return GDALComputedRasterBand::Operation::OP_EQ;
10449 6 : case GRABO_NE:
10450 6 : break;
10451 12 : case GRABO_LOGICAL_AND:
10452 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
10453 12 : case GRABO_LOGICAL_OR:
10454 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
10455 3 : case GRABO_POW:
10456 3 : return GDALComputedRasterBand::Operation::OP_POW;
10457 : }
10458 6 : return GDALComputedRasterBand::Operation::OP_NE;
10459 : }
10460 :
10461 : /************************************************************************/
10462 : /* GDALRasterBandBinaryOpBand() */
10463 : /************************************************************************/
10464 :
10465 : /** Apply a binary operation on this band with another one.
10466 : *
10467 : * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
10468 : * "hBand1 - hBand2".
10469 : *
10470 : * The resulting band is lazy evaluated. A reference is taken on both input
10471 : * datasets.
10472 : *
10473 : * @since 3.12
10474 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10475 : */
10476 : GDALComputedRasterBandH
10477 57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
10478 : GDALRasterAlgebraBinaryOperation eOp,
10479 : GDALRasterBandH hOtherBand)
10480 : {
10481 57 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10482 57 : VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
10483 : #ifndef HAVE_MUPARSER
10484 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10485 : {
10486 : CPLError(
10487 : CE_Failure, CPLE_NotSupported,
10488 : "Band comparison operators not available on a GDAL build without "
10489 : "muparser");
10490 : return nullptr;
10491 : }
10492 : else if (eOp == GRABO_POW)
10493 : {
10494 : CPLError(
10495 : CE_Failure, CPLE_NotSupported,
10496 : "pow(band, band) not available on a GDAL build without muparser");
10497 : return nullptr;
10498 : }
10499 : #endif
10500 57 : auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
10501 57 : auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
10502 : try
10503 : {
10504 57 : GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
10505 : }
10506 13 : catch (const std::exception &e)
10507 : {
10508 13 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
10509 13 : return nullptr;
10510 : }
10511 : return new GDALComputedRasterBand(
10512 44 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
10513 44 : secondBand);
10514 : }
10515 :
10516 : /************************************************************************/
10517 : /* GDALRasterBandBinaryOpDouble() */
10518 : /************************************************************************/
10519 :
10520 : /** Apply a binary operation on this band with a constant
10521 : *
10522 : * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
10523 : * "hBand - constant".
10524 : *
10525 : * The resulting band is lazy evaluated. A reference is taken on the input
10526 : * dataset.
10527 : *
10528 : * @since 3.12
10529 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10530 : */
10531 : GDALComputedRasterBandH
10532 59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
10533 : GDALRasterAlgebraBinaryOperation eOp,
10534 : double constant)
10535 : {
10536 59 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10537 : #ifndef HAVE_MUPARSER
10538 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10539 : {
10540 : CPLError(
10541 : CE_Failure, CPLE_NotSupported,
10542 : "Band comparison operators not available on a GDAL build without "
10543 : "muparser");
10544 : return nullptr;
10545 : }
10546 : #endif
10547 : return new GDALComputedRasterBand(
10548 59 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
10549 59 : *(GDALRasterBand::FromHandle(hBand)), constant);
10550 : }
10551 :
10552 : /************************************************************************/
10553 : /* GDALRasterBandBinaryOpDoubleToBand() */
10554 : /************************************************************************/
10555 :
10556 : /** Apply a binary operation on the constant with this band
10557 : *
10558 : * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
10559 : * "constant - hBand".
10560 : *
10561 : * The resulting band is lazy evaluated. A reference is taken on the input
10562 : * dataset.
10563 : *
10564 : * @since 3.12
10565 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10566 : */
10567 : GDALComputedRasterBandH
10568 18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
10569 : GDALRasterAlgebraBinaryOperation eOp,
10570 : GDALRasterBandH hBand)
10571 : {
10572 18 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10573 : #ifndef HAVE_MUPARSER
10574 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10575 : {
10576 : CPLError(
10577 : CE_Failure, CPLE_NotSupported,
10578 : "Band comparison operators not available on a GDAL build without "
10579 : "muparser");
10580 : return nullptr;
10581 : }
10582 : #endif
10583 18 : switch (eOp)
10584 : {
10585 15 : case GRABO_ADD:
10586 : case GRABO_MUL:
10587 : {
10588 : return new GDALComputedRasterBand(
10589 15 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
10590 15 : *(GDALRasterBand::FromHandle(hBand)), constant);
10591 : }
10592 :
10593 2 : case GRABO_DIV:
10594 : case GRABO_GT:
10595 : case GRABO_GE:
10596 : case GRABO_LT:
10597 : case GRABO_LE:
10598 : case GRABO_EQ:
10599 : case GRABO_NE:
10600 : case GRABO_LOGICAL_AND:
10601 : case GRABO_LOGICAL_OR:
10602 : case GRABO_POW:
10603 : {
10604 : return new GDALComputedRasterBand(
10605 2 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
10606 2 : *(GDALRasterBand::FromHandle(hBand)));
10607 : }
10608 :
10609 1 : case GRABO_SUB:
10610 : {
10611 1 : break;
10612 : }
10613 : }
10614 :
10615 : return new GDALComputedRasterBand(
10616 : GDALComputedRasterBand::Operation::OP_ADD,
10617 2 : GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
10618 1 : *(GDALRasterBand::FromHandle(hBand)), -1.0),
10619 1 : constant);
10620 : }
10621 :
10622 : /************************************************************************/
10623 : /* operator+() */
10624 : /************************************************************************/
10625 :
10626 : /** Add this band with another one.
10627 : *
10628 : * The resulting band is lazy evaluated. A reference is taken on both input
10629 : * datasets.
10630 : *
10631 : * @since 3.12
10632 : * @throw std::runtime_error if both bands do not have the same dimensions.
10633 : */
10634 : GDALComputedRasterBand
10635 8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
10636 : {
10637 8 : ThrowIfNotSameDimensions(*this, other);
10638 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
10639 7 : *this, other);
10640 : }
10641 :
10642 : /************************************************************************/
10643 : /* operator+() */
10644 : /************************************************************************/
10645 :
10646 : /** Add this band with a constant.
10647 : *
10648 : * The resulting band is lazy evaluated. A reference is taken on the input
10649 : * dataset.
10650 : *
10651 : * @since 3.12
10652 : */
10653 13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
10654 : {
10655 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
10656 13 : *this, constant);
10657 : }
10658 :
10659 : /************************************************************************/
10660 : /* operator+() */
10661 : /************************************************************************/
10662 :
10663 : /** Add a band with a constant.
10664 : *
10665 : * The resulting band is lazy evaluated. A reference is taken on the input
10666 : * dataset.
10667 : *
10668 : * @since 3.12
10669 : */
10670 1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
10671 : {
10672 1 : return other + constant;
10673 : }
10674 :
10675 : /************************************************************************/
10676 : /* operator-() */
10677 : /************************************************************************/
10678 :
10679 : /** Return a band whose value is the opposite value of the band for each
10680 : * pixel.
10681 : *
10682 : * The resulting band is lazy evaluated. A reference is taken on the input
10683 : * dataset.
10684 : *
10685 : * @since 3.12
10686 : */
10687 2 : GDALComputedRasterBand GDALRasterBand::operator-() const
10688 : {
10689 2 : return 0 - *this;
10690 : }
10691 :
10692 : /************************************************************************/
10693 : /* operator-() */
10694 : /************************************************************************/
10695 :
10696 : /** Subtract this band with another one.
10697 : *
10698 : * The resulting band is lazy evaluated. A reference is taken on both input
10699 : * datasets.
10700 : *
10701 : * @since 3.12
10702 : * @throw std::runtime_error if both bands do not have the same dimensions.
10703 : */
10704 : GDALComputedRasterBand
10705 2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
10706 : {
10707 2 : ThrowIfNotSameDimensions(*this, other);
10708 : return GDALComputedRasterBand(
10709 2 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
10710 : }
10711 :
10712 : /************************************************************************/
10713 : /* operator-() */
10714 : /************************************************************************/
10715 :
10716 : /** Subtract this band with a constant.
10717 : *
10718 : * The resulting band is lazy evaluated. A reference is taken on the input
10719 : * dataset.
10720 : *
10721 : * @since 3.12
10722 : */
10723 1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
10724 : {
10725 : return GDALComputedRasterBand(
10726 1 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
10727 : }
10728 :
10729 : /************************************************************************/
10730 : /* operator-() */
10731 : /************************************************************************/
10732 :
10733 : /** Subtract a constant with a band.
10734 : *
10735 : * The resulting band is lazy evaluated. A reference is taken on the input
10736 : * dataset.
10737 : *
10738 : * @since 3.12
10739 : */
10740 3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
10741 : {
10742 6 : return other * (-1.0) + constant;
10743 : }
10744 :
10745 : /************************************************************************/
10746 : /* operator*() */
10747 : /************************************************************************/
10748 :
10749 : /** Multiply this band with another one.
10750 : *
10751 : * The resulting band is lazy evaluated. A reference is taken on both input
10752 : * datasets.
10753 : *
10754 : * @since 3.12
10755 : * @throw std::runtime_error if both bands do not have the same dimensions.
10756 : */
10757 : GDALComputedRasterBand
10758 2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
10759 : {
10760 2 : ThrowIfNotSameDimensions(*this, other);
10761 : return GDALComputedRasterBand(
10762 2 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
10763 : }
10764 :
10765 : /************************************************************************/
10766 : /* operator*() */
10767 : /************************************************************************/
10768 :
10769 : /** Multiply this band by a constant.
10770 : *
10771 : * The resulting band is lazy evaluated. A reference is taken on the input
10772 : * dataset.
10773 : *
10774 : * @since 3.12
10775 : */
10776 14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
10777 : {
10778 : return GDALComputedRasterBand(
10779 14 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
10780 : }
10781 :
10782 : /************************************************************************/
10783 : /* operator*() */
10784 : /************************************************************************/
10785 :
10786 : /** Multiply a band with a constant.
10787 : *
10788 : * The resulting band is lazy evaluated. A reference is taken on the input
10789 : * dataset.
10790 : *
10791 : * @since 3.12
10792 : */
10793 2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
10794 : {
10795 2 : return other * constant;
10796 : }
10797 :
10798 : /************************************************************************/
10799 : /* operator/() */
10800 : /************************************************************************/
10801 :
10802 : /** Divide this band with another one.
10803 : *
10804 : * The resulting band is lazy evaluated. A reference is taken on both input
10805 : * datasets.
10806 : *
10807 : * @since 3.12
10808 : * @throw std::runtime_error if both bands do not have the same dimensions.
10809 : */
10810 : GDALComputedRasterBand
10811 2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
10812 : {
10813 2 : ThrowIfNotSameDimensions(*this, other);
10814 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10815 2 : *this, other);
10816 : }
10817 :
10818 : /************************************************************************/
10819 : /* operator/() */
10820 : /************************************************************************/
10821 :
10822 : /** Divide this band by a constant.
10823 : *
10824 : * The resulting band is lazy evaluated. A reference is taken on the input
10825 : * dataset.
10826 : *
10827 : * @since 3.12
10828 : */
10829 0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
10830 : {
10831 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10832 0 : *this, constant);
10833 : }
10834 :
10835 : /************************************************************************/
10836 : /* operator/() */
10837 : /************************************************************************/
10838 :
10839 : /** Divide a constant by a band.
10840 : *
10841 : * The resulting band is lazy evaluated. A reference is taken on the input
10842 : * dataset.
10843 : *
10844 : * @since 3.12
10845 : */
10846 1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
10847 : {
10848 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10849 1 : constant, other);
10850 : }
10851 :
10852 : /************************************************************************/
10853 : /* ThrowIfNotMuparser() */
10854 : /************************************************************************/
10855 :
10856 : #ifndef HAVE_MUPARSER
10857 : static GDALComputedRasterBand ThrowIfNotMuparser()
10858 : {
10859 : throw std::runtime_error("Operator not available on a "
10860 : "GDAL build without muparser");
10861 : }
10862 : #endif
10863 :
10864 : /************************************************************************/
10865 : /* operator>() */
10866 : /************************************************************************/
10867 :
10868 : /** Return a band whose value is 1 if the pixel value of the left operand
10869 : * is greater than the pixel value of the right operand.
10870 : *
10871 : * The resulting band is lazy evaluated. A reference is taken on the input
10872 : * dataset.
10873 : *
10874 : * @since 3.12
10875 : */
10876 : GDALComputedRasterBand
10877 3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
10878 : {
10879 : #ifndef HAVE_MUPARSER
10880 : (void)other;
10881 : return ThrowIfNotMuparser();
10882 : #else
10883 3 : ThrowIfNotSameDimensions(*this, other);
10884 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10885 2 : *this, other);
10886 : #endif
10887 : }
10888 :
10889 : /************************************************************************/
10890 : /* operator>() */
10891 : /************************************************************************/
10892 :
10893 : /** Return a band whose value is 1 if the pixel value of the left operand
10894 : * is greater than the constant.
10895 : *
10896 : * The resulting band is lazy evaluated. A reference is taken on the input
10897 : * dataset.
10898 : *
10899 : * @since 3.12
10900 : */
10901 3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
10902 : {
10903 : #ifndef HAVE_MUPARSER
10904 : (void)constant;
10905 : return ThrowIfNotMuparser();
10906 : #else
10907 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10908 3 : *this, constant);
10909 : #endif
10910 : }
10911 :
10912 : /************************************************************************/
10913 : /* operator>() */
10914 : /************************************************************************/
10915 :
10916 : /** Return a band whose value is 1 if the constant is greater than the pixel
10917 : * value of the right operand.
10918 : *
10919 : * The resulting band is lazy evaluated. A reference is taken on the input
10920 : * dataset.
10921 : *
10922 : * @since 3.12
10923 : */
10924 2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
10925 : {
10926 : #ifndef HAVE_MUPARSER
10927 : (void)constant;
10928 : (void)other;
10929 : return ThrowIfNotMuparser();
10930 : #else
10931 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10932 2 : constant, other);
10933 : #endif
10934 : }
10935 :
10936 : /************************************************************************/
10937 : /* operator>=() */
10938 : /************************************************************************/
10939 :
10940 : /** Return a band whose value is 1 if the pixel value of the left operand
10941 : * is greater or equal to the pixel value of the right operand.
10942 : *
10943 : * The resulting band is lazy evaluated. A reference is taken on the input
10944 : * dataset.
10945 : *
10946 : * @since 3.12
10947 : */
10948 : GDALComputedRasterBand
10949 4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
10950 : {
10951 : #ifndef HAVE_MUPARSER
10952 : (void)other;
10953 : return ThrowIfNotMuparser();
10954 : #else
10955 4 : ThrowIfNotSameDimensions(*this, other);
10956 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10957 3 : *this, other);
10958 : #endif
10959 : }
10960 :
10961 : /************************************************************************/
10962 : /* operator>=() */
10963 : /************************************************************************/
10964 :
10965 : /** Return a band whose value is 1 if the pixel value of the left operand
10966 : * is greater or equal to the constant.
10967 : *
10968 : * The resulting band is lazy evaluated. A reference is taken on the input
10969 : * dataset.
10970 : *
10971 : * @since 3.12
10972 : */
10973 3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
10974 : {
10975 : #ifndef HAVE_MUPARSER
10976 : (void)constant;
10977 : return ThrowIfNotMuparser();
10978 : #else
10979 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10980 3 : *this, constant);
10981 : #endif
10982 : }
10983 :
10984 : /************************************************************************/
10985 : /* operator>=() */
10986 : /************************************************************************/
10987 :
10988 : /** Return a band whose value is 1 if the constant is greater or equal to
10989 : * the pixel value of the right operand.
10990 : *
10991 : * The resulting band is lazy evaluated. A reference is taken on the input
10992 : * dataset.
10993 : *
10994 : * @since 3.12
10995 : */
10996 2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
10997 : {
10998 : #ifndef HAVE_MUPARSER
10999 : (void)constant;
11000 : (void)other;
11001 : return ThrowIfNotMuparser();
11002 : #else
11003 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11004 2 : constant, other);
11005 : #endif
11006 : }
11007 :
11008 : /************************************************************************/
11009 : /* operator<() */
11010 : /************************************************************************/
11011 :
11012 : /** Return a band whose value is 1 if the pixel value of the left operand
11013 : * is lesser than the pixel value of the right operand.
11014 : *
11015 : * The resulting band is lazy evaluated. A reference is taken on the input
11016 : * dataset.
11017 : *
11018 : * @since 3.12
11019 : */
11020 : GDALComputedRasterBand
11021 3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
11022 : {
11023 : #ifndef HAVE_MUPARSER
11024 : (void)other;
11025 : return ThrowIfNotMuparser();
11026 : #else
11027 3 : ThrowIfNotSameDimensions(*this, other);
11028 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11029 2 : *this, other);
11030 : #endif
11031 : }
11032 :
11033 : /************************************************************************/
11034 : /* operator<() */
11035 : /************************************************************************/
11036 :
11037 : /** Return a band whose value is 1 if the pixel value of the left operand
11038 : * is lesser than the constant.
11039 : *
11040 : * The resulting band is lazy evaluated. A reference is taken on the input
11041 : * dataset.
11042 : *
11043 : * @since 3.12
11044 : */
11045 3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
11046 : {
11047 : #ifndef HAVE_MUPARSER
11048 : (void)constant;
11049 : return ThrowIfNotMuparser();
11050 : #else
11051 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11052 3 : *this, constant);
11053 : #endif
11054 : }
11055 :
11056 : /************************************************************************/
11057 : /* operator<() */
11058 : /************************************************************************/
11059 :
11060 : /** Return a band whose value is 1 if the constant is lesser than the pixel
11061 : * value of the right operand.
11062 : *
11063 : * The resulting band is lazy evaluated. A reference is taken on the input
11064 : * dataset.
11065 : *
11066 : * @since 3.12
11067 : */
11068 2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
11069 : {
11070 : #ifndef HAVE_MUPARSER
11071 : (void)constant;
11072 : (void)other;
11073 : return ThrowIfNotMuparser();
11074 : #else
11075 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11076 2 : constant, other);
11077 : #endif
11078 : }
11079 :
11080 : /************************************************************************/
11081 : /* operator<=() */
11082 : /************************************************************************/
11083 :
11084 : /** Return a band whose value is 1 if the pixel value of the left operand
11085 : * is lesser or equal to the pixel value of the right operand.
11086 : *
11087 : * The resulting band is lazy evaluated. A reference is taken on the input
11088 : * dataset.
11089 : *
11090 : * @since 3.12
11091 : */
11092 : GDALComputedRasterBand
11093 4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
11094 : {
11095 : #ifndef HAVE_MUPARSER
11096 : (void)other;
11097 : return ThrowIfNotMuparser();
11098 : #else
11099 4 : ThrowIfNotSameDimensions(*this, other);
11100 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11101 3 : *this, other);
11102 : #endif
11103 : }
11104 :
11105 : /************************************************************************/
11106 : /* operator<=() */
11107 : /************************************************************************/
11108 :
11109 : /** Return a band whose value is 1 if the pixel value of the left operand
11110 : * is lesser or equal to the constant.
11111 : *
11112 : * The resulting band is lazy evaluated. A reference is taken on the input
11113 : * dataset.
11114 : *
11115 : * @since 3.12
11116 : */
11117 3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
11118 : {
11119 : #ifndef HAVE_MUPARSER
11120 : (void)constant;
11121 : return ThrowIfNotMuparser();
11122 : #else
11123 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11124 3 : *this, constant);
11125 : #endif
11126 : }
11127 :
11128 : /************************************************************************/
11129 : /* operator<=() */
11130 : /************************************************************************/
11131 :
11132 : /** Return a band whose value is 1 if the constant is lesser or equal to
11133 : * the pixel value of the right operand.
11134 : *
11135 : * The resulting band is lazy evaluated. A reference is taken on the input
11136 : * dataset.
11137 : *
11138 : * @since 3.12
11139 : */
11140 2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
11141 : {
11142 : #ifndef HAVE_MUPARSER
11143 : (void)constant;
11144 : (void)other;
11145 : return ThrowIfNotMuparser();
11146 : #else
11147 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11148 2 : constant, other);
11149 : #endif
11150 : }
11151 :
11152 : /************************************************************************/
11153 : /* operator==() */
11154 : /************************************************************************/
11155 :
11156 : /** Return a band whose value is 1 if the pixel value of the left operand
11157 : * is equal to the pixel value of the right operand.
11158 : *
11159 : * The resulting band is lazy evaluated. A reference is taken on the input
11160 : * dataset.
11161 : *
11162 : * @since 3.12
11163 : */
11164 : GDALComputedRasterBand
11165 3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
11166 : {
11167 : #ifndef HAVE_MUPARSER
11168 : (void)other;
11169 : return ThrowIfNotMuparser();
11170 : #else
11171 3 : ThrowIfNotSameDimensions(*this, other);
11172 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11173 2 : *this, other);
11174 : #endif
11175 : }
11176 :
11177 : /************************************************************************/
11178 : /* operator==() */
11179 : /************************************************************************/
11180 :
11181 : /** Return a band whose value is 1 if the pixel value of the left operand
11182 : * is equal to the constant.
11183 : *
11184 : * The resulting band is lazy evaluated. A reference is taken on the input
11185 : * dataset.
11186 : *
11187 : * @since 3.12
11188 : */
11189 8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
11190 : {
11191 : #ifndef HAVE_MUPARSER
11192 : (void)constant;
11193 : return ThrowIfNotMuparser();
11194 : #else
11195 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11196 8 : *this, constant);
11197 : #endif
11198 : }
11199 :
11200 : /************************************************************************/
11201 : /* operator==() */
11202 : /************************************************************************/
11203 :
11204 : /** Return a band whose value is 1 if the constant is equal to
11205 : * the pixel value of the right operand.
11206 : *
11207 : * The resulting band is lazy evaluated. A reference is taken on the input
11208 : * dataset.
11209 : *
11210 : * @since 3.12
11211 : */
11212 2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
11213 : {
11214 : #ifndef HAVE_MUPARSER
11215 : (void)constant;
11216 : (void)other;
11217 : return ThrowIfNotMuparser();
11218 : #else
11219 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11220 2 : constant, other);
11221 : #endif
11222 : }
11223 :
11224 : /************************************************************************/
11225 : /* operator!=() */
11226 : /************************************************************************/
11227 :
11228 : /** Return a band whose value is 1 if the pixel value of the left operand
11229 : * is different from the pixel value of the right operand.
11230 : *
11231 : * The resulting band is lazy evaluated. A reference is taken on the input
11232 : * dataset.
11233 : *
11234 : * @since 3.12
11235 : */
11236 : GDALComputedRasterBand
11237 3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
11238 : {
11239 : #ifndef HAVE_MUPARSER
11240 : (void)other;
11241 : return ThrowIfNotMuparser();
11242 : #else
11243 3 : ThrowIfNotSameDimensions(*this, other);
11244 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11245 2 : *this, other);
11246 : #endif
11247 : }
11248 :
11249 : /************************************************************************/
11250 : /* operator!=() */
11251 : /************************************************************************/
11252 :
11253 : /** Return a band whose value is 1 if the pixel value of the left operand
11254 : * is different from the constant.
11255 : *
11256 : * The resulting band is lazy evaluated. A reference is taken on the input
11257 : * dataset.
11258 : *
11259 : * @since 3.12
11260 : */
11261 6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
11262 : {
11263 : #ifndef HAVE_MUPARSER
11264 : (void)constant;
11265 : return ThrowIfNotMuparser();
11266 : #else
11267 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11268 6 : *this, constant);
11269 : #endif
11270 : }
11271 :
11272 : /************************************************************************/
11273 : /* operator!=() */
11274 : /************************************************************************/
11275 :
11276 : /** Return a band whose value is 1 if the constant is different from
11277 : * the pixel value of the right operand.
11278 : *
11279 : * The resulting band is lazy evaluated. A reference is taken on the input
11280 : * dataset.
11281 : *
11282 : * @since 3.12
11283 : */
11284 2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
11285 : {
11286 : #ifndef HAVE_MUPARSER
11287 : (void)constant;
11288 : (void)other;
11289 : return ThrowIfNotMuparser();
11290 : #else
11291 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11292 2 : constant, other);
11293 : #endif
11294 : }
11295 :
11296 : #if defined(__GNUC__)
11297 : #pragma GCC diagnostic push
11298 : #pragma GCC diagnostic ignored "-Weffc++"
11299 : #endif
11300 :
11301 : /************************************************************************/
11302 : /* operator&&() */
11303 : /************************************************************************/
11304 :
11305 : /** Return a band whose value is 1 if the pixel value of the left and right
11306 : * operands is true.
11307 : *
11308 : * The resulting band is lazy evaluated. A reference is taken on the input
11309 : * dataset.
11310 : *
11311 : * @since 3.12
11312 : */
11313 : GDALComputedRasterBand
11314 3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
11315 : {
11316 : #ifndef HAVE_MUPARSER
11317 : (void)other;
11318 : return ThrowIfNotMuparser();
11319 : #else
11320 3 : ThrowIfNotSameDimensions(*this, other);
11321 : return GDALComputedRasterBand(
11322 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
11323 : #endif
11324 : }
11325 :
11326 : /************************************************************************/
11327 : /* operator&&() */
11328 : /************************************************************************/
11329 :
11330 : /** Return a band whose value is 1 if the pixel value of the left operand
11331 : * is true, as well as the constant
11332 : *
11333 : * The resulting band is lazy evaluated. A reference is taken on the input
11334 : * dataset.
11335 : *
11336 : * @since 3.12
11337 : */
11338 2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
11339 : {
11340 : #ifndef HAVE_MUPARSER
11341 : (void)constant;
11342 : return ThrowIfNotMuparser();
11343 : #else
11344 : return GDALComputedRasterBand(
11345 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
11346 : #endif
11347 : }
11348 :
11349 : /************************************************************************/
11350 : /* operator&&() */
11351 : /************************************************************************/
11352 :
11353 : /** Return a band whose value is 1 if the constant is true, as well as
11354 : * the pixel value of the right operand.
11355 : *
11356 : * The resulting band is lazy evaluated. A reference is taken on the input
11357 : * dataset.
11358 : *
11359 : * @since 3.12
11360 : */
11361 2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
11362 : {
11363 : #ifndef HAVE_MUPARSER
11364 : (void)constant;
11365 : (void)other;
11366 : return ThrowIfNotMuparser();
11367 : #else
11368 : return GDALComputedRasterBand(
11369 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
11370 : #endif
11371 : }
11372 :
11373 : /************************************************************************/
11374 : /* operator||() */
11375 : /************************************************************************/
11376 :
11377 : /** Return a band whose value is 1 if the pixel value of the left or right
11378 : * operands is true.
11379 : *
11380 : * The resulting band is lazy evaluated. A reference is taken on the input
11381 : * dataset.
11382 : *
11383 : * @since 3.12
11384 : */
11385 : GDALComputedRasterBand
11386 4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
11387 : {
11388 : #ifndef HAVE_MUPARSER
11389 : (void)other;
11390 : return ThrowIfNotMuparser();
11391 : #else
11392 4 : ThrowIfNotSameDimensions(*this, other);
11393 : return GDALComputedRasterBand(
11394 3 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
11395 : #endif
11396 : }
11397 :
11398 : /************************************************************************/
11399 : /* operator||() */
11400 : /************************************************************************/
11401 :
11402 : /** Return a band whose value is 1 if the pixel value of the left operand
11403 : * is true, or if the constant is true
11404 : *
11405 : * The resulting band is lazy evaluated. A reference is taken on the input
11406 : * dataset.
11407 : *
11408 : * @since 3.12
11409 : */
11410 4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
11411 : {
11412 : #ifndef HAVE_MUPARSER
11413 : (void)constant;
11414 : return ThrowIfNotMuparser();
11415 : #else
11416 : return GDALComputedRasterBand(
11417 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
11418 : #endif
11419 : }
11420 :
11421 : /************************************************************************/
11422 : /* operator||() */
11423 : /************************************************************************/
11424 :
11425 : /** Return a band whose value is 1 if the constant is true, or
11426 : * the pixel value of the right operand is true
11427 : *
11428 : * The resulting band is lazy evaluated. A reference is taken on the input
11429 : * dataset.
11430 : *
11431 : * @since 3.12
11432 : */
11433 4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
11434 : {
11435 : #ifndef HAVE_MUPARSER
11436 : (void)constant;
11437 : (void)other;
11438 : return ThrowIfNotMuparser();
11439 : #else
11440 : return GDALComputedRasterBand(
11441 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
11442 : #endif
11443 : }
11444 :
11445 : #if defined(__GNUC__)
11446 : #pragma GCC diagnostic pop
11447 : #endif
11448 :
11449 : /************************************************************************/
11450 : /* operator!() */
11451 : /************************************************************************/
11452 :
11453 : /** Return a band whose value is the logical negation of the pixel value
11454 : *
11455 : * The resulting band is lazy evaluated. A reference is taken on the input
11456 : * dataset.
11457 : *
11458 : * @since 3.12
11459 : */
11460 2 : GDALComputedRasterBand GDALRasterBand::operator!() const
11461 : {
11462 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11463 2 : *this, true);
11464 : }
11465 :
11466 : namespace gdal
11467 : {
11468 :
11469 : /************************************************************************/
11470 : /* IfThenElse() */
11471 : /************************************************************************/
11472 :
11473 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
11474 : * is not zero, or the one from elseBand otherwise.
11475 : *
11476 : * Variants of this method exits where thenBand and/or elseBand can be double
11477 : * values.
11478 : *
11479 : * The resulting band is lazy evaluated. A reference is taken on the input
11480 : * datasets.
11481 : *
11482 : * This method is the same as the C function GDALRasterBandIfThenElse()
11483 : *
11484 : * @since 3.12
11485 : */
11486 5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11487 : const GDALRasterBand &thenBand,
11488 : const GDALRasterBand &elseBand)
11489 : {
11490 : #ifndef HAVE_MUPARSER
11491 : (void)condBand;
11492 : (void)thenBand;
11493 : (void)elseBand;
11494 : return ThrowIfNotMuparser();
11495 : #else
11496 5 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11497 4 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11498 : return GDALComputedRasterBand(
11499 : GDALComputedRasterBand::Operation::OP_TERNARY,
11500 6 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11501 : #endif
11502 : }
11503 :
11504 : //! @cond Doxygen_Suppress
11505 :
11506 : /************************************************************************/
11507 : /* IfThenElse() */
11508 : /************************************************************************/
11509 :
11510 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
11511 : * is not zero, or the one from elseBand otherwise.
11512 : *
11513 : * The resulting band is lazy evaluated. A reference is taken on the input
11514 : * datasets.
11515 : *
11516 : * This method is the same as the C function GDALRasterBandIfThenElse(),
11517 : * with thenBand = (condBand * 0) + thenValue
11518 : *
11519 : * @since 3.12
11520 : */
11521 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11522 : double thenValue,
11523 : const GDALRasterBand &elseBand)
11524 : {
11525 : #ifndef HAVE_MUPARSER
11526 : (void)condBand;
11527 : (void)thenValue;
11528 : (void)elseBand;
11529 : return ThrowIfNotMuparser();
11530 : #else
11531 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11532 : auto thenBand =
11533 1 : (condBand * 0)
11534 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
11535 1 : thenValue;
11536 : return GDALComputedRasterBand(
11537 : GDALComputedRasterBand::Operation::OP_TERNARY,
11538 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11539 : #endif
11540 : }
11541 :
11542 : /************************************************************************/
11543 : /* IfThenElse() */
11544 : /************************************************************************/
11545 :
11546 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
11547 : * is not zero, or the one from elseValue otherwise.
11548 : *
11549 : * The resulting band is lazy evaluated. A reference is taken on the input
11550 : * datasets.
11551 : *
11552 : * This method is the same as the C function GDALRasterBandIfThenElse(),
11553 : * with elseBand = (condBand * 0) + elseValue
11554 :
11555 : * @since 3.12
11556 : */
11557 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11558 : const GDALRasterBand &thenBand,
11559 : double elseValue)
11560 : {
11561 : #ifndef HAVE_MUPARSER
11562 : (void)condBand;
11563 : (void)thenBand;
11564 : (void)elseValue;
11565 : return ThrowIfNotMuparser();
11566 : #else
11567 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11568 : auto elseBand =
11569 1 : (condBand * 0)
11570 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
11571 1 : elseValue;
11572 : return GDALComputedRasterBand(
11573 : GDALComputedRasterBand::Operation::OP_TERNARY,
11574 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11575 : #endif
11576 : }
11577 :
11578 : /************************************************************************/
11579 : /* IfThenElse() */
11580 : /************************************************************************/
11581 :
11582 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
11583 : * is not zero, or the one from elseValue otherwise.
11584 : *
11585 : * The resulting band is lazy evaluated. A reference is taken on the input
11586 : * datasets.
11587 : *
11588 : * This method is the same as the C function GDALRasterBandIfThenElse(),
11589 : * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
11590 : *
11591 : * @since 3.12
11592 : */
11593 3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11594 : double thenValue, double elseValue)
11595 : {
11596 : #ifndef HAVE_MUPARSER
11597 : (void)condBand;
11598 : (void)thenValue;
11599 : (void)elseValue;
11600 : return ThrowIfNotMuparser();
11601 : #else
11602 : auto thenBand =
11603 3 : (condBand * 0)
11604 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
11605 6 : thenValue;
11606 : auto elseBand =
11607 3 : (condBand * 0)
11608 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
11609 3 : elseValue;
11610 : return GDALComputedRasterBand(
11611 : GDALComputedRasterBand::Operation::OP_TERNARY,
11612 9 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11613 : #endif
11614 : }
11615 :
11616 : //! @endcond
11617 :
11618 : } // namespace gdal
11619 :
11620 : /************************************************************************/
11621 : /* GDALRasterBandIfThenElse() */
11622 : /************************************************************************/
11623 :
11624 : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
11625 : * is not zero, or the one from hElseBand otherwise.
11626 : *
11627 : * The resulting band is lazy evaluated. A reference is taken on the input
11628 : * datasets.
11629 : *
11630 : * This function is the same as the C++ method gdal::IfThenElse()
11631 : *
11632 : * @since 3.12
11633 : */
11634 12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
11635 : GDALRasterBandH hThenBand,
11636 : GDALRasterBandH hElseBand)
11637 : {
11638 12 : VALIDATE_POINTER1(hCondBand, __func__, nullptr);
11639 12 : VALIDATE_POINTER1(hThenBand, __func__, nullptr);
11640 12 : VALIDATE_POINTER1(hElseBand, __func__, nullptr);
11641 : #ifndef HAVE_MUPARSER
11642 : CPLError(CE_Failure, CPLE_NotSupported,
11643 : "Band comparison operators not available on a GDAL build without "
11644 : "muparser");
11645 : return nullptr;
11646 : #else
11647 :
11648 12 : auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
11649 12 : auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
11650 12 : auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
11651 : try
11652 : {
11653 12 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11654 11 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11655 : }
11656 2 : catch (const std::exception &e)
11657 : {
11658 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11659 2 : return nullptr;
11660 : }
11661 : return new GDALComputedRasterBand(
11662 : GDALComputedRasterBand::Operation::OP_TERNARY,
11663 10 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11664 : #endif
11665 : }
11666 :
11667 : /************************************************************************/
11668 : /* GDALRasterBand::AsType() */
11669 : /************************************************************************/
11670 :
11671 : /** Cast this band to another type.
11672 : *
11673 : * The resulting band is lazy evaluated. A reference is taken on the input
11674 : * dataset.
11675 : *
11676 : * This method is the same as the C function GDALRasterBandAsDataType()
11677 : *
11678 : * @since 3.12
11679 : */
11680 10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
11681 : {
11682 10 : if (dt == GDT_Unknown)
11683 : {
11684 1 : throw std::runtime_error("AsType(GDT_Unknown) is not supported");
11685 : }
11686 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
11687 9 : *this, dt);
11688 : }
11689 :
11690 : /************************************************************************/
11691 : /* GDALRasterBandAsDataType() */
11692 : /************************************************************************/
11693 :
11694 : /** Cast this band to another type.
11695 : *
11696 : * The resulting band is lazy evaluated. A reference is taken on the input
11697 : * dataset.
11698 : *
11699 : * This function is the same as the C++ method GDALRasterBand::AsType()
11700 : *
11701 : * @since 3.12
11702 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11703 : */
11704 16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
11705 : GDALDataType eDT)
11706 : {
11707 16 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11708 16 : if (eDT == GDT_Unknown)
11709 : {
11710 1 : CPLError(CE_Failure, CPLE_NotSupported,
11711 : "GDALRasterBandAsDataType(GDT_Unknown) not supported");
11712 1 : return nullptr;
11713 : }
11714 : return new GDALComputedRasterBand(
11715 : GDALComputedRasterBand::Operation::OP_CAST,
11716 15 : *(GDALRasterBand::FromHandle(hBand)), eDT);
11717 : }
11718 :
11719 : /************************************************************************/
11720 : /* GetBandVector() */
11721 : /************************************************************************/
11722 :
11723 : static std::vector<const GDALRasterBand *>
11724 10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
11725 : {
11726 10 : std::vector<const GDALRasterBand *> bands;
11727 27 : for (size_t i = 0; i < nBandCount; ++i)
11728 : {
11729 20 : if (i > 0)
11730 : {
11731 10 : GDALRasterBand::ThrowIfNotSameDimensions(
11732 10 : *(GDALRasterBand::FromHandle(pahBands[0])),
11733 10 : *(GDALRasterBand::FromHandle(pahBands[i])));
11734 : }
11735 17 : bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
11736 : }
11737 7 : return bands;
11738 : }
11739 :
11740 : /************************************************************************/
11741 : /* GDALOperationOnNBands() */
11742 : /************************************************************************/
11743 :
11744 : static GDALComputedRasterBandH
11745 11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
11746 : GDALRasterBandH *pahBands)
11747 : {
11748 11 : VALIDATE_POINTER1(pahBands, __func__, nullptr);
11749 11 : if (nBandCount == 0)
11750 : {
11751 1 : CPLError(CE_Failure, CPLE_AppDefined,
11752 : "At least one band should be passed");
11753 1 : return nullptr;
11754 : }
11755 :
11756 20 : std::vector<const GDALRasterBand *> bands;
11757 : try
11758 : {
11759 10 : bands = GetBandVector(nBandCount, pahBands);
11760 : }
11761 3 : catch (const std::exception &e)
11762 : {
11763 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11764 3 : return nullptr;
11765 : }
11766 7 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
11767 : }
11768 :
11769 : /************************************************************************/
11770 : /* GDALMaximumOfNBands() */
11771 : /************************************************************************/
11772 :
11773 : /** Return a band whose each pixel value is the maximum of the corresponding
11774 : * pixel values in the input bands.
11775 : *
11776 : * The resulting band is lazy evaluated. A reference is taken on input
11777 : * datasets.
11778 : *
11779 : * This function is the same as the C ++ method gdal::max()
11780 : *
11781 : * @since 3.12
11782 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11783 : */
11784 4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
11785 : GDALRasterBandH *pahBands)
11786 : {
11787 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
11788 4 : nBandCount, pahBands);
11789 : }
11790 :
11791 : /************************************************************************/
11792 : /* gdal::max() */
11793 : /************************************************************************/
11794 :
11795 : namespace gdal
11796 : {
11797 : /** Return a band whose each pixel value is the maximum of the corresponding
11798 : * pixel values in the inputs (bands or constants)
11799 : *
11800 : * The resulting band is lazy evaluated. A reference is taken on input
11801 : * datasets.
11802 : *
11803 : * Two or more bands can be passed.
11804 : *
11805 : * This method is the same as the C function GDALMaximumOfNBands()
11806 : *
11807 : * @since 3.12
11808 : * @throw std::runtime_error if bands do not have the same dimensions.
11809 : */
11810 1 : GDALComputedRasterBand max(const GDALRasterBand &first,
11811 : const GDALRasterBand &second)
11812 : {
11813 1 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11814 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
11815 1 : first, second);
11816 : }
11817 : } // namespace gdal
11818 :
11819 : /************************************************************************/
11820 : /* GDALRasterBandMaxConstant() */
11821 : /************************************************************************/
11822 :
11823 : /** Return a band whose each pixel value is the maximum of the corresponding
11824 : * pixel values in the input band and the constant.
11825 : *
11826 : * The resulting band is lazy evaluated. A reference is taken on the input
11827 : * dataset.
11828 : *
11829 : * This function is the same as the C ++ method gdal::max()
11830 : *
11831 : * @since 3.12
11832 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11833 : */
11834 2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
11835 : double dfConstant)
11836 : {
11837 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
11838 : GDALComputedRasterBand::Operation::OP_MAX,
11839 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
11840 6 : dfConstant));
11841 : }
11842 :
11843 : /************************************************************************/
11844 : /* GDALMinimumOfNBands() */
11845 : /************************************************************************/
11846 :
11847 : /** Return a band whose each pixel value is the minimum of the corresponding
11848 : * pixel values in the input bands.
11849 : *
11850 : * The resulting band is lazy evaluated. A reference is taken on input
11851 : * datasets.
11852 : *
11853 : * This function is the same as the C ++ method gdal::min()
11854 : *
11855 : * @since 3.12
11856 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11857 : */
11858 4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
11859 : GDALRasterBandH *pahBands)
11860 : {
11861 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
11862 4 : nBandCount, pahBands);
11863 : }
11864 :
11865 : /************************************************************************/
11866 : /* gdal::min() */
11867 : /************************************************************************/
11868 :
11869 : namespace gdal
11870 : {
11871 : /** Return a band whose each pixel value is the minimum of the corresponding
11872 : * pixel values in the inputs (bands or constants)
11873 : *
11874 : * The resulting band is lazy evaluated. A reference is taken on input
11875 : * datasets.
11876 : *
11877 : * Two or more bands can be passed.
11878 : *
11879 : * This method is the same as the C function GDALMinimumOfNBands()
11880 : *
11881 : * @since 3.12
11882 : * @throw std::runtime_error if bands do not have the same dimensions.
11883 : */
11884 0 : GDALComputedRasterBand min(const GDALRasterBand &first,
11885 : const GDALRasterBand &second)
11886 : {
11887 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11888 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
11889 0 : first, second);
11890 : }
11891 : } // namespace gdal
11892 :
11893 : /************************************************************************/
11894 : /* GDALRasterBandMinConstant() */
11895 : /************************************************************************/
11896 :
11897 : /** Return a band whose each pixel value is the minimum of the corresponding
11898 : * pixel values in the input band and the constant.
11899 : *
11900 : * The resulting band is lazy evaluated. A reference is taken on the input
11901 : * dataset.
11902 : *
11903 : * This function is the same as the C ++ method gdal::min()
11904 : *
11905 : * @since 3.12
11906 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11907 : */
11908 2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
11909 : double dfConstant)
11910 : {
11911 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
11912 : GDALComputedRasterBand::Operation::OP_MIN,
11913 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
11914 6 : dfConstant));
11915 : }
11916 :
11917 : /************************************************************************/
11918 : /* GDALMeanOfNBands() */
11919 : /************************************************************************/
11920 :
11921 : /** Return a band whose each pixel value is the arithmetic mean of the
11922 : * corresponding pixel values in the input bands.
11923 : *
11924 : * The resulting band is lazy evaluated. A reference is taken on input
11925 : * datasets.
11926 : *
11927 : * This function is the same as the C ++ method gdal::mean()
11928 : *
11929 : * @since 3.12
11930 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11931 : */
11932 3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
11933 : GDALRasterBandH *pahBands)
11934 : {
11935 3 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
11936 3 : nBandCount, pahBands);
11937 : }
11938 :
11939 : /************************************************************************/
11940 : /* gdal::mean() */
11941 : /************************************************************************/
11942 :
11943 : namespace gdal
11944 : {
11945 :
11946 : /** Return a band whose each pixel value is the arithmetic mean of the
11947 : * corresponding pixel values in the input bands.
11948 : *
11949 : * The resulting band is lazy evaluated. A reference is taken on input
11950 : * datasets.
11951 : *
11952 : * Two or more bands can be passed.
11953 : *
11954 : * This method is the same as the C function GDALMeanOfNBands()
11955 : *
11956 : * @since 3.12
11957 : * @throw std::runtime_error if bands do not have the same dimensions.
11958 : */
11959 0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
11960 : const GDALRasterBand &second)
11961 : {
11962 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11963 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
11964 0 : first, second);
11965 : }
11966 : } // namespace gdal
11967 :
11968 : /************************************************************************/
11969 : /* gdal::abs() */
11970 : /************************************************************************/
11971 :
11972 : namespace gdal
11973 : {
11974 :
11975 : /** Return a band whose each pixel value is the absolute value (or module
11976 : * for complex data type) of the corresponding pixel value in the input band.
11977 : *
11978 : * The resulting band is lazy evaluated. A reference is taken on input
11979 : * datasets.
11980 : *
11981 : * @since 3.12
11982 : */
11983 1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
11984 : {
11985 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
11986 1 : band);
11987 : }
11988 : } // namespace gdal
11989 :
11990 : /************************************************************************/
11991 : /* gdal::fabs() */
11992 : /************************************************************************/
11993 :
11994 : namespace gdal
11995 : {
11996 :
11997 : /** Return a band whose each pixel value is the absolute value (or module
11998 : * for complex data type) of the corresponding pixel value in the input band.
11999 : *
12000 : * The resulting band is lazy evaluated. A reference is taken on input
12001 : * datasets.
12002 : *
12003 : * @since 3.12
12004 : */
12005 1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
12006 : {
12007 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12008 1 : band);
12009 : }
12010 : } // namespace gdal
12011 :
12012 : /************************************************************************/
12013 : /* gdal::sqrt() */
12014 : /************************************************************************/
12015 :
12016 : namespace gdal
12017 : {
12018 :
12019 : /** Return a band whose each pixel value is the square root of the
12020 : * corresponding pixel value in the input band.
12021 : *
12022 : * The resulting band is lazy evaluated. A reference is taken on input
12023 : * datasets.
12024 : *
12025 : * @since 3.12
12026 : */
12027 1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
12028 : {
12029 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
12030 1 : band);
12031 : }
12032 : } // namespace gdal
12033 :
12034 : /************************************************************************/
12035 : /* gdal::log() */
12036 : /************************************************************************/
12037 :
12038 : namespace gdal
12039 : {
12040 :
12041 : /** Return a band whose each pixel value is the natural logarithm of the
12042 : * corresponding pixel value in the input band.
12043 : *
12044 : * The resulting band is lazy evaluated. A reference is taken on input
12045 : * datasets.
12046 : *
12047 : * @since 3.12
12048 : */
12049 1 : GDALComputedRasterBand log(const GDALRasterBand &band)
12050 : {
12051 : #ifndef HAVE_MUPARSER
12052 : (void)band;
12053 : return ThrowIfNotMuparser();
12054 : #else
12055 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
12056 1 : band);
12057 : #endif
12058 : }
12059 : } // namespace gdal
12060 :
12061 : /************************************************************************/
12062 : /* gdal::log10() */
12063 : /************************************************************************/
12064 :
12065 : namespace gdal
12066 : {
12067 :
12068 : /** Return a band whose each pixel value is the logarithm base 10 of the
12069 : * corresponding pixel value in the input band.
12070 : *
12071 : * The resulting band is lazy evaluated. A reference is taken on input
12072 : * datasets.
12073 : *
12074 : * @since 3.12
12075 : */
12076 1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
12077 : {
12078 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
12079 1 : band);
12080 : }
12081 : } // namespace gdal
12082 :
12083 : /************************************************************************/
12084 : /* gdal::pow() */
12085 : /************************************************************************/
12086 :
12087 : namespace gdal
12088 : {
12089 :
12090 : #ifndef DOXYGEN_SKIP
12091 : /** Return a band whose each pixel value is the constant raised to the power of
12092 : * the corresponding pixel value in the input band.
12093 : *
12094 : * The resulting band is lazy evaluated. A reference is taken on input
12095 : * datasets.
12096 : *
12097 : * @since 3.12
12098 : */
12099 1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
12100 : {
12101 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12102 1 : constant, band);
12103 : }
12104 : #endif
12105 :
12106 : } // namespace gdal
12107 :
12108 : /************************************************************************/
12109 : /* gdal::pow() */
12110 : /************************************************************************/
12111 :
12112 : namespace gdal
12113 : {
12114 :
12115 : /** Return a band whose each pixel value is the the corresponding pixel value
12116 : * in the input band raised to the power of the constant.
12117 : *
12118 : * The resulting band is lazy evaluated. A reference is taken on input
12119 : * datasets.
12120 : *
12121 : * @since 3.12
12122 : */
12123 1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
12124 : {
12125 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12126 1 : band, constant);
12127 : }
12128 : } // namespace gdal
12129 :
12130 : /************************************************************************/
12131 : /* gdal::pow() */
12132 : /************************************************************************/
12133 :
12134 : namespace gdal
12135 : {
12136 :
12137 : #ifndef DOXYGEN_SKIP
12138 : /** Return a band whose each pixel value is the the corresponding pixel value
12139 : * in the input band1 raised to the power of the corresponding pixel value
12140 : * in the input band2
12141 : *
12142 : * The resulting band is lazy evaluated. A reference is taken on input
12143 : * datasets.
12144 : *
12145 : * @since 3.12
12146 : * @throw std::runtime_error if bands do not have the same dimensions.
12147 : */
12148 2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
12149 : const GDALRasterBand &band2)
12150 : {
12151 : #ifndef HAVE_MUPARSER
12152 : (void)band1;
12153 : (void)band2;
12154 : return ThrowIfNotMuparser();
12155 : #else
12156 2 : GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
12157 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12158 1 : band1, band2);
12159 : #endif
12160 : }
12161 : #endif
12162 : } // namespace gdal
|