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 <climits>
20 : #include <cmath>
21 : #include <cstdarg>
22 : #include <cstddef>
23 : #include <cstdio>
24 : #include <cstdlib>
25 : #include <cstring>
26 : #include <algorithm>
27 : #include <limits>
28 : #include <memory>
29 : #include <new>
30 : #include <type_traits>
31 :
32 : #include "cpl_conv.h"
33 : #include "cpl_error.h"
34 : #include "cpl_float.h"
35 : #include "cpl_progress.h"
36 : #include "cpl_string.h"
37 : #include "cpl_virtualmem.h"
38 : #include "cpl_vsi.h"
39 : #include "gdal.h"
40 : #include "gdal_rat.h"
41 : #include "gdal_priv_templates.hpp"
42 : #include "gdal_interpolateatpoint.h"
43 : #include "gdal_minmax_element.hpp"
44 :
45 : /************************************************************************/
46 : /* GDALRasterBand() */
47 : /************************************************************************/
48 :
49 : /*! Constructor. Applications should never create GDALRasterBands directly. */
50 :
51 1638880 : GDALRasterBand::GDALRasterBand()
52 : : GDALRasterBand(
53 1638880 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
54 : {
55 1638610 : }
56 :
57 : /** Constructor. Applications should never create GDALRasterBands directly.
58 : * @param bForceCachedIOIn Whether cached IO should be forced.
59 : */
60 1910000 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
61 1910000 : : bForceCachedIO(bForceCachedIOIn)
62 :
63 : {
64 1909670 : }
65 :
66 : /************************************************************************/
67 : /* ~GDALRasterBand() */
68 : /************************************************************************/
69 :
70 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
71 : instead destroy the GDALDataset. */
72 :
73 1910000 : GDALRasterBand::~GDALRasterBand()
74 :
75 : {
76 1910000 : if (poDS && poDS->IsMarkedSuppressOnClose())
77 : {
78 526 : if (poBandBlockCache)
79 461 : poBandBlockCache->DisableDirtyBlockWriting();
80 : }
81 1910000 : GDALRasterBand::FlushCache(true);
82 :
83 1910000 : delete poBandBlockCache;
84 :
85 1910000 : if (static_cast<GIntBig>(nBlockReads) >
86 1910000 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
87 219 : nBand == 1 && poDS != nullptr)
88 : {
89 318 : CPLDebug(
90 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
91 159 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
92 159 : poDS->GetDescription());
93 : }
94 :
95 1910000 : InvalidateMaskBand();
96 1910000 : nBand = -nBand;
97 :
98 1910000 : delete m_poPointsCache;
99 1910000 : }
100 :
101 : /************************************************************************/
102 : /* RasterIO() */
103 : /************************************************************************/
104 :
105 : /**
106 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
107 : * int nXOff, int nYOff, int nXSize, int nYSize,
108 : * void * pData, int nBufXSize, int nBufYSize,
109 : * GDALDataType eBufType,
110 : * GSpacing nPixelSpace,
111 : * GSpacing nLineSpace,
112 : * GDALRasterIOExtraArg* psExtraArg )
113 : * \brief Read/write a region of image data for this band.
114 : *
115 : * This method allows reading a region of a GDALRasterBand into a buffer,
116 : * or writing data from a buffer into a region of a GDALRasterBand. It
117 : * automatically takes care of data type translation if the data type
118 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
119 : * The method also takes care of image decimation / replication if the
120 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
121 : * region being accessed (nXSize x nYSize).
122 : *
123 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
124 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
125 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
126 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
127 : * Or use nLineSpace and a possibly shifted pData value.
128 : *
129 : * The nPixelSpace and nLineSpace parameters allow reading into or
130 : * writing from unusually organized buffers. This is primarily used
131 : * for buffers containing more than one bands raster data in interleaved
132 : * format.
133 : *
134 : * Some formats may efficiently implement decimation into a buffer by
135 : * reading from lower resolution overview images. The logic of the default
136 : * implementation in the base class GDALRasterBand is the following one. It
137 : * computes a target_downscaling_factor from the window of interest and buffer
138 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
139 : * It then walks through overviews and will select the first one whose
140 : * downscaling factor is greater than target_downscaling_factor / 1.2.
141 : *
142 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
143 : * The relationship between target_downscaling_factor and the select overview
144 : * level is the following one:
145 : *
146 : * target_downscaling_factor | selected_overview
147 : * ------------------------- | -----------------
148 : * ]0, 2 / 1.2] | full resolution band
149 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
150 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
151 : * ]8 / 1.2, infinity[ | 8x downsampled band
152 : *
153 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
154 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
155 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
156 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
157 : * this oversampling threshold defaults to 1. Consequently if there are overviews
158 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
159 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
160 : *
161 : * For highest performance full resolution data access, read and write
162 : * on "block boundaries" as returned by GetBlockSize(), or use the
163 : * ReadBlock() and WriteBlock() methods.
164 : *
165 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
166 : * functions.
167 : *
168 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
169 : * write a region of data.
170 : *
171 : * @param nXOff The pixel offset to the top left corner of the region
172 : * of the band to be accessed. This would be zero to start from the left side.
173 : *
174 : * @param nYOff The line offset to the top left corner of the region
175 : * of the band to be accessed. This would be zero to start from the top.
176 : *
177 : * @param nXSize The width of the region of the band to be accessed in pixels.
178 : *
179 : * @param nYSize The height of the region of the band to be accessed in lines.
180 : *
181 : * @param pData The buffer into which the data should be read, or from which
182 : * it should be written. This buffer must contain at least nBufXSize *
183 : * nBufYSize words of type eBufType. It is organized in left to right,
184 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
185 : * and nLineSpace parameters.
186 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
187 : * temporarily modified during the execution of this method (and eventually
188 : * restored back to its original content), so it is not safe to use a buffer
189 : * stored in a read-only section of the calling program.
190 : *
191 : * @param nBufXSize the width of the buffer image into which the desired region
192 : * is to be read, or from which it is to be written.
193 : *
194 : * @param nBufYSize the height of the buffer image into which the desired region
195 : * is to be read, or from which it is to be written.
196 : *
197 : * @param eBufType the type of the pixel values in the pData data buffer. The
198 : * pixel values will automatically be translated to/from the GDALRasterBand
199 : * data type as needed. Most driver implementations will use GDALCopyWords64()
200 : * to perform data type translation.
201 : *
202 : * @param nPixelSpace The byte offset from the start of one pixel value in
203 : * pData to the start of the next pixel value within a scanline. If defaulted
204 : * (0) the size of the datatype eBufType is used.
205 : *
206 : * @param nLineSpace The byte offset from the start of one scanline in
207 : * pData to the start of the next. If defaulted (0) the size of the datatype
208 : * eBufType * nBufXSize is used.
209 : *
210 : * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
211 : * structure with additional arguments to specify resampling and progress
212 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
213 : * configuration option can also be defined to override the default resampling
214 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
215 : *
216 : * @return CE_Failure if the access fails, otherwise CE_None.
217 : */
218 :
219 : /**
220 : * \brief Read/write a region of image data for this band.
221 : *
222 : * This method allows reading a region of a GDALRasterBand into a buffer,
223 : * or writing data from a buffer into a region of a GDALRasterBand. It
224 : * automatically takes care of data type translation if the data type
225 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
226 : * The method also takes care of image decimation / replication if the
227 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
228 : * region being accessed (nXSize x nYSize).
229 : *
230 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
231 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
232 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
233 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
234 : * Or use nLineSpace and a possibly shifted pData value.
235 : *
236 : * The nPixelSpace and nLineSpace parameters allow reading into or
237 : * writing from unusually organized buffers. This is primarily used
238 : * for buffers containing more than one bands raster data in interleaved
239 : * format.
240 : *
241 : * Some formats may efficiently implement decimation into a buffer by
242 : * reading from lower resolution overview images. The logic of the default
243 : * implementation in the base class GDALRasterBand is the following one. It
244 : * computes a target_downscaling_factor from the window of interest and buffer
245 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
246 : * It then walks through overviews and will select the first one whose
247 : * downscaling factor is greater than target_downscaling_factor / 1.2.
248 : *
249 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
250 : * The relationship between target_downscaling_factor and the select overview
251 : * level is the following one:
252 : *
253 : * target_downscaling_factor | selected_overview
254 : * ------------------------- | -----------------
255 : * ]0, 2 / 1.2] | full resolution band
256 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
257 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
258 : * ]8 / 1.2, infinity[ | 8x downsampled band
259 : *
260 : * For highest performance full resolution data access, read and write
261 : * on "block boundaries" as returned by GetBlockSize(), or use the
262 : * ReadBlock() and WriteBlock() methods.
263 : *
264 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
265 : * functions.
266 : *
267 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
268 : * more convenient to use for most common use cases.
269 : *
270 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
271 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
272 : * instance of this dataset) concurrently from several threads.
273 : *
274 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
275 : * write a region of data.
276 : *
277 : * @param nXOff The pixel offset to the top left corner of the region
278 : * of the band to be accessed. This would be zero to start from the left side.
279 : *
280 : * @param nYOff The line offset to the top left corner of the region
281 : * of the band to be accessed. This would be zero to start from the top.
282 : *
283 : * @param nXSize The width of the region of the band to be accessed in pixels.
284 : *
285 : * @param nYSize The height of the region of the band to be accessed in lines.
286 : *
287 : * @param[in,out] pData The buffer into which the data should be read, or from
288 : * which it should be written. This buffer must contain at least nBufXSize *
289 : * nBufYSize words of type eBufType. It is organized in left to right,
290 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
291 : * and nLineSpace parameters.
292 : *
293 : * @param nBufXSize the width of the buffer image into which the desired region
294 : * is to be read, or from which it is to be written.
295 : *
296 : * @param nBufYSize the height of the buffer image into which the desired region
297 : * is to be read, or from which it is to be written.
298 : *
299 : * @param eBufType the type of the pixel values in the pData data buffer. The
300 : * pixel values will automatically be translated to/from the GDALRasterBand
301 : * data type as needed.
302 : *
303 : * @param nPixelSpace The byte offset from the start of one pixel value in
304 : * pData to the start of the next pixel value within a scanline. If defaulted
305 : * (0) the size of the datatype eBufType is used.
306 : *
307 : * @param nLineSpace The byte offset from the start of one scanline in
308 : * pData to the start of the next. If defaulted (0) the size of the datatype
309 : * eBufType * nBufXSize is used.
310 : *
311 : * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
312 : * structure with additional arguments to specify resampling and progress
313 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
314 : * configuration option can also be defined to override the default resampling
315 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
316 : *
317 : * @return CE_Failure if the access fails, otherwise CE_None.
318 : *
319 : * @see GDALRasterBand::ReadRaster()
320 : */
321 :
322 4391730 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
323 : int nXSize, int nYSize, void *pData,
324 : int nBufXSize, int nBufYSize,
325 : GDALDataType eBufType, GSpacing nPixelSpace,
326 : GSpacing nLineSpace,
327 : GDALRasterIOExtraArg *psExtraArg)
328 :
329 : {
330 : GDALRasterIOExtraArg sExtraArg;
331 4391730 : if (psExtraArg == nullptr)
332 : {
333 3795430 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
334 3795430 : psExtraArg = &sExtraArg;
335 : }
336 596300 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
337 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
338 : {
339 0 : ReportError(CE_Failure, CPLE_AppDefined,
340 : "Unhandled version of GDALRasterIOExtraArg");
341 0 : return CE_Failure;
342 : }
343 :
344 4391730 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
345 : nBufYSize);
346 :
347 4396040 : if (CPL_UNLIKELY(nullptr == pData))
348 : {
349 0 : ReportError(CE_Failure, CPLE_AppDefined,
350 : "The buffer into which the data should be read is null");
351 0 : return CE_Failure;
352 : }
353 :
354 : /* -------------------------------------------------------------------- */
355 : /* Some size values are "noop". Lets just return to avoid */
356 : /* stressing lower level functions. */
357 : /* -------------------------------------------------------------------- */
358 4396040 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
359 : nBufYSize < 1))
360 : {
361 2 : CPLDebug("GDAL",
362 : "RasterIO() skipped for odd window or buffer size.\n"
363 : " Window = (%d,%d)x%dx%d\n"
364 : " Buffer = %dx%d\n",
365 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
366 :
367 2 : return CE_None;
368 : }
369 :
370 4396040 : if (eRWFlag == GF_Write)
371 : {
372 363063 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
373 : {
374 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
375 : "An error occurred while writing a dirty block "
376 : "from GDALRasterBand::RasterIO");
377 0 : CPLErr eErr = eFlushBlockErr;
378 0 : eFlushBlockErr = CE_None;
379 0 : return eErr;
380 : }
381 363063 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
382 : {
383 7 : return CE_Failure;
384 : }
385 : }
386 :
387 : /* -------------------------------------------------------------------- */
388 : /* If pixel and line spacing are defaulted assign reasonable */
389 : /* value assuming a packed buffer. */
390 : /* -------------------------------------------------------------------- */
391 4396050 : if (nPixelSpace == 0)
392 : {
393 4000240 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
394 : }
395 :
396 4391190 : if (nLineSpace == 0)
397 : {
398 3983710 : nLineSpace = nPixelSpace * nBufXSize;
399 : }
400 :
401 : /* -------------------------------------------------------------------- */
402 : /* Do some validation of parameters. */
403 : /* -------------------------------------------------------------------- */
404 4391190 : if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
405 : nXOff + nXSize > nRasterXSize || nYOff < 0 ||
406 : nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
407 : {
408 15 : ReportError(CE_Failure, CPLE_IllegalArg,
409 : "Access window out of range in RasterIO(). Requested\n"
410 : "(%d,%d) of size %dx%d on raster of %dx%d.",
411 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
412 15 : return CE_Failure;
413 : }
414 :
415 4391180 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
416 : {
417 0 : ReportError(
418 : CE_Failure, CPLE_IllegalArg,
419 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
420 : eRWFlag);
421 0 : return CE_Failure;
422 : }
423 4391180 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
424 : {
425 2 : ReportError(CE_Failure, CPLE_IllegalArg,
426 : "Illegal GDT_Unknown/GDT_TypeCount argument");
427 2 : return CE_Failure;
428 : }
429 :
430 4391180 : return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
431 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
432 4385620 : nLineSpace, psExtraArg);
433 : }
434 :
435 : /************************************************************************/
436 : /* RasterIOInternal() */
437 : /************************************************************************/
438 :
439 4398740 : CPLErr GDALRasterBand::RasterIOInternal(
440 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
441 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
442 : GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
443 : {
444 : /* -------------------------------------------------------------------- */
445 : /* Call the format specific function. */
446 : /* -------------------------------------------------------------------- */
447 :
448 4398740 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
449 :
450 : CPLErr eErr;
451 4392160 : if (bForceCachedIO)
452 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
453 : pData, nBufXSize, nBufYSize, eBufType,
454 : nPixelSpace, nLineSpace, psExtraArg);
455 : else
456 : eErr =
457 4397290 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
458 4392130 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
459 :
460 4397310 : if (bCallLeaveReadWrite)
461 600153 : LeaveReadWrite();
462 :
463 4389650 : return eErr;
464 : }
465 :
466 : /************************************************************************/
467 : /* GDALRasterIO() */
468 : /************************************************************************/
469 :
470 : /**
471 : * \brief Read/write a region of image data for this band.
472 : *
473 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
474 : * resolution, progress callback, etc. are needed)
475 : *
476 : * @see GDALRasterBand::RasterIO()
477 : */
478 :
479 3401900 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
480 : int nXOff, int nYOff, int nXSize, int nYSize,
481 : void *pData, int nBufXSize, int nBufYSize,
482 : GDALDataType eBufType, int nPixelSpace,
483 : int nLineSpace)
484 :
485 : {
486 3401900 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
487 :
488 3401900 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
489 :
490 3394340 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
491 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
492 3383690 : nLineSpace, nullptr));
493 : }
494 :
495 : /************************************************************************/
496 : /* GDALRasterIOEx() */
497 : /************************************************************************/
498 :
499 : /**
500 : * \brief Read/write a region of image data for this band.
501 : *
502 : * @see GDALRasterBand::RasterIO()
503 : * @since GDAL 2.0
504 : */
505 :
506 39074 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
507 : int nXOff, int nYOff, int nXSize, int nYSize,
508 : void *pData, int nBufXSize, int nBufYSize,
509 : GDALDataType eBufType, GSpacing nPixelSpace,
510 : GSpacing nLineSpace,
511 : GDALRasterIOExtraArg *psExtraArg)
512 :
513 : {
514 39074 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
515 :
516 39074 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
517 :
518 39074 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
519 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
520 39073 : nLineSpace, psExtraArg));
521 : }
522 :
523 : /************************************************************************/
524 : /* GetGDTFromCppType() */
525 : /************************************************************************/
526 :
527 : namespace
528 : {
529 : template <class T> struct GetGDTFromCppType;
530 :
531 : #define DEFINE_GetGDTFromCppType(T, eDT) \
532 : template <> struct GetGDTFromCppType<T> \
533 : { \
534 : static constexpr GDALDataType GDT = eDT; \
535 : }
536 :
537 : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
538 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
539 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
540 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
541 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
542 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
543 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
544 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
545 : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
546 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
547 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
548 : // Not allowed by C++ standard
549 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
550 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
551 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
552 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
553 : } // namespace
554 :
555 : /************************************************************************/
556 : /* ReadRaster() */
557 : /************************************************************************/
558 :
559 : // clang-format off
560 : /** Read a region of image data for this band.
561 : *
562 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
563 : * for common use cases, like reading a whole band.
564 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
565 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
566 : * float, double, std::complex<float|double>.
567 : *
568 : * 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>&,
569 : * and can allocate memory automatically.
570 : *
571 : * To read a whole band (assuming it fits into memory), as an array of double:
572 : *
573 : \code{.cpp}
574 : double* myArray = static_cast<double*>(
575 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
576 : // TODO: check here that myArray != nullptr
577 : const size_t nArrayEltCount =
578 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
579 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
580 : {
581 : // do something
582 : }
583 : VSIFree(myArray)
584 : \endcode
585 : *
586 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
587 : *
588 : \code{.cpp}
589 : double* myArray = static_cast<double*>(
590 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
591 : // TODO: check here that myArray != nullptr
592 : const size_t nArrayEltCount = 128 * 128;
593 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
594 : {
595 : // do something
596 : }
597 : VSIFree(myArray)
598 : \endcode
599 : *
600 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
601 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
602 : * instance of this dataset) concurrently from several threads.
603 : *
604 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
605 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
606 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
607 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
608 : * Or use nLineSpace and a possibly shifted pData value.
609 : *
610 : * @param[out] pData The buffer into which the data should be written.
611 : * This buffer must contain at least nBufXSize *
612 : * nBufYSize words of type T. It is organized in left to right,
613 : * top to bottom pixel order, and fully packed.
614 : * The type of the buffer does not need to be the one of GetDataType(). The
615 : * method will perform data type translation (with potential rounding, clamping)
616 : * if needed.
617 : *
618 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
619 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
620 : * return in error if it is not. If set to zero, then pData is trusted to be
621 : * large enough.
622 : *
623 : * @param dfXOff The pixel offset to the top left corner of the region
624 : * of the band to be accessed. This would be zero to start from the left side.
625 : * Defaults to 0.
626 : *
627 : * @param dfYOff The line offset to the top left corner of the region
628 : * of the band to be accessed. This would be zero to start from the top.
629 : * Defaults to 0.
630 : *
631 : * @param dfXSize The width of the region of the band to be accessed in pixels.
632 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
633 : * dfXSize is set to the band width.
634 : *
635 : * @param dfYSize The height of the region of the band to be accessed in lines.
636 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
637 : * dfYSize is set to the band height.
638 : *
639 : * @param nBufXSize the width of the buffer image into which the desired region
640 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
641 : * then nBufXSize is initialized with dfXSize.
642 : *
643 : * @param nBufYSize the height of the buffer image into which the desired region
644 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
645 : * then nBufYSize is initialized with dfYSize.
646 : *
647 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
648 : *
649 : * @param pfnProgress Progress function. May be nullptr.
650 : *
651 : * @param pProgressData User data of pfnProgress. May be nullptr.
652 : *
653 : * @return CE_Failure if the access fails, otherwise CE_None.
654 : *
655 : * @see GDALRasterBand::RasterIO()
656 : * @since GDAL 3.10
657 : */
658 : // clang-format on
659 :
660 : template <class T>
661 20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
662 : double dfXOff, double dfYOff, double dfXSize,
663 : double dfYSize, size_t nBufXSize,
664 : size_t nBufYSize,
665 : GDALRIOResampleAlg eResampleAlg,
666 : GDALProgressFunc pfnProgress,
667 : void *pProgressData) const
668 : {
669 20 : if (((nBufXSize | nBufYSize) >> 31) != 0)
670 : {
671 2 : return CE_Failure;
672 : }
673 :
674 18 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
675 : {
676 16 : dfXSize = nRasterXSize;
677 16 : dfYSize = nRasterYSize;
678 : }
679 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
680 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
681 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
682 2 : dfYOff + dfYSize > INT_MAX)
683 : {
684 0 : return CE_Failure;
685 : }
686 :
687 : GDALRasterIOExtraArg sExtraArg;
688 18 : sExtraArg.nVersion = 1;
689 18 : sExtraArg.eResampleAlg = eResampleAlg;
690 18 : sExtraArg.pfnProgress = pfnProgress;
691 18 : sExtraArg.pProgressData = pProgressData;
692 18 : sExtraArg.bFloatingPointWindowValidity = true;
693 18 : sExtraArg.dfXOff = dfXOff;
694 18 : sExtraArg.dfYOff = dfYOff;
695 18 : sExtraArg.dfXSize = dfXSize;
696 18 : sExtraArg.dfYSize = dfYSize;
697 18 : const int nXOff = static_cast<int>(dfXOff);
698 18 : const int nYOff = static_cast<int>(dfYOff);
699 18 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
700 18 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
701 18 : if (nBufXSize == 0 && nBufYSize == 0)
702 : {
703 17 : if (static_cast<int>(dfXSize) == dfXSize &&
704 17 : static_cast<int>(dfYSize) == dfYSize)
705 : {
706 17 : nBufXSize = static_cast<int>(dfXSize);
707 17 : nBufYSize = static_cast<int>(dfYSize);
708 : }
709 : else
710 : {
711 0 : CPLError(CE_Failure, CPLE_AppDefined,
712 : "nBufXSize and nBufYSize must be provided if dfXSize or "
713 : "dfYSize is not an integer value");
714 0 : return CE_Failure;
715 : }
716 : }
717 18 : if (nBufXSize == 0 || nBufYSize == 0)
718 : {
719 0 : CPLDebug("GDAL",
720 : "RasterIO() skipped for odd window or buffer size.\n"
721 : " Window = (%d,%d)x%dx%d\n"
722 : " Buffer = %dx%d\n",
723 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
724 : static_cast<int>(nBufYSize));
725 :
726 0 : return CE_None;
727 : }
728 :
729 18 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
730 : {
731 1 : CPLError(CE_Failure, CPLE_AppDefined,
732 : "Provided array is not large enough");
733 1 : return CE_Failure;
734 : }
735 :
736 17 : constexpr GSpacing nPixelSpace = sizeof(T);
737 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
738 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
739 :
740 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
741 :
742 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
743 : static_cast<int>(nBufXSize),
744 : static_cast<int>(nBufYSize), eBufType,
745 17 : nPixelSpace, nLineSpace, &sExtraArg);
746 : }
747 :
748 : //! @cond Doxygen_Suppress
749 :
750 : #define INSTANTIATE_READ_RASTER(T) \
751 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
752 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
753 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
754 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
755 : void *pProgressData) const;
756 :
757 : INSTANTIATE_READ_RASTER(uint8_t)
758 : INSTANTIATE_READ_RASTER(int8_t)
759 : INSTANTIATE_READ_RASTER(uint16_t)
760 : INSTANTIATE_READ_RASTER(int16_t)
761 : INSTANTIATE_READ_RASTER(uint32_t)
762 : INSTANTIATE_READ_RASTER(int32_t)
763 : INSTANTIATE_READ_RASTER(uint64_t)
764 : INSTANTIATE_READ_RASTER(int64_t)
765 : INSTANTIATE_READ_RASTER(GFloat16)
766 : INSTANTIATE_READ_RASTER(float)
767 : INSTANTIATE_READ_RASTER(double)
768 : // Not allowed by C++ standard
769 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
770 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
771 : INSTANTIATE_READ_RASTER(std::complex<float>)
772 : INSTANTIATE_READ_RASTER(std::complex<double>)
773 :
774 : //! @endcond
775 :
776 : /************************************************************************/
777 : /* ReadRaster() */
778 : /************************************************************************/
779 :
780 : /** Read a region of image data for this band.
781 : *
782 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
783 : * for common use cases, like reading a whole band.
784 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
785 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
786 : * float, double, std::complex<float|double>.
787 : *
788 : * To read a whole band (assuming it fits into memory), as a vector of double:
789 : *
790 : \code
791 : std::vector<double> myArray;
792 : if (poBand->ReadRaster(myArray) == CE_None)
793 : {
794 : // do something
795 : }
796 : \endcode
797 : *
798 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
799 : *
800 : \code{.cpp}
801 : std::vector<double> myArray;
802 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
803 : {
804 : // do something
805 : }
806 : \endcode
807 : *
808 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
809 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
810 : * instance of this dataset) concurrently from several threads.
811 : *
812 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
813 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
814 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
815 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
816 : * Or use nLineSpace and a possibly shifted pData value.
817 : *
818 : * @param[out] vData The vector into which the data should be written.
819 : * The vector will be resized, if needed, to contain at least nBufXSize *
820 : * nBufYSize values. The values in the vector are organized in left to right,
821 : * top to bottom pixel order, and fully packed.
822 : * The type of the vector does not need to be the one of GetDataType(). The
823 : * method will perform data type translation (with potential rounding, clamping)
824 : * if needed.
825 : *
826 : * @param dfXOff The pixel offset to the top left corner of the region
827 : * of the band to be accessed. This would be zero to start from the left side.
828 : * Defaults to 0.
829 : *
830 : * @param dfYOff The line offset to the top left corner of the region
831 : * of the band to be accessed. This would be zero to start from the top.
832 : * Defaults to 0.
833 : *
834 : * @param dfXSize The width of the region of the band to be accessed in pixels.
835 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
836 : * dfXSize is set to the band width.
837 : *
838 : * @param dfYSize The height of the region of the band to be accessed in lines.
839 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
840 : * dfYSize is set to the band height.
841 : *
842 : * @param nBufXSize the width of the buffer image into which the desired region
843 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
844 : * then nBufXSize is initialized with dfXSize.
845 : *
846 : * @param nBufYSize the height of the buffer image into which the desired region
847 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
848 : * then nBufYSize is initialized with dfYSize.
849 : *
850 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
851 : *
852 : * @param pfnProgress Progress function. May be nullptr.
853 : *
854 : * @param pProgressData User data of pfnProgress. May be nullptr.
855 : *
856 : * @return CE_Failure if the access fails, otherwise CE_None.
857 : *
858 : * @see GDALRasterBand::RasterIO()
859 : * @since GDAL 3.10
860 : */
861 : template <class T>
862 22 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
863 : double dfYOff, double dfXSize, double dfYSize,
864 : size_t nBufXSize, size_t nBufYSize,
865 : GDALRIOResampleAlg eResampleAlg,
866 : GDALProgressFunc pfnProgress,
867 : void *pProgressData) const
868 : {
869 22 : if (((nBufXSize | nBufYSize) >> 31) != 0)
870 : {
871 2 : return CE_Failure;
872 : }
873 :
874 20 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
875 : {
876 13 : dfXSize = nRasterXSize;
877 13 : dfYSize = nRasterYSize;
878 : }
879 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
880 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
881 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
882 7 : dfYOff + dfYSize > INT_MAX)
883 : {
884 0 : return CE_Failure;
885 : }
886 :
887 : GDALRasterIOExtraArg sExtraArg;
888 20 : sExtraArg.nVersion = 1;
889 20 : sExtraArg.eResampleAlg = eResampleAlg;
890 20 : sExtraArg.pfnProgress = pfnProgress;
891 20 : sExtraArg.pProgressData = pProgressData;
892 20 : sExtraArg.bFloatingPointWindowValidity = true;
893 20 : sExtraArg.dfXOff = dfXOff;
894 20 : sExtraArg.dfYOff = dfYOff;
895 20 : sExtraArg.dfXSize = dfXSize;
896 20 : sExtraArg.dfYSize = dfYSize;
897 20 : const int nXOff = static_cast<int>(dfXOff);
898 20 : const int nYOff = static_cast<int>(dfYOff);
899 20 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
900 20 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
901 20 : if (nBufXSize == 0 && nBufYSize == 0)
902 : {
903 16 : if (static_cast<int>(dfXSize) == dfXSize &&
904 15 : static_cast<int>(dfYSize) == dfYSize)
905 : {
906 15 : nBufXSize = static_cast<int>(dfXSize);
907 15 : nBufYSize = static_cast<int>(dfYSize);
908 : }
909 : else
910 : {
911 1 : CPLError(CE_Failure, CPLE_AppDefined,
912 : "nBufXSize and nBufYSize must be provided if "
913 : "dfXSize or dfYSize is not an integer value");
914 1 : return CE_Failure;
915 : }
916 : }
917 19 : if (nBufXSize == 0 || nBufYSize == 0)
918 : {
919 0 : CPLDebug("GDAL",
920 : "RasterIO() skipped for odd window or buffer size.\n"
921 : " Window = (%d,%d)x%dx%d\n"
922 : " Buffer = %dx%d\n",
923 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
924 : static_cast<int>(nBufYSize));
925 :
926 0 : return CE_None;
927 : }
928 :
929 : if constexpr (SIZEOF_VOIDP < 8)
930 : {
931 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
932 : {
933 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
934 : return CE_Failure;
935 : }
936 : }
937 :
938 19 : if (vData.size() < nBufXSize * nBufYSize)
939 : {
940 : try
941 : {
942 17 : vData.resize(nBufXSize * nBufYSize);
943 : }
944 1 : catch (const std::exception &)
945 : {
946 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
947 1 : return CE_Failure;
948 : }
949 : }
950 :
951 18 : constexpr GSpacing nPixelSpace = sizeof(T);
952 18 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
953 18 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
954 :
955 18 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
956 :
957 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
958 : vData.data(), static_cast<int>(nBufXSize),
959 : static_cast<int>(nBufYSize), eBufType,
960 18 : nPixelSpace, nLineSpace, &sExtraArg);
961 : }
962 :
963 : //! @cond Doxygen_Suppress
964 :
965 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
966 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
967 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
968 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
969 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
970 : void *pProgressData) const;
971 :
972 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
973 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
974 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
975 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
976 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
977 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
978 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
979 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
980 : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
981 : INSTANTIATE_READ_RASTER_VECTOR(float)
982 : INSTANTIATE_READ_RASTER_VECTOR(double)
983 : // Not allowed by C++ standard
984 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
985 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
986 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
987 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
988 :
989 : //! @endcond
990 :
991 : /************************************************************************/
992 : /* ReadBlock() */
993 : /************************************************************************/
994 :
995 : /**
996 : * \brief Read a block of image data efficiently.
997 : *
998 : * This method accesses a "natural" block from the raster band without
999 : * resampling, or data type conversion. For a more generalized, but
1000 : * potentially less efficient access use RasterIO().
1001 : *
1002 : * This method is the same as the C GDALReadBlock() function.
1003 : *
1004 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1005 : * block oriented data without an extra copy into an application buffer.
1006 : *
1007 : * The following code would efficiently compute a histogram of eight bit
1008 : * raster data. Note that the final block may be partial ... data beyond
1009 : * the edge of the underlying raster band in these edge blocks is of an
1010 : * undetermined value.
1011 : *
1012 : \code{.cpp}
1013 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1014 :
1015 : {
1016 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1017 :
1018 : CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1019 :
1020 : int nXBlockSize, nYBlockSize;
1021 :
1022 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1023 : int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1024 : int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1025 :
1026 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1027 :
1028 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1029 : {
1030 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1031 : {
1032 : int nXValid, nYValid;
1033 :
1034 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1035 :
1036 : // Compute the portion of the block that is valid
1037 : // for partial edge blocks.
1038 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1039 :
1040 : // Collect the histogram counts.
1041 : for( int iY = 0; iY < nYValid; iY++ )
1042 : {
1043 : for( int iX = 0; iX < nXValid; iX++ )
1044 : {
1045 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1046 : }
1047 : }
1048 : }
1049 : }
1050 : }
1051 : \endcode
1052 : *
1053 : * @param nXBlockOff the horizontal block offset, with zero indicating
1054 : * the left most block, 1 the next block and so forth.
1055 : *
1056 : * @param nYBlockOff the vertical block offset, with zero indicating
1057 : * the top most block, 1 the next block and so forth.
1058 : *
1059 : * @param pImage the buffer into which the data will be read. The buffer
1060 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1061 : * of type GetRasterDataType().
1062 : *
1063 : * @return CE_None on success or CE_Failure on an error.
1064 : */
1065 :
1066 879 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1067 :
1068 : {
1069 : /* -------------------------------------------------------------------- */
1070 : /* Validate arguments. */
1071 : /* -------------------------------------------------------------------- */
1072 879 : CPLAssert(pImage != nullptr);
1073 :
1074 879 : if (!InitBlockInfo())
1075 0 : return CE_Failure;
1076 :
1077 879 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1078 : {
1079 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1080 : "Illegal nXBlockOff value (%d) in "
1081 : "GDALRasterBand::ReadBlock()\n",
1082 : nXBlockOff);
1083 :
1084 0 : return (CE_Failure);
1085 : }
1086 :
1087 879 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1088 : {
1089 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1090 : "Illegal nYBlockOff value (%d) in "
1091 : "GDALRasterBand::ReadBlock()\n",
1092 : nYBlockOff);
1093 :
1094 0 : return (CE_Failure);
1095 : }
1096 :
1097 : /* -------------------------------------------------------------------- */
1098 : /* Invoke underlying implementation method. */
1099 : /* -------------------------------------------------------------------- */
1100 :
1101 879 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1102 879 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1103 879 : if (bCallLeaveReadWrite)
1104 4 : LeaveReadWrite();
1105 879 : return eErr;
1106 : }
1107 :
1108 : /************************************************************************/
1109 : /* GDALReadBlock() */
1110 : /************************************************************************/
1111 :
1112 : /**
1113 : * \brief Read a block of image data efficiently.
1114 : *
1115 : * @see GDALRasterBand::ReadBlock()
1116 : */
1117 :
1118 69 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1119 : void *pData)
1120 :
1121 : {
1122 69 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1123 :
1124 69 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1125 69 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1126 : }
1127 :
1128 : /************************************************************************/
1129 : /* IReadBlock() */
1130 : /************************************************************************/
1131 :
1132 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1133 : * ) \brief Read a block of data.
1134 : *
1135 : * Default internal implementation ... to be overridden by
1136 : * subclasses that support reading.
1137 : * @param nBlockXOff Block X Offset
1138 : * @param nBlockYOff Block Y Offset
1139 : * @param pData Pixel buffer into which to place read data.
1140 : * @return CE_None on success or CE_Failure on an error.
1141 : */
1142 :
1143 : /************************************************************************/
1144 : /* IWriteBlock() */
1145 : /************************************************************************/
1146 :
1147 : /**
1148 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1149 : * Write a block of data.
1150 : *
1151 : * Default internal implementation ... to be overridden by
1152 : * subclasses that support writing.
1153 : * @param nBlockXOff Block X Offset
1154 : * @param nBlockYOff Block Y Offset
1155 : * @param pData Pixel buffer to write
1156 : * @return CE_None on success or CE_Failure on an error.
1157 : */
1158 :
1159 : /**/
1160 : /**/
1161 :
1162 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1163 : void * /*pData*/)
1164 :
1165 : {
1166 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1167 0 : ReportError(CE_Failure, CPLE_NotSupported,
1168 : "WriteBlock() not supported for this dataset.");
1169 :
1170 0 : return (CE_Failure);
1171 : }
1172 :
1173 : /************************************************************************/
1174 : /* WriteBlock() */
1175 : /************************************************************************/
1176 :
1177 : /**
1178 : * \brief Write a block of image data efficiently.
1179 : *
1180 : * This method accesses a "natural" block from the raster band without
1181 : * resampling, or data type conversion. For a more generalized, but
1182 : * potentially less efficient access use RasterIO().
1183 : *
1184 : * This method is the same as the C GDALWriteBlock() function.
1185 : *
1186 : * See ReadBlock() for an example of block oriented data access.
1187 : *
1188 : * @param nXBlockOff the horizontal block offset, with zero indicating
1189 : * the left most block, 1 the next block and so forth.
1190 : *
1191 : * @param nYBlockOff the vertical block offset, with zero indicating
1192 : * the left most block, 1 the next block and so forth.
1193 : *
1194 : * @param pImage the buffer from which the data will be written. The buffer
1195 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1196 : * of type GetRasterDataType(). Note that the content of the buffer might be
1197 : * temporarily modified during the execution of this method (and eventually
1198 : * restored back to its original content), so it is not safe to use a buffer
1199 : * stored in a read-only section of the calling program.
1200 : *
1201 : * @return CE_None on success or CE_Failure on an error.
1202 : */
1203 :
1204 4888 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1205 :
1206 : {
1207 : /* -------------------------------------------------------------------- */
1208 : /* Validate arguments. */
1209 : /* -------------------------------------------------------------------- */
1210 4888 : CPLAssert(pImage != nullptr);
1211 :
1212 4888 : if (!InitBlockInfo())
1213 0 : return CE_Failure;
1214 :
1215 4888 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1216 : {
1217 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1218 : "Illegal nXBlockOff value (%d) in "
1219 : "GDALRasterBand::WriteBlock()\n",
1220 : nXBlockOff);
1221 :
1222 0 : return (CE_Failure);
1223 : }
1224 :
1225 4888 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1226 : {
1227 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1228 : "Illegal nYBlockOff value (%d) in "
1229 : "GDALRasterBand::WriteBlock()\n",
1230 : nYBlockOff);
1231 :
1232 0 : return (CE_Failure);
1233 : }
1234 :
1235 4888 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1236 : {
1237 0 : return CE_Failure;
1238 : }
1239 :
1240 4888 : if (eFlushBlockErr != CE_None)
1241 : {
1242 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1243 : "An error occurred while writing a dirty block "
1244 : "from GDALRasterBand::WriteBlock");
1245 0 : CPLErr eErr = eFlushBlockErr;
1246 0 : eFlushBlockErr = CE_None;
1247 0 : return eErr;
1248 : }
1249 :
1250 : /* -------------------------------------------------------------------- */
1251 : /* Invoke underlying implementation method. */
1252 : /* -------------------------------------------------------------------- */
1253 :
1254 4888 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1255 4888 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1256 4888 : if (bCallLeaveReadWrite)
1257 4888 : LeaveReadWrite();
1258 :
1259 4888 : return eErr;
1260 : }
1261 :
1262 : /************************************************************************/
1263 : /* GDALWriteBlock() */
1264 : /************************************************************************/
1265 :
1266 : /**
1267 : * \brief Write a block of image data efficiently.
1268 : *
1269 : * @see GDALRasterBand::WriteBlock()
1270 : */
1271 :
1272 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1273 : void *pData)
1274 :
1275 : {
1276 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1277 :
1278 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1279 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1280 : }
1281 :
1282 : /************************************************************************/
1283 : /* EmitErrorMessageIfWriteNotSupported() */
1284 : /************************************************************************/
1285 :
1286 : /**
1287 : * Emit an error message if a write operation to this band is not supported.
1288 : *
1289 : * The base implementation will emit an error message if the access mode is
1290 : * read-only. Derived classes may implement it to provide a custom message.
1291 : *
1292 : * @param pszCaller Calling function.
1293 : * @return true if an error message has been emitted.
1294 : */
1295 636192 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1296 : const char *pszCaller) const
1297 : {
1298 636192 : if (eAccess == GA_ReadOnly)
1299 : {
1300 4 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1301 : "%s: attempt to write to dataset opened in read-only mode.",
1302 : pszCaller);
1303 :
1304 4 : return true;
1305 : }
1306 636188 : return false;
1307 : }
1308 :
1309 : /************************************************************************/
1310 : /* GetActualBlockSize() */
1311 : /************************************************************************/
1312 : /**
1313 : * \brief Fetch the actual block size for a given block offset.
1314 : *
1315 : * Handles partial blocks at the edges of the raster and returns the true
1316 : * number of pixels
1317 : *
1318 : * @param nXBlockOff the horizontal block offset for which to calculate the
1319 : * number of valid pixels, with zero indicating the left most block, 1 the next
1320 : * block and so forth.
1321 : *
1322 : * @param nYBlockOff the vertical block offset, with zero indicating
1323 : * the top most block, 1 the next block and so forth.
1324 : *
1325 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1326 : * the x direction will be stored
1327 : *
1328 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1329 : * the y direction will be stored
1330 : *
1331 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1332 : *
1333 : * @since GDAL 2.2
1334 : */
1335 50501 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1336 : int *pnXValid, int *pnYValid) const
1337 : {
1338 101001 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1339 100999 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1340 100996 : nYBlockOff < 0 || nBlockYSize == 0 ||
1341 50498 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1342 : {
1343 4 : return CE_Failure;
1344 : }
1345 :
1346 50497 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1347 50497 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1348 :
1349 50497 : *pnXValid = nBlockXSize;
1350 50497 : *pnYValid = nBlockYSize;
1351 :
1352 50497 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1353 : {
1354 49109 : *pnXValid = nRasterXSize - nXPixelOff;
1355 : }
1356 :
1357 50497 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1358 : {
1359 3501 : *pnYValid = nRasterYSize - nYPixelOff;
1360 : }
1361 :
1362 50497 : return CE_None;
1363 : }
1364 :
1365 : /************************************************************************/
1366 : /* GDALGetActualBlockSize() */
1367 : /************************************************************************/
1368 :
1369 : /**
1370 : * \brief Retrieve the actual block size for a given block offset.
1371 : *
1372 : * @see GDALRasterBand::GetActualBlockSize()
1373 : */
1374 :
1375 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1376 : int nYBlockOff, int *pnXValid,
1377 : int *pnYValid)
1378 :
1379 : {
1380 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1381 :
1382 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1383 : return (
1384 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1385 : }
1386 :
1387 : /************************************************************************/
1388 : /* GetSuggestedBlockAccessPattern() */
1389 : /************************************************************************/
1390 :
1391 : /**
1392 : * \brief Return the suggested/most efficient access pattern to blocks
1393 : * (for read operations).
1394 : *
1395 : * While all GDAL drivers have to expose a block size, not all can guarantee
1396 : * efficient random access (GSBAP_RANDOM) to any block.
1397 : * Some drivers for example decompress sequentially a compressed stream from
1398 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1399 : * case best performance will be achieved while reading blocks in that order.
1400 : * (accessing blocks in random access in such rasters typically causes the
1401 : * decoding to be re-initialized from the start if accessing blocks in
1402 : * a non-sequential order)
1403 : *
1404 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1405 : * returned by drivers that expose a somewhat artificial block size, because
1406 : * they can extract any part of a raster, but in a rather inefficient way.
1407 : *
1408 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1409 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1410 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1411 : * most efficient strategy is to read as many pixels as possible in the less
1412 : * RasterIO() operations.
1413 : *
1414 : * The return of this method is for example used to determine the swath size
1415 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1416 : *
1417 : * @since GDAL 3.6
1418 : */
1419 :
1420 : GDALSuggestedBlockAccessPattern
1421 2355 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1422 : {
1423 2355 : return GSBAP_UNKNOWN;
1424 : }
1425 :
1426 : /************************************************************************/
1427 : /* GetRasterDataType() */
1428 : /************************************************************************/
1429 :
1430 : /**
1431 : * \brief Fetch the pixel data type for this band.
1432 : *
1433 : * This method is the same as the C function GDALGetRasterDataType().
1434 : *
1435 : * @return the data type of pixels for this band.
1436 : */
1437 :
1438 8979320 : GDALDataType GDALRasterBand::GetRasterDataType() const
1439 :
1440 : {
1441 8979320 : return eDataType;
1442 : }
1443 :
1444 : /************************************************************************/
1445 : /* GDALGetRasterDataType() */
1446 : /************************************************************************/
1447 :
1448 : /**
1449 : * \brief Fetch the pixel data type for this band.
1450 : *
1451 : * @see GDALRasterBand::GetRasterDataType()
1452 : */
1453 :
1454 903544 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1455 :
1456 : {
1457 903544 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1458 :
1459 903544 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1460 903543 : return poBand->GetRasterDataType();
1461 : }
1462 :
1463 : /************************************************************************/
1464 : /* GetBlockSize() */
1465 : /************************************************************************/
1466 :
1467 : /**
1468 : * \brief Fetch the "natural" block size of this band.
1469 : *
1470 : * GDAL contains a concept of the natural block size of rasters so that
1471 : * applications can organized data access efficiently for some file formats.
1472 : * The natural block size is the block size that is most efficient for
1473 : * accessing the format. For many formats this is simple a whole scanline
1474 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1475 : *
1476 : * However, for tiled images this will typically be the tile size.
1477 : *
1478 : * Note that the X and Y block sizes don't have to divide the image size
1479 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1480 : * See ReadBlock() for an example of code dealing with these issues.
1481 : *
1482 : * This method is the same as the C function GDALGetBlockSize().
1483 : *
1484 : * @param pnXSize integer to put the X block size into or NULL.
1485 : *
1486 : * @param pnYSize integer to put the Y block size into or NULL.
1487 : */
1488 :
1489 5482300 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1490 :
1491 : {
1492 5482300 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1493 : {
1494 19741 : ReportError(CE_Failure, CPLE_AppDefined,
1495 19741 : "Invalid block dimension : %d * %d", nBlockXSize,
1496 19741 : nBlockYSize);
1497 0 : if (pnXSize != nullptr)
1498 0 : *pnXSize = 0;
1499 0 : if (pnYSize != nullptr)
1500 0 : *pnYSize = 0;
1501 : }
1502 : else
1503 : {
1504 5462560 : if (pnXSize != nullptr)
1505 5466100 : *pnXSize = nBlockXSize;
1506 5462560 : if (pnYSize != nullptr)
1507 5464120 : *pnYSize = nBlockYSize;
1508 : }
1509 5462560 : }
1510 :
1511 : /************************************************************************/
1512 : /* GDALGetBlockSize() */
1513 : /************************************************************************/
1514 :
1515 : /**
1516 : * \brief Fetch the "natural" block size of this band.
1517 : *
1518 : * @see GDALRasterBand::GetBlockSize()
1519 : */
1520 :
1521 41034 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1522 : int *pnYSize)
1523 :
1524 : {
1525 41034 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1526 :
1527 41034 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1528 41034 : poBand->GetBlockSize(pnXSize, pnYSize);
1529 : }
1530 :
1531 : /************************************************************************/
1532 : /* InitBlockInfo() */
1533 : /************************************************************************/
1534 :
1535 : //! @cond Doxygen_Suppress
1536 3639130 : int GDALRasterBand::InitBlockInfo()
1537 :
1538 : {
1539 3639130 : if (poBandBlockCache != nullptr)
1540 3402710 : return poBandBlockCache->IsInitOK();
1541 :
1542 : /* Do some validation of raster and block dimensions in case the driver */
1543 : /* would have neglected to do it itself */
1544 236420 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1545 : {
1546 0 : ReportError(CE_Failure, CPLE_AppDefined,
1547 : "Invalid block dimension : %d * %d", nBlockXSize,
1548 : nBlockYSize);
1549 0 : return FALSE;
1550 : }
1551 :
1552 236462 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1553 : {
1554 118 : ReportError(CE_Failure, CPLE_AppDefined,
1555 : "Invalid raster dimension : %d * %d", nRasterXSize,
1556 : nRasterYSize);
1557 0 : return FALSE;
1558 : }
1559 :
1560 236344 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1561 236395 : if (nDataTypeSize == 0)
1562 : {
1563 22 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1564 0 : return FALSE;
1565 : }
1566 :
1567 : #if SIZEOF_VOIDP == 4
1568 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1569 : {
1570 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1571 : * multiplication in other cases */
1572 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1573 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1574 : {
1575 : ReportError(CE_Failure, CPLE_NotSupported,
1576 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1577 : nBlockYSize);
1578 : return FALSE;
1579 : }
1580 : }
1581 : #endif
1582 :
1583 236373 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1584 236373 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1585 :
1586 : const char *pszBlockStrategy =
1587 236373 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1588 236493 : bool bUseArray = true;
1589 236493 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1590 : {
1591 236453 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1592 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1593 : {
1594 236434 : GUIntBig nBlockCount =
1595 236434 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1596 236434 : if (poDS != nullptr)
1597 236238 : nBlockCount *= poDS->GetRasterCount();
1598 236435 : bUseArray = (nBlockCount < 1024 * 1024);
1599 : }
1600 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1601 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1602 : {
1603 0 : bUseArray = false;
1604 236454 : }
1605 : }
1606 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1607 40 : bUseArray = false;
1608 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1609 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1610 : pszBlockStrategy);
1611 :
1612 236493 : if (bUseArray)
1613 236422 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1614 : else
1615 : {
1616 71 : if (nBand == 1)
1617 26 : CPLDebug("GDAL", "Use hashset band block cache");
1618 71 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1619 : }
1620 236447 : if (poBandBlockCache == nullptr)
1621 0 : return FALSE;
1622 236447 : return poBandBlockCache->Init();
1623 : }
1624 :
1625 : //! @endcond
1626 :
1627 : /************************************************************************/
1628 : /* FlushCache() */
1629 : /************************************************************************/
1630 :
1631 : /**
1632 : * \brief Flush raster data cache.
1633 : *
1634 : * This call will recover memory used to cache data blocks for this raster
1635 : * band, and ensure that new requests are referred to the underlying driver.
1636 : *
1637 : * This method is the same as the C function GDALFlushRasterCache().
1638 : *
1639 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1640 : * @return CE_None on success.
1641 : */
1642 :
1643 5918290 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1644 :
1645 : {
1646 6031920 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1647 113634 : poBandBlockCache)
1648 2538 : poBandBlockCache->DisableDirtyBlockWriting();
1649 :
1650 5914070 : CPLErr eGlobalErr = eFlushBlockErr;
1651 :
1652 5914070 : if (eFlushBlockErr != CE_None)
1653 : {
1654 0 : ReportError(
1655 : eFlushBlockErr, CPLE_AppDefined,
1656 : "An error occurred while writing a dirty block from FlushCache");
1657 0 : eFlushBlockErr = CE_None;
1658 : }
1659 :
1660 5914070 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1661 5149460 : return eGlobalErr;
1662 :
1663 764616 : return poBandBlockCache->FlushCache();
1664 : }
1665 :
1666 : /************************************************************************/
1667 : /* GDALFlushRasterCache() */
1668 : /************************************************************************/
1669 :
1670 : /**
1671 : * \brief Flush raster data cache.
1672 : *
1673 : * @see GDALRasterBand::FlushCache()
1674 : */
1675 :
1676 133 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1677 :
1678 : {
1679 133 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1680 :
1681 133 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1682 : }
1683 :
1684 : /************************************************************************/
1685 : /* DropCache() */
1686 : /************************************************************************/
1687 :
1688 : /**
1689 : * \brief Drop raster data cache : data in cache will be lost.
1690 : *
1691 : * This call will recover memory used to cache data blocks for this raster
1692 : * band, and ensure that new requests are referred to the underlying driver.
1693 : *
1694 : * This method is the same as the C function GDALDropRasterCache().
1695 : *
1696 : * @return CE_None on success.
1697 : * @since 3.9
1698 : */
1699 :
1700 1 : CPLErr GDALRasterBand::DropCache()
1701 :
1702 : {
1703 1 : CPLErr result = CE_None;
1704 :
1705 1 : if (poBandBlockCache)
1706 1 : poBandBlockCache->DisableDirtyBlockWriting();
1707 :
1708 1 : CPLErr eGlobalErr = eFlushBlockErr;
1709 :
1710 1 : if (eFlushBlockErr != CE_None)
1711 : {
1712 0 : ReportError(
1713 : eFlushBlockErr, CPLE_AppDefined,
1714 : "An error occurred while writing a dirty block from DropCache");
1715 0 : eFlushBlockErr = CE_None;
1716 : }
1717 :
1718 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1719 0 : result = eGlobalErr;
1720 : else
1721 1 : result = poBandBlockCache->FlushCache();
1722 :
1723 1 : if (poBandBlockCache)
1724 1 : poBandBlockCache->EnableDirtyBlockWriting();
1725 :
1726 1 : return result;
1727 : }
1728 :
1729 : /************************************************************************/
1730 : /* GDALDropRasterCache() */
1731 : /************************************************************************/
1732 :
1733 : /**
1734 : * \brief Drop raster data cache.
1735 : *
1736 : * @see GDALRasterBand::DropCache()
1737 : * @since 3.9
1738 : */
1739 :
1740 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1741 :
1742 : {
1743 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1744 :
1745 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1746 : }
1747 :
1748 : /************************************************************************/
1749 : /* UnreferenceBlock() */
1750 : /* */
1751 : /* Unreference the block from our array of blocks */
1752 : /* This method should only be called by */
1753 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1754 : /* the block cache mutex) */
1755 : /************************************************************************/
1756 :
1757 29653 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1758 : {
1759 : #ifdef notdef
1760 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1761 : {
1762 : if (poBandBlockCache == nullptr)
1763 : printf("poBandBlockCache == NULL\n"); /*ok*/
1764 : else
1765 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1766 : printf("caller = %s\n", pszCaller); /*ok*/
1767 : printf("GDALRasterBand: %p\n", this); /*ok*/
1768 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1769 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1770 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1771 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1772 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1773 : poBlock->DumpBlock();
1774 : if (GetDataset() != nullptr)
1775 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1776 : GDALRasterBlock::Verify();
1777 : abort();
1778 : }
1779 : #endif
1780 29653 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1781 29653 : return poBandBlockCache->UnreferenceBlock(poBlock);
1782 : }
1783 :
1784 : /************************************************************************/
1785 : /* AddBlockToFreeList() */
1786 : /* */
1787 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1788 : /* finished with a block about to be free'd, they pass it to that */
1789 : /* method. */
1790 : /************************************************************************/
1791 :
1792 : //! @cond Doxygen_Suppress
1793 29652 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1794 : {
1795 29652 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1796 29653 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1797 : }
1798 :
1799 : //! @endcond
1800 :
1801 : /************************************************************************/
1802 : /* FlushBlock() */
1803 : /************************************************************************/
1804 :
1805 : /** Flush a block out of the block cache.
1806 : * @param nXBlockOff block x offset
1807 : * @param nYBlockOff blocky offset
1808 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1809 : * @return CE_None in case of success, an error code otherwise.
1810 : */
1811 2310 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1812 : int bWriteDirtyBlock)
1813 :
1814 : {
1815 2310 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1816 0 : return (CE_Failure);
1817 :
1818 : /* -------------------------------------------------------------------- */
1819 : /* Validate the request */
1820 : /* -------------------------------------------------------------------- */
1821 2310 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1822 : {
1823 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1824 : "Illegal nBlockXOff value (%d) in "
1825 : "GDALRasterBand::FlushBlock()\n",
1826 : nXBlockOff);
1827 :
1828 0 : return (CE_Failure);
1829 : }
1830 :
1831 2310 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1832 : {
1833 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1834 : "Illegal nBlockYOff value (%d) in "
1835 : "GDALRasterBand::FlushBlock()\n",
1836 : nYBlockOff);
1837 :
1838 0 : return (CE_Failure);
1839 : }
1840 :
1841 2310 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1842 2310 : bWriteDirtyBlock);
1843 : }
1844 :
1845 : /************************************************************************/
1846 : /* TryGetLockedBlockRef() */
1847 : /************************************************************************/
1848 :
1849 : /**
1850 : * \brief Try fetching block ref.
1851 : *
1852 : * This method will returned the requested block (locked) if it is already
1853 : * in the block cache for the layer. If not, nullptr is returned.
1854 : *
1855 : * If a non-NULL value is returned, then a lock for the block will have been
1856 : * acquired on behalf of the caller. It is absolutely imperative that the
1857 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1858 : * severe problems may result.
1859 : *
1860 : * @param nXBlockOff the horizontal block offset, with zero indicating
1861 : * the left most block, 1 the next block and so forth.
1862 : *
1863 : * @param nYBlockOff the vertical block offset, with zero indicating
1864 : * the top most block, 1 the next block and so forth.
1865 : *
1866 : * @return NULL if block not available, or locked block pointer.
1867 : */
1868 :
1869 10626700 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1870 : int nYBlockOff)
1871 :
1872 : {
1873 10626700 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1874 170310 : return nullptr;
1875 :
1876 : /* -------------------------------------------------------------------- */
1877 : /* Validate the request */
1878 : /* -------------------------------------------------------------------- */
1879 10456500 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1880 : {
1881 178 : ReportError(CE_Failure, CPLE_IllegalArg,
1882 : "Illegal nBlockXOff value (%d) in "
1883 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1884 : nXBlockOff);
1885 :
1886 0 : return (nullptr);
1887 : }
1888 :
1889 10456300 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1890 : {
1891 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1892 : "Illegal nBlockYOff value (%d) in "
1893 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1894 : nYBlockOff);
1895 :
1896 0 : return (nullptr);
1897 : }
1898 :
1899 10456300 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1900 : }
1901 :
1902 : /************************************************************************/
1903 : /* GetLockedBlockRef() */
1904 : /************************************************************************/
1905 :
1906 : /**
1907 : * \brief Fetch a pointer to an internally cached raster block.
1908 : *
1909 : * This method will returned the requested block (locked) if it is already
1910 : * in the block cache for the layer. If not, the block will be read from
1911 : * the driver, and placed in the layer block cached, then returned. If an
1912 : * error occurs reading the block from the driver, a NULL value will be
1913 : * returned.
1914 : *
1915 : * If a non-NULL value is returned, then a lock for the block will have been
1916 : * acquired on behalf of the caller. It is absolutely imperative that the
1917 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1918 : * severe problems may result.
1919 : *
1920 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1921 : * enable caching.
1922 : *
1923 : * @param nXBlockOff the horizontal block offset, with zero indicating
1924 : * the left most block, 1 the next block and so forth.
1925 : *
1926 : * @param nYBlockOff the vertical block offset, with zero indicating
1927 : * the top most block, 1 the next block and so forth.
1928 : *
1929 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1930 : * but not actually read from the source. This is useful when it will just
1931 : * be completely set and written back.
1932 : *
1933 : * @return pointer to the block object, or NULL on failure.
1934 : */
1935 :
1936 10318500 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1937 : int nYBlockOff,
1938 : int bJustInitialize)
1939 :
1940 : {
1941 : /* -------------------------------------------------------------------- */
1942 : /* Try and fetch from cache. */
1943 : /* -------------------------------------------------------------------- */
1944 10318500 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1945 :
1946 : /* -------------------------------------------------------------------- */
1947 : /* If we didn't find it in our memory cache, instantiate a */
1948 : /* block (potentially load from disk) and "adopt" it into the */
1949 : /* cache. */
1950 : /* -------------------------------------------------------------------- */
1951 10318500 : if (poBlock == nullptr)
1952 : {
1953 3362730 : if (!InitBlockInfo())
1954 0 : return (nullptr);
1955 :
1956 : /* --------------------------------------------------------------------
1957 : */
1958 : /* Validate the request */
1959 : /* --------------------------------------------------------------------
1960 : */
1961 3362870 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1962 : {
1963 49 : ReportError(CE_Failure, CPLE_IllegalArg,
1964 : "Illegal nBlockXOff value (%d) in "
1965 : "GDALRasterBand::GetLockedBlockRef()\n",
1966 : nXBlockOff);
1967 :
1968 0 : return (nullptr);
1969 : }
1970 :
1971 3362820 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1972 : {
1973 21 : ReportError(CE_Failure, CPLE_IllegalArg,
1974 : "Illegal nBlockYOff value (%d) in "
1975 : "GDALRasterBand::GetLockedBlockRef()\n",
1976 : nYBlockOff);
1977 :
1978 0 : return (nullptr);
1979 : }
1980 :
1981 3362800 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1982 3362800 : if (poBlock == nullptr)
1983 0 : return nullptr;
1984 :
1985 3362800 : poBlock->AddLock();
1986 :
1987 : /* We need to temporarily drop the read-write lock in the following */
1988 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
1989 : */
1990 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
1991 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
1992 : */
1993 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
1994 : */
1995 : /* called and attempt at taking the lock on T2 (already taken).
1996 : * Similarly */
1997 : /* for T2 with D1, hence a deadlock situation (#6163) */
1998 : /* But this may open the door to other problems... */
1999 3362780 : if (poDS)
2000 3362030 : poDS->TemporarilyDropReadWriteLock();
2001 : /* allocate data space */
2002 3362830 : CPLErr eErr = poBlock->Internalize();
2003 3362870 : if (poDS)
2004 3362090 : poDS->ReacquireReadWriteLock();
2005 3362790 : if (eErr != CE_None)
2006 : {
2007 0 : poBlock->DropLock();
2008 0 : delete poBlock;
2009 0 : return nullptr;
2010 : }
2011 :
2012 3362790 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2013 : {
2014 0 : poBlock->DropLock();
2015 0 : delete poBlock;
2016 0 : return nullptr;
2017 : }
2018 :
2019 3362790 : if (!bJustInitialize)
2020 : {
2021 2901300 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2022 2901350 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2023 2901310 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2024 2901430 : if (bCallLeaveReadWrite)
2025 129988 : LeaveReadWrite();
2026 2901350 : if (eErr != CE_None)
2027 : {
2028 1160 : poBlock->DropLock();
2029 1160 : FlushBlock(nXBlockOff, nYBlockOff);
2030 1160 : ReportError(CE_Failure, CPLE_AppDefined,
2031 : "IReadBlock failed at X offset %d, Y offset %d%s",
2032 : nXBlockOff, nYBlockOff,
2033 1160 : (nErrorCounter != CPLGetErrorCounter())
2034 1158 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2035 : : "");
2036 1160 : return nullptr;
2037 : }
2038 :
2039 2900190 : nBlockReads++;
2040 2900190 : if (static_cast<GIntBig>(nBlockReads) ==
2041 2900190 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2042 219 : 1 &&
2043 219 : nBand == 1 && poDS != nullptr)
2044 : {
2045 159 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2046 159 : poDS->GetDescription());
2047 : }
2048 : }
2049 : }
2050 :
2051 10317400 : return poBlock;
2052 : }
2053 :
2054 : /************************************************************************/
2055 : /* Fill() */
2056 : /************************************************************************/
2057 :
2058 : /**
2059 : * \brief Fill this band with a constant value.
2060 : *
2061 : * GDAL makes no guarantees
2062 : * about what values pixels in newly created files are set to, so this
2063 : * method can be used to clear a band to a specified "default" value.
2064 : * The fill value is passed in as a double but this will be converted
2065 : * to the underlying type before writing to the file. An optional
2066 : * second argument allows the imaginary component of a complex
2067 : * constant value to be specified.
2068 : *
2069 : * This method is the same as the C function GDALFillRaster().
2070 : *
2071 : * @param dfRealValue Real component of fill value
2072 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2073 : *
2074 : * @return CE_Failure if the write fails, otherwise CE_None
2075 : */
2076 268271 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2077 : {
2078 :
2079 : // General approach is to construct a source block of the file's
2080 : // native type containing the appropriate value and then copy this
2081 : // to each block in the image via the RasterBlock cache. Using
2082 : // the cache means we avoid file I/O if it is not necessary, at the
2083 : // expense of some extra memcpy's (since we write to the
2084 : // RasterBlock cache, which is then at some point written to the
2085 : // underlying file, rather than simply directly to the underlying
2086 : // file.)
2087 :
2088 : // Check we can write to the file.
2089 268271 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2090 : {
2091 6 : return CE_Failure;
2092 : }
2093 :
2094 : // Make sure block parameters are set.
2095 268265 : if (!InitBlockInfo())
2096 0 : return CE_Failure;
2097 :
2098 : // Allocate the source block.
2099 268265 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2100 268265 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2101 268265 : auto blockByteSize = blockSize * elementSize;
2102 : unsigned char *srcBlock =
2103 268265 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2104 268265 : if (srcBlock == nullptr)
2105 : {
2106 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2107 : "GDALRasterBand::Fill(): Out of memory "
2108 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2109 : static_cast<GUIntBig>(blockByteSize));
2110 0 : return CE_Failure;
2111 : }
2112 :
2113 : // Initialize the source block.
2114 268265 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2115 268265 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2116 : elementSize, blockSize);
2117 :
2118 268265 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2119 :
2120 : // Write block to block cache
2121 848582 : for (int j = 0; j < nBlocksPerColumn; ++j)
2122 : {
2123 1454970 : for (int i = 0; i < nBlocksPerRow; ++i)
2124 : {
2125 874650 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2126 874650 : if (destBlock == nullptr)
2127 : {
2128 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2129 : "GDALRasterBand::Fill(): Error "
2130 : "while retrieving cache block.");
2131 0 : VSIFree(srcBlock);
2132 0 : return CE_Failure;
2133 : }
2134 874650 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2135 874650 : destBlock->MarkDirty();
2136 874650 : destBlock->DropLock();
2137 : }
2138 : }
2139 :
2140 268265 : if (bCallLeaveReadWrite)
2141 267628 : LeaveReadWrite();
2142 :
2143 : // Free up the source block
2144 268265 : VSIFree(srcBlock);
2145 :
2146 268265 : return CE_None;
2147 : }
2148 :
2149 : /************************************************************************/
2150 : /* GDALFillRaster() */
2151 : /************************************************************************/
2152 :
2153 : /**
2154 : * \brief Fill this band with a constant value.
2155 : *
2156 : * @see GDALRasterBand::Fill()
2157 : */
2158 268208 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2159 : double dfImaginaryValue)
2160 : {
2161 268208 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2162 :
2163 268208 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2164 268208 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2165 : }
2166 :
2167 : /************************************************************************/
2168 : /* GetAccess() */
2169 : /************************************************************************/
2170 :
2171 : /**
2172 : * \brief Find out if we have update permission for this band.
2173 : *
2174 : * This method is the same as the C function GDALGetRasterAccess().
2175 : *
2176 : * @return Either GA_Update or GA_ReadOnly.
2177 : */
2178 :
2179 2762 : GDALAccess GDALRasterBand::GetAccess()
2180 :
2181 : {
2182 2762 : return eAccess;
2183 : }
2184 :
2185 : /************************************************************************/
2186 : /* GDALGetRasterAccess() */
2187 : /************************************************************************/
2188 :
2189 : /**
2190 : * \brief Find out if we have update permission for this band.
2191 : *
2192 : * @see GDALRasterBand::GetAccess()
2193 : */
2194 :
2195 2113 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2196 :
2197 : {
2198 2113 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2199 :
2200 2113 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2201 2113 : return poBand->GetAccess();
2202 : }
2203 :
2204 : /************************************************************************/
2205 : /* GetCategoryNames() */
2206 : /************************************************************************/
2207 :
2208 : /**
2209 : * \brief Fetch the list of category names for this raster.
2210 : *
2211 : * The return list is a "StringList" in the sense of the CPL functions.
2212 : * That is a NULL terminated array of strings. Raster values without
2213 : * associated names will have an empty string in the returned list. The
2214 : * first entry in the list is for raster values of zero, and so on.
2215 : *
2216 : * The returned stringlist should not be altered or freed by the application.
2217 : * It may change on the next GDAL call, so please copy it if it is needed
2218 : * for any period of time.
2219 : *
2220 : * This method is the same as the C function GDALGetRasterCategoryNames().
2221 : *
2222 : * @return list of names, or NULL if none.
2223 : */
2224 :
2225 294 : char **GDALRasterBand::GetCategoryNames()
2226 :
2227 : {
2228 294 : return nullptr;
2229 : }
2230 :
2231 : /************************************************************************/
2232 : /* GDALGetRasterCategoryNames() */
2233 : /************************************************************************/
2234 :
2235 : /**
2236 : * \brief Fetch the list of category names for this raster.
2237 : *
2238 : * @see GDALRasterBand::GetCategoryNames()
2239 : */
2240 :
2241 186 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2242 :
2243 : {
2244 186 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2245 :
2246 186 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2247 186 : return poBand->GetCategoryNames();
2248 : }
2249 :
2250 : /************************************************************************/
2251 : /* SetCategoryNames() */
2252 : /************************************************************************/
2253 :
2254 : /**
2255 : * \fn GDALRasterBand::SetCategoryNames(char**)
2256 : * \brief Set the category names for this band.
2257 : *
2258 : * See the GetCategoryNames() method for more on the interpretation of
2259 : * category names.
2260 : *
2261 : * This method is the same as the C function GDALSetRasterCategoryNames().
2262 : *
2263 : * @param papszNames the NULL terminated StringList of category names. May
2264 : * be NULL to just clear the existing list.
2265 : *
2266 : * @return CE_None on success of CE_Failure on failure. If unsupported
2267 : * by the driver CE_Failure is returned, but no error message is reported.
2268 : */
2269 :
2270 : /**/
2271 : /**/
2272 :
2273 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2274 : {
2275 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2276 0 : ReportError(CE_Failure, CPLE_NotSupported,
2277 : "SetCategoryNames() not supported for this dataset.");
2278 :
2279 0 : return CE_Failure;
2280 : }
2281 :
2282 : /************************************************************************/
2283 : /* GDALSetCategoryNames() */
2284 : /************************************************************************/
2285 :
2286 : /**
2287 : * \brief Set the category names for this band.
2288 : *
2289 : * @see GDALRasterBand::SetCategoryNames()
2290 : */
2291 :
2292 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2293 : CSLConstList papszNames)
2294 :
2295 : {
2296 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2297 :
2298 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2299 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2300 : }
2301 :
2302 : /************************************************************************/
2303 : /* GetNoDataValue() */
2304 : /************************************************************************/
2305 :
2306 : /**
2307 : * \brief Fetch the no data value for this band.
2308 : *
2309 : * If there is no out of data value, an out of range value will generally
2310 : * be returned. The no data value for a band is generally a special marker
2311 : * value used to mark pixels that are not valid data. Such pixels should
2312 : * generally not be displayed, nor contribute to analysis operations.
2313 : *
2314 : * The no data value returned is 'raw', meaning that it has no offset and
2315 : * scale applied.
2316 : *
2317 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2318 : * lossy if the nodata value cannot exactly been represented by a double.
2319 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2320 : *
2321 : * This method is the same as the C function GDALGetRasterNoDataValue().
2322 : *
2323 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2324 : * is actually associated with this layer. May be NULL (default).
2325 : *
2326 : * @return the nodata value for this band.
2327 : */
2328 :
2329 31573 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2330 :
2331 : {
2332 31573 : if (pbSuccess != nullptr)
2333 31573 : *pbSuccess = FALSE;
2334 :
2335 31573 : return -1e10;
2336 : }
2337 :
2338 : /************************************************************************/
2339 : /* GDALGetRasterNoDataValue() */
2340 : /************************************************************************/
2341 :
2342 : /**
2343 : * \brief Fetch the no data value for this band.
2344 : *
2345 : * @see GDALRasterBand::GetNoDataValue()
2346 : */
2347 :
2348 414233 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2349 : int *pbSuccess)
2350 :
2351 : {
2352 414233 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2353 :
2354 414233 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2355 414233 : return poBand->GetNoDataValue(pbSuccess);
2356 : }
2357 :
2358 : /************************************************************************/
2359 : /* GetNoDataValueAsInt64() */
2360 : /************************************************************************/
2361 :
2362 : /**
2363 : * \brief Fetch the no data value for this band.
2364 : *
2365 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2366 : *
2367 : * If there is no out of data value, an out of range value will generally
2368 : * be returned. The no data value for a band is generally a special marker
2369 : * value used to mark pixels that are not valid data. Such pixels should
2370 : * generally not be displayed, nor contribute to analysis operations.
2371 : *
2372 : * The no data value returned is 'raw', meaning that it has no offset and
2373 : * scale applied.
2374 : *
2375 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2376 : *
2377 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2378 : * is actually associated with this layer. May be NULL (default).
2379 : *
2380 : * @return the nodata value for this band.
2381 : *
2382 : * @since GDAL 3.5
2383 : */
2384 :
2385 4 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2386 :
2387 : {
2388 4 : if (pbSuccess != nullptr)
2389 4 : *pbSuccess = FALSE;
2390 :
2391 4 : return std::numeric_limits<int64_t>::min();
2392 : }
2393 :
2394 : /************************************************************************/
2395 : /* GDALGetRasterNoDataValueAsInt64() */
2396 : /************************************************************************/
2397 :
2398 : /**
2399 : * \brief Fetch the no data value for this band.
2400 : *
2401 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2402 : *
2403 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2404 : *
2405 : * @since GDAL 3.5
2406 : */
2407 :
2408 27 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2409 : int *pbSuccess)
2410 :
2411 : {
2412 27 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2413 : std::numeric_limits<int64_t>::min());
2414 :
2415 27 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2416 27 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2417 : }
2418 :
2419 : /************************************************************************/
2420 : /* GetNoDataValueAsUInt64() */
2421 : /************************************************************************/
2422 :
2423 : /**
2424 : * \brief Fetch the no data value for this band.
2425 : *
2426 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2427 : *
2428 : * If there is no out of data value, an out of range value will generally
2429 : * be returned. The no data value for a band is generally a special marker
2430 : * value used to mark pixels that are not valid data. Such pixels should
2431 : * generally not be displayed, nor contribute to analysis operations.
2432 : *
2433 : * The no data value returned is 'raw', meaning that it has no offset and
2434 : * scale applied.
2435 : *
2436 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2437 : *
2438 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2439 : * is actually associated with this layer. May be NULL (default).
2440 : *
2441 : * @return the nodata value for this band.
2442 : *
2443 : * @since GDAL 3.5
2444 : */
2445 :
2446 3 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2447 :
2448 : {
2449 3 : if (pbSuccess != nullptr)
2450 3 : *pbSuccess = FALSE;
2451 :
2452 3 : return std::numeric_limits<uint64_t>::max();
2453 : }
2454 :
2455 : /************************************************************************/
2456 : /* GDALGetRasterNoDataValueAsUInt64() */
2457 : /************************************************************************/
2458 :
2459 : /**
2460 : * \brief Fetch the no data value for this band.
2461 : *
2462 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2463 : *
2464 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2465 : *
2466 : * @since GDAL 3.5
2467 : */
2468 :
2469 18 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2470 : int *pbSuccess)
2471 :
2472 : {
2473 18 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2474 : std::numeric_limits<uint64_t>::max());
2475 :
2476 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2477 18 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2478 : }
2479 :
2480 : /************************************************************************/
2481 : /* SetNoDataValueAsString() */
2482 : /************************************************************************/
2483 :
2484 : /**
2485 : * \brief Set the no data value for this band.
2486 : *
2487 : * Depending on drivers, changing the no data value may or may not have an
2488 : * effect on the pixel values of a raster that has just been created. It is
2489 : * thus advised to explicitly called Fill() if the intent is to initialize
2490 : * the raster to the nodata value.
2491 : * In any case, changing an existing no data value, when one already exists and
2492 : * the dataset exists or has been initialized, has no effect on the pixel whose
2493 : * value matched the previous nodata value.
2494 : *
2495 : * To clear the nodata value, use DeleteNoDataValue().
2496 : *
2497 : * @param pszNoData the value to set.
2498 : * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2499 : * If the value cannot be exactly represented on the output data
2500 : * type, *pbCannotBeExactlyRepresented will be set to true.
2501 : *
2502 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2503 : * by the driver, CE_Failure is returned but no error message will have
2504 : * been emitted.
2505 : *
2506 : * @since 3.11
2507 : */
2508 :
2509 : CPLErr
2510 123 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2511 : bool *pbCannotBeExactlyRepresented)
2512 : {
2513 123 : if (pbCannotBeExactlyRepresented)
2514 123 : *pbCannotBeExactlyRepresented = false;
2515 123 : if (eDataType == GDT_Int64)
2516 : {
2517 8 : if (strchr(pszNoData, '.') ||
2518 3 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2519 : {
2520 2 : char *endptr = nullptr;
2521 2 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2522 4 : if (endptr == pszNoData + strlen(pszNoData) &&
2523 2 : GDALIsValueExactAs<int64_t>(dfVal))
2524 : {
2525 0 : return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2526 : }
2527 : }
2528 : else
2529 : {
2530 : try
2531 : {
2532 7 : const auto val = std::stoll(pszNoData);
2533 1 : return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2534 : }
2535 2 : catch (const std::exception &)
2536 : {
2537 : }
2538 : }
2539 : }
2540 118 : else if (eDataType == GDT_UInt64)
2541 : {
2542 2 : if (strchr(pszNoData, '.') ||
2543 1 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2544 : {
2545 0 : char *endptr = nullptr;
2546 0 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2547 0 : if (endptr == pszNoData + strlen(pszNoData) &&
2548 0 : GDALIsValueExactAs<uint64_t>(dfVal))
2549 : {
2550 0 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2551 : }
2552 : }
2553 : else
2554 : {
2555 : try
2556 : {
2557 1 : const auto val = std::stoull(pszNoData);
2558 1 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2559 : }
2560 0 : catch (const std::exception &)
2561 : {
2562 : }
2563 : }
2564 : }
2565 117 : else if (eDataType == GDT_Float32)
2566 : {
2567 10 : char *endptr = nullptr;
2568 10 : const float fVal = CPLStrtof(pszNoData, &endptr);
2569 10 : if (endptr == pszNoData + strlen(pszNoData))
2570 : {
2571 10 : return SetNoDataValue(fVal);
2572 : }
2573 : }
2574 : else
2575 : {
2576 107 : char *endptr = nullptr;
2577 107 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2578 214 : if (endptr == pszNoData + strlen(pszNoData) &&
2579 107 : GDALIsValueExactAs(dfVal, eDataType))
2580 : {
2581 106 : return SetNoDataValue(dfVal);
2582 : }
2583 : }
2584 5 : if (pbCannotBeExactlyRepresented)
2585 5 : *pbCannotBeExactlyRepresented = true;
2586 5 : return CE_Failure;
2587 : }
2588 :
2589 : /************************************************************************/
2590 : /* SetNoDataValue() */
2591 : /************************************************************************/
2592 :
2593 : /**
2594 : * \fn GDALRasterBand::SetNoDataValue(double)
2595 : * \brief Set the no data value for this band.
2596 : *
2597 : * Depending on drivers, changing the no data value may or may not have an
2598 : * effect on the pixel values of a raster that has just been created. It is
2599 : * thus advised to explicitly called Fill() if the intent is to initialize
2600 : * the raster to the nodata value.
2601 : * In any case, changing an existing no data value, when one already exists and
2602 : * the dataset exists or has been initialized, has no effect on the pixel whose
2603 : * value matched the previous nodata value.
2604 : *
2605 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2606 : * be represented by a double, use SetNoDataValueAsInt64() or
2607 : * SetNoDataValueAsUInt64() instead.
2608 : *
2609 : * To clear the nodata value, use DeleteNoDataValue().
2610 : *
2611 : * This method is the same as the C function GDALSetRasterNoDataValue().
2612 : *
2613 : * @param dfNoData the value to set.
2614 : *
2615 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2616 : * by the driver, CE_Failure is returned but no error message will have
2617 : * been emitted.
2618 : */
2619 :
2620 : /**/
2621 : /**/
2622 :
2623 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2624 :
2625 : {
2626 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2627 0 : ReportError(CE_Failure, CPLE_NotSupported,
2628 : "SetNoDataValue() not supported for this dataset.");
2629 :
2630 0 : return CE_Failure;
2631 : }
2632 :
2633 : /************************************************************************/
2634 : /* GDALSetRasterNoDataValue() */
2635 : /************************************************************************/
2636 :
2637 : /**
2638 : * \brief Set the no data value for this band.
2639 : *
2640 : * Depending on drivers, changing the no data value may or may not have an
2641 : * effect on the pixel values of a raster that has just been created. It is
2642 : * thus advised to explicitly called Fill() if the intent is to initialize
2643 : * the raster to the nodata value.
2644 : * In any case, changing an existing no data value, when one already exists and
2645 : * the dataset exists or has been initialized, has no effect on the pixel whose
2646 : * value matched the previous nodata value.
2647 : *
2648 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2649 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2650 : * GDALSetRasterNoDataValueAsUInt64() instead.
2651 : *
2652 : * @see GDALRasterBand::SetNoDataValue()
2653 : */
2654 :
2655 848 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2656 : double dfValue)
2657 :
2658 : {
2659 848 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2660 :
2661 848 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2662 848 : return poBand->SetNoDataValue(dfValue);
2663 : }
2664 :
2665 : /************************************************************************/
2666 : /* SetNoDataValueAsInt64() */
2667 : /************************************************************************/
2668 :
2669 : /**
2670 : * \brief Set the no data value for this band.
2671 : *
2672 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2673 : *
2674 : * Depending on drivers, changing the no data value may or may not have an
2675 : * effect on the pixel values of a raster that has just been created. It is
2676 : * thus advised to explicitly called Fill() if the intent is to initialize
2677 : * the raster to the nodata value.
2678 : * In ay case, changing an existing no data value, when one already exists and
2679 : * the dataset exists or has been initialized, has no effect on the pixel whose
2680 : * value matched the previous nodata value.
2681 : *
2682 : * To clear the nodata value, use DeleteNoDataValue().
2683 : *
2684 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2685 : *
2686 : * @param nNoDataValue the value to set.
2687 : *
2688 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2689 : * by the driver, CE_Failure is returned but no error message will have
2690 : * been emitted.
2691 : *
2692 : * @since GDAL 3.5
2693 : */
2694 :
2695 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2696 :
2697 : {
2698 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2699 0 : ReportError(CE_Failure, CPLE_NotSupported,
2700 : "SetNoDataValueAsInt64() not supported for this dataset.");
2701 :
2702 0 : return CE_Failure;
2703 : }
2704 :
2705 : /************************************************************************/
2706 : /* GDALSetRasterNoDataValueAsInt64() */
2707 : /************************************************************************/
2708 :
2709 : /**
2710 : * \brief Set the no data value for this band.
2711 : *
2712 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2713 : *
2714 : * Depending on drivers, changing the no data value may or may not have an
2715 : * effect on the pixel values of a raster that has just been created. It is
2716 : * thus advised to explicitly called Fill() if the intent is to initialize
2717 : * the raster to the nodata value.
2718 : * In ay case, changing an existing no data value, when one already exists and
2719 : * the dataset exists or has been initialized, has no effect on the pixel whose
2720 : * value matched the previous nodata value.
2721 : *
2722 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2723 : *
2724 : * @since GDAL 3.5
2725 : */
2726 :
2727 19 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2728 : int64_t nValue)
2729 :
2730 : {
2731 19 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2732 :
2733 19 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2734 19 : return poBand->SetNoDataValueAsInt64(nValue);
2735 : }
2736 :
2737 : /************************************************************************/
2738 : /* SetNoDataValueAsUInt64() */
2739 : /************************************************************************/
2740 :
2741 : /**
2742 : * \brief Set the no data value for this band.
2743 : *
2744 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2745 : *
2746 : * Depending on drivers, changing the no data value may or may not have an
2747 : * effect on the pixel values of a raster that has just been created. It is
2748 : * thus advised to explicitly called Fill() if the intent is to initialize
2749 : * the raster to the nodata value.
2750 : * In ay case, changing an existing no data value, when one already exists and
2751 : * the dataset exists or has been initialized, has no effect on the pixel whose
2752 : * value matched the previous nodata value.
2753 : *
2754 : * To clear the nodata value, use DeleteNoDataValue().
2755 : *
2756 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2757 : *
2758 : * @param nNoDataValue the value to set.
2759 : *
2760 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2761 : * by the driver, CE_Failure is returned but no error message will have
2762 : * been emitted.
2763 : *
2764 : * @since GDAL 3.5
2765 : */
2766 :
2767 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2768 :
2769 : {
2770 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2771 0 : ReportError(CE_Failure, CPLE_NotSupported,
2772 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2773 :
2774 0 : return CE_Failure;
2775 : }
2776 :
2777 : /************************************************************************/
2778 : /* GDALSetRasterNoDataValueAsUInt64() */
2779 : /************************************************************************/
2780 :
2781 : /**
2782 : * \brief Set the no data value for this band.
2783 : *
2784 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2785 : *
2786 : * Depending on drivers, changing the no data value may or may not have an
2787 : * effect on the pixel values of a raster that has just been created. It is
2788 : * thus advised to explicitly called Fill() if the intent is to initialize
2789 : * the raster to the nodata value.
2790 : * In ay case, changing an existing no data value, when one already exists and
2791 : * the dataset exists or has been initialized, has no effect on the pixel whose
2792 : * value matched the previous nodata value.
2793 : *
2794 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2795 : *
2796 : * @since GDAL 3.5
2797 : */
2798 :
2799 17 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2800 : uint64_t nValue)
2801 :
2802 : {
2803 17 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2804 :
2805 17 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2806 17 : return poBand->SetNoDataValueAsUInt64(nValue);
2807 : }
2808 :
2809 : /************************************************************************/
2810 : /* DeleteNoDataValue() */
2811 : /************************************************************************/
2812 :
2813 : /**
2814 : * \brief Remove the no data value for this band.
2815 : *
2816 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2817 : *
2818 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2819 : * by the driver, CE_Failure is returned but no error message will have
2820 : * been emitted.
2821 : *
2822 : * @since GDAL 2.1
2823 : */
2824 :
2825 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2826 :
2827 : {
2828 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2829 0 : ReportError(CE_Failure, CPLE_NotSupported,
2830 : "DeleteNoDataValue() not supported for this dataset.");
2831 :
2832 0 : return CE_Failure;
2833 : }
2834 :
2835 : /************************************************************************/
2836 : /* GDALDeleteRasterNoDataValue() */
2837 : /************************************************************************/
2838 :
2839 : /**
2840 : * \brief Remove the no data value for this band.
2841 : *
2842 : * @see GDALRasterBand::DeleteNoDataValue()
2843 : *
2844 : * @since GDAL 2.1
2845 : */
2846 :
2847 53 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2848 :
2849 : {
2850 53 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2851 :
2852 53 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2853 53 : return poBand->DeleteNoDataValue();
2854 : }
2855 :
2856 : /************************************************************************/
2857 : /* GetMaximum() */
2858 : /************************************************************************/
2859 :
2860 : /**
2861 : * \brief Fetch the maximum value for this band.
2862 : *
2863 : * For file formats that don't know this intrinsically, the maximum supported
2864 : * value for the data type will generally be returned.
2865 : *
2866 : * This method is the same as the C function GDALGetRasterMaximum().
2867 : *
2868 : * @param pbSuccess pointer to a boolean to use to indicate if the
2869 : * returned value is a tight maximum or not. May be NULL (default).
2870 : *
2871 : * @return the maximum raster value (excluding no data pixels)
2872 : */
2873 :
2874 519 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2875 :
2876 : {
2877 519 : const char *pszValue = nullptr;
2878 :
2879 519 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2880 : {
2881 46 : if (pbSuccess != nullptr)
2882 41 : *pbSuccess = TRUE;
2883 :
2884 46 : return CPLAtofM(pszValue);
2885 : }
2886 :
2887 473 : if (pbSuccess != nullptr)
2888 469 : *pbSuccess = FALSE;
2889 :
2890 473 : switch (eDataType)
2891 : {
2892 323 : case GDT_Byte:
2893 : {
2894 323 : EnablePixelTypeSignedByteWarning(false);
2895 : const char *pszPixelType =
2896 323 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2897 323 : EnablePixelTypeSignedByteWarning(true);
2898 323 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2899 0 : return 127;
2900 :
2901 323 : return 255;
2902 : }
2903 :
2904 1 : case GDT_Int8:
2905 1 : return 127;
2906 :
2907 21 : case GDT_UInt16:
2908 21 : return 65535;
2909 :
2910 23 : case GDT_Int16:
2911 : case GDT_CInt16:
2912 23 : return 32767;
2913 :
2914 39 : case GDT_Int32:
2915 : case GDT_CInt32:
2916 39 : return 2147483647.0;
2917 :
2918 12 : case GDT_UInt32:
2919 12 : return 4294967295.0;
2920 :
2921 1 : case GDT_Int64:
2922 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2923 :
2924 1 : case GDT_UInt64:
2925 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2926 :
2927 0 : case GDT_Float16:
2928 : case GDT_CFloat16:
2929 0 : return 65504.0;
2930 :
2931 30 : case GDT_Float32:
2932 : case GDT_CFloat32:
2933 30 : return 4294967295.0; // Not actually accurate.
2934 :
2935 22 : case GDT_Float64:
2936 : case GDT_CFloat64:
2937 22 : return 4294967295.0; // Not actually accurate.
2938 :
2939 0 : case GDT_Unknown:
2940 : case GDT_TypeCount:
2941 0 : break;
2942 : }
2943 0 : return 4294967295.0; // Not actually accurate.
2944 : }
2945 :
2946 : /************************************************************************/
2947 : /* GDALGetRasterMaximum() */
2948 : /************************************************************************/
2949 :
2950 : /**
2951 : * \brief Fetch the maximum value for this band.
2952 : *
2953 : * @see GDALRasterBand::GetMaximum()
2954 : */
2955 :
2956 284 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2957 :
2958 : {
2959 284 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2960 :
2961 284 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2962 284 : return poBand->GetMaximum(pbSuccess);
2963 : }
2964 :
2965 : /************************************************************************/
2966 : /* GetMinimum() */
2967 : /************************************************************************/
2968 :
2969 : /**
2970 : * \brief Fetch the minimum value for this band.
2971 : *
2972 : * For file formats that don't know this intrinsically, the minimum supported
2973 : * value for the data type will generally be returned.
2974 : *
2975 : * This method is the same as the C function GDALGetRasterMinimum().
2976 : *
2977 : * @param pbSuccess pointer to a boolean to use to indicate if the
2978 : * returned value is a tight minimum or not. May be NULL (default).
2979 : *
2980 : * @return the minimum raster value (excluding no data pixels)
2981 : */
2982 :
2983 527 : double GDALRasterBand::GetMinimum(int *pbSuccess)
2984 :
2985 : {
2986 527 : const char *pszValue = nullptr;
2987 :
2988 527 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
2989 : {
2990 51 : if (pbSuccess != nullptr)
2991 46 : *pbSuccess = TRUE;
2992 :
2993 51 : return CPLAtofM(pszValue);
2994 : }
2995 :
2996 476 : if (pbSuccess != nullptr)
2997 472 : *pbSuccess = FALSE;
2998 :
2999 476 : switch (eDataType)
3000 : {
3001 326 : case GDT_Byte:
3002 : {
3003 326 : EnablePixelTypeSignedByteWarning(false);
3004 : const char *pszPixelType =
3005 326 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3006 326 : EnablePixelTypeSignedByteWarning(true);
3007 326 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3008 0 : return -128;
3009 :
3010 326 : return 0;
3011 : }
3012 :
3013 1 : case GDT_Int8:
3014 1 : return -128;
3015 : break;
3016 :
3017 21 : case GDT_UInt16:
3018 21 : return 0;
3019 :
3020 23 : case GDT_Int16:
3021 : case GDT_CInt16:
3022 23 : 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 294 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3067 :
3068 : {
3069 294 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3070 :
3071 294 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3072 294 : 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 5430 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3109 :
3110 : {
3111 5430 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3112 :
3113 5430 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3114 5430 : 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 1818 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3155 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3156 :
3157 : {
3158 1818 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3159 :
3160 1818 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3161 1818 : 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 231 : GDALColorTable *GDALRasterBand::GetColorTable()
3181 :
3182 : {
3183 231 : 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 1889 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3197 :
3198 : {
3199 1889 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3200 :
3201 1889 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3202 1889 : 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 77 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3249 : GDALColorTableH hCT)
3250 :
3251 : {
3252 77 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3253 :
3254 77 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3255 77 : 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 254 : int GDALRasterBand::HasArbitraryOverviews()
3278 :
3279 : {
3280 254 : return FALSE;
3281 : }
3282 :
3283 : /************************************************************************/
3284 : /* GDALHasArbitraryOverviews() */
3285 : /************************************************************************/
3286 :
3287 : /**
3288 : * \brief Check for arbitrary overviews.
3289 : *
3290 : * @see GDALRasterBand::HasArbitraryOverviews()
3291 : */
3292 :
3293 176 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3294 :
3295 : {
3296 176 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3297 :
3298 176 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3299 176 : 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 1065570 : int GDALRasterBand::GetOverviewCount()
3315 :
3316 : {
3317 1721990 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3318 656414 : poDS->AreOverviewsEnabled())
3319 656414 : return poDS->oOvManager.GetOverviewCount(nBand);
3320 :
3321 409158 : 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 3278 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3335 :
3336 : {
3337 3278 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3338 :
3339 3278 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3340 3278 : 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 844 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3358 :
3359 : {
3360 1633 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3361 789 : poDS->AreOverviewsEnabled())
3362 789 : return poDS->oOvManager.GetOverview(nBand, i);
3363 :
3364 55 : 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 5654 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3378 :
3379 : {
3380 5654 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3381 :
3382 5654 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3383 5654 : 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 460 : double GDALRasterBand::GetOffset(int *pbSuccess)
3559 :
3560 : {
3561 460 : if (pbSuccess != nullptr)
3562 351 : *pbSuccess = FALSE;
3563 :
3564 460 : 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 380 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3578 :
3579 : {
3580 380 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3581 :
3582 380 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3583 380 : 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 460 : double GDALRasterBand::GetScale(int *pbSuccess)
3665 :
3666 : {
3667 460 : if (pbSuccess != nullptr)
3668 351 : *pbSuccess = FALSE;
3669 :
3670 460 : 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 378 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3684 :
3685 : {
3686 378 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3687 :
3688 378 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3689 378 : 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 1421 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3776 :
3777 : {
3778 1421 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3779 :
3780 1421 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3781 1421 : 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 8423410 : int GDALRasterBand::GetXSize() const
3851 :
3852 : {
3853 8423410 : return nRasterXSize;
3854 : }
3855 :
3856 : /************************************************************************/
3857 : /* GDALGetRasterBandXSize() */
3858 : /************************************************************************/
3859 :
3860 : /**
3861 : * \brief Fetch XSize of raster.
3862 : *
3863 : * @see GDALRasterBand::GetXSize()
3864 : */
3865 :
3866 57488 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3867 :
3868 : {
3869 57488 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3870 :
3871 57488 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3872 57488 : 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 4628220 : int GDALRasterBand::GetYSize() const
3888 :
3889 : {
3890 4628220 : return nRasterYSize;
3891 : }
3892 :
3893 : /************************************************************************/
3894 : /* GDALGetRasterBandYSize() */
3895 : /************************************************************************/
3896 :
3897 : /**
3898 : * \brief Fetch YSize of raster.
3899 : *
3900 : * @see GDALRasterBand::GetYSize()
3901 : */
3902 :
3903 56347 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3904 :
3905 : {
3906 56347 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3907 :
3908 56347 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3909 56347 : 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 151344 : int GDALRasterBand::GetBand() const
3930 :
3931 : {
3932 151344 : return nBand;
3933 : }
3934 :
3935 : /************************************************************************/
3936 : /* GDALGetBandNumber() */
3937 : /************************************************************************/
3938 :
3939 : /**
3940 : * \brief Fetch the band number.
3941 : *
3942 : * @see GDALRasterBand::GetBand()
3943 : */
3944 :
3945 202 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3946 :
3947 : {
3948 202 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3949 :
3950 202 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3951 202 : 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 5265150 : GDALDataset *GDALRasterBand::GetDataset() const
3971 :
3972 : {
3973 5265150 : 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 2215 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4000 : double dfNoDataValue,
4001 : int &bGotNoDataValue,
4002 : GFloat16 &fNoDataValue,
4003 : bool &bGotFloat16NoDataValue)
4004 : {
4005 2215 : 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 2215 : }
4016 :
4017 : /************************************************************************/
4018 : /* ComputeFloatNoDataValue() */
4019 : /************************************************************************/
4020 :
4021 2215 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4022 : double dfNoDataValue,
4023 : int &bGotNoDataValue,
4024 : float &fNoDataValue,
4025 : bool &bGotFloatNoDataValue)
4026 : {
4027 2215 : if (eDataType == GDT_Float32 && bGotNoDataValue)
4028 : {
4029 84 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4030 84 : if (GDALIsValueInRange<float>(dfNoDataValue))
4031 : {
4032 84 : fNoDataValue = static_cast<float>(dfNoDataValue);
4033 84 : bGotFloatNoDataValue = true;
4034 84 : bGotNoDataValue = false;
4035 : }
4036 : }
4037 2215 : }
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 2259 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4069 2259 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4070 : bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4071 : bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4072 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4073 2259 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4074 : {
4075 2259 : 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 2231 : 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 2215 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4110 2215 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4111 :
4112 2215 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4113 2215 : fNoDataValue, bGotFloatNoDataValue);
4114 :
4115 2215 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4116 2215 : hfNoDataValue, bGotFloat16NoDataValue);
4117 : }
4118 2259 : }
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 40 : 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 40 : CPLAssert(nullptr != panHistogram);
4184 :
4185 40 : if (pfnProgress == nullptr)
4186 27 : pfnProgress = GDALDummyProgress;
4187 :
4188 : /* -------------------------------------------------------------------- */
4189 : /* If we have overviews, use them for the histogram. */
4190 : /* -------------------------------------------------------------------- */
4191 40 : 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 40 : 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 40 : 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 35 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4225 :
4226 35 : const double dfScale = nBuckets / (dfMax - dfMin);
4227 35 : 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 30 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4235 :
4236 30 : GDALNoDataValues sNoDataValues(this, eDataType);
4237 30 : GDALRasterBand *poMaskBand = nullptr;
4238 30 : if (!sNoDataValues.bGotNoDataValue)
4239 : {
4240 29 : const int l_nMaskFlags = GetMaskFlags();
4241 31 : if (l_nMaskFlags != GMF_ALL_VALID &&
4242 2 : GetColorInterpretation() != GCI_AlphaBand)
4243 : {
4244 2 : poMaskBand = GetMaskBand();
4245 : }
4246 : }
4247 :
4248 30 : bool bSignedByte = false;
4249 30 : 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 30 : 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 = 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 : static_cast<float *>(pData)[iOffset * 2];
4432 0 : const double dfImag =
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 30 : 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 30 : int nSampleRate = 1;
4497 30 : 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 30 : GByte *pabyMaskData = nullptr;
4510 30 : 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 30 : for (GIntBig iSampleBlock = 0;
4526 150 : iSampleBlock <
4527 150 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4528 120 : iSampleBlock += nSampleRate)
4529 : {
4530 120 : if (!pfnProgress(
4531 120 : static_cast<double>(iSampleBlock) /
4532 120 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4533 : "Compute Histogram", pProgressData))
4534 : {
4535 0 : CPLFree(pabyMaskData);
4536 0 : return CE_Failure;
4537 : }
4538 :
4539 120 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4540 120 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4541 :
4542 120 : int nXCheck = 0, nYCheck = 0;
4543 120 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4544 :
4545 122 : 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 120 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4556 120 : if (poBlock == nullptr)
4557 : {
4558 0 : CPLFree(pabyMaskData);
4559 0 : return CE_Failure;
4560 : }
4561 :
4562 120 : void *pData = poBlock->GetDataRef();
4563 :
4564 : // this is a special case for a common situation.
4565 120 : 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 253 : for (int iY = 0; iY < nYCheck; iY++)
4591 : {
4592 36385 : for (int iX = 0; iX < nXCheck; iX++)
4593 : {
4594 36169 : const GPtrDiff_t iOffset =
4595 36169 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4596 :
4597 36169 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4598 2 : continue;
4599 :
4600 36167 : double dfValue = 0.0;
4601 :
4602 36167 : 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 0 : case GDT_Int8:
4614 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4615 0 : break;
4616 16384 : case GDT_UInt16:
4617 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4618 16384 : break;
4619 2 : case GDT_Int16:
4620 2 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4621 2 : 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 = 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 =
4698 0 : static_cast<float *>(pData)[iOffset * 2];
4699 0 : double dfImag =
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 36167 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4725 72334 : 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 36167 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4733 :
4734 36167 : if (dfIndex < 0)
4735 : {
4736 1 : if (bIncludeOutOfRange)
4737 1 : panHistogram[0]++;
4738 : }
4739 36166 : else if (dfIndex >= nBuckets)
4740 : {
4741 7 : if (bIncludeOutOfRange)
4742 4 : ++panHistogram[nBuckets - 1];
4743 : }
4744 : else
4745 : {
4746 36159 : ++panHistogram[static_cast<int>(dfIndex)];
4747 : }
4748 : }
4749 : }
4750 :
4751 37 : poBlock->DropLock();
4752 : }
4753 :
4754 30 : CPLFree(pabyMaskData);
4755 : }
4756 :
4757 30 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4758 :
4759 30 : 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 22 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4887 : int *pnBuckets,
4888 : GUIntBig **ppanHistogram, int bForce,
4889 : GDALProgressFunc pfnProgress,
4890 : void *pProgressData)
4891 :
4892 : {
4893 22 : CPLAssert(nullptr != pnBuckets);
4894 22 : CPLAssert(nullptr != ppanHistogram);
4895 22 : CPLAssert(nullptr != pdfMin);
4896 22 : CPLAssert(nullptr != pdfMax);
4897 :
4898 22 : *pnBuckets = 0;
4899 22 : *ppanHistogram = nullptr;
4900 :
4901 22 : if (!bForce)
4902 5 : return CE_Warning;
4903 :
4904 17 : const int nBuckets = 256;
4905 :
4906 17 : bool bSignedByte = false;
4907 17 : 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 17 : if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4918 : {
4919 17 : *pdfMin = -0.5;
4920 17 : *pdfMax = 255.5;
4921 : }
4922 : else
4923 : {
4924 :
4925 : const CPLErr eErr =
4926 0 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4927 0 : const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4928 0 : *pdfMin -= dfHalfBucket;
4929 0 : *pdfMax += dfHalfBucket;
4930 :
4931 0 : if (eErr != CE_None)
4932 0 : return eErr;
4933 : }
4934 :
4935 17 : *ppanHistogram =
4936 17 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4937 17 : if (*ppanHistogram == nullptr)
4938 : {
4939 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4940 : "Out of memory in InitBlockInfo().");
4941 0 : return CE_Failure;
4942 : }
4943 :
4944 17 : *pnBuckets = nBuckets;
4945 34 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4946 17 : TRUE, FALSE, pfnProgress, pProgressData);
4947 17 : if (eErr != CE_None)
4948 : {
4949 0 : *pnBuckets = 0;
4950 : }
4951 17 : return eErr;
4952 : }
4953 :
4954 : /************************************************************************/
4955 : /* GDALGetDefaultHistogram() */
4956 : /************************************************************************/
4957 :
4958 : /**
4959 : * \brief Fetch default raster histogram.
4960 : *
4961 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4962 : * exceeding 2 billion.
4963 : *
4964 : * @see GDALRasterBand::GDALGetDefaultHistogram()
4965 : * @see GDALGetRasterHistogramEx()
4966 : */
4967 :
4968 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4969 : double *pdfMin, double *pdfMax,
4970 : int *pnBuckets, int **ppanHistogram,
4971 : int bForce,
4972 : GDALProgressFunc pfnProgress,
4973 : void *pProgressData)
4974 :
4975 : {
4976 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4977 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4978 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4979 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4980 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4981 :
4982 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4983 0 : GUIntBig *panHistogramTemp = nullptr;
4984 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
4985 : &panHistogramTemp, bForce,
4986 0 : pfnProgress, pProgressData);
4987 0 : if (eErr == CE_None)
4988 : {
4989 0 : const int nBuckets = *pnBuckets;
4990 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
4991 0 : if (*ppanHistogram == nullptr)
4992 : {
4993 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4994 : "Out of memory in GDALGetDefaultHistogram().");
4995 0 : VSIFree(panHistogramTemp);
4996 0 : return CE_Failure;
4997 : }
4998 :
4999 0 : for (int i = 0; i < nBuckets; ++i)
5000 : {
5001 0 : if (panHistogramTemp[i] > INT_MAX)
5002 : {
5003 0 : CPLError(CE_Warning, CPLE_AppDefined,
5004 : "Count for bucket %d, which is " CPL_FRMT_GUIB
5005 : " exceeds maximum 32 bit value",
5006 0 : i, panHistogramTemp[i]);
5007 0 : (*ppanHistogram)[i] = INT_MAX;
5008 : }
5009 : else
5010 : {
5011 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5012 : }
5013 : }
5014 :
5015 0 : CPLFree(panHistogramTemp);
5016 : }
5017 : else
5018 : {
5019 0 : *ppanHistogram = nullptr;
5020 : }
5021 :
5022 0 : return eErr;
5023 : }
5024 :
5025 : /************************************************************************/
5026 : /* GDALGetDefaultHistogramEx() */
5027 : /************************************************************************/
5028 :
5029 : /**
5030 : * \brief Fetch default raster histogram.
5031 : *
5032 : * @see GDALRasterBand::GetDefaultHistogram()
5033 : *
5034 : * @since GDAL 2.0
5035 : */
5036 :
5037 : CPLErr CPL_STDCALL
5038 28 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5039 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5040 : GDALProgressFunc pfnProgress, void *pProgressData)
5041 :
5042 : {
5043 28 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5044 28 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5045 28 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5046 28 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5047 28 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5048 :
5049 28 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5050 28 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5051 28 : bForce, pfnProgress, pProgressData);
5052 : }
5053 :
5054 : /************************************************************************/
5055 : /* AdviseRead() */
5056 : /************************************************************************/
5057 :
5058 : /**
5059 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5060 : * \brief Advise driver of upcoming read requests.
5061 : *
5062 : * Some GDAL drivers operate more efficiently if they know in advance what
5063 : * set of upcoming read requests will be made. The AdviseRead() method allows
5064 : * an application to notify the driver of the region of interest,
5065 : * and at what resolution the region will be read.
5066 : *
5067 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
5068 : * accelerate access via some drivers.
5069 : *
5070 : * Depending on call paths, drivers might receive several calls to
5071 : * AdviseRead() with the same parameters.
5072 : *
5073 : * @param nXOff The pixel offset to the top left corner of the region
5074 : * of the band to be accessed. This would be zero to start from the left side.
5075 : *
5076 : * @param nYOff The line offset to the top left corner of the region
5077 : * of the band to be accessed. This would be zero to start from the top.
5078 : *
5079 : * @param nXSize The width of the region of the band to be accessed in pixels.
5080 : *
5081 : * @param nYSize The height of the region of the band to be accessed in lines.
5082 : *
5083 : * @param nBufXSize the width of the buffer image into which the desired region
5084 : * is to be read, or from which it is to be written.
5085 : *
5086 : * @param nBufYSize the height of the buffer image into which the desired
5087 : * region is to be read, or from which it is to be written.
5088 : *
5089 : * @param eBufType the type of the pixel values in the pData data buffer. The
5090 : * pixel values will automatically be translated to/from the GDALRasterBand
5091 : * data type as needed.
5092 : *
5093 : * @param papszOptions a list of name=value strings with special control
5094 : * options. Normally this is NULL.
5095 : *
5096 : * @return CE_Failure if the request is invalid and CE_None if it works or
5097 : * is ignored.
5098 : */
5099 :
5100 : /**/
5101 : /**/
5102 :
5103 114349 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5104 : int /*nYSize*/, int /*nBufXSize*/,
5105 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5106 : char ** /*papszOptions*/)
5107 : {
5108 114349 : return CE_None;
5109 : }
5110 :
5111 : /************************************************************************/
5112 : /* GDALRasterAdviseRead() */
5113 : /************************************************************************/
5114 :
5115 : /**
5116 : * \brief Advise driver of upcoming read requests.
5117 : *
5118 : * @see GDALRasterBand::AdviseRead()
5119 : */
5120 :
5121 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5122 : int nYOff, int nXSize, int nYSize,
5123 : int nBufXSize, int nBufYSize,
5124 : GDALDataType eDT,
5125 : CSLConstList papszOptions)
5126 :
5127 : {
5128 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5129 :
5130 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5131 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5132 : nBufYSize, eDT,
5133 2 : const_cast<char **>(papszOptions));
5134 : }
5135 :
5136 : /************************************************************************/
5137 : /* GetStatistics() */
5138 : /************************************************************************/
5139 :
5140 : /**
5141 : * \brief Fetch image statistics.
5142 : *
5143 : * Returns the minimum, maximum, mean and standard deviation of all
5144 : * pixel values in this band. If approximate statistics are sufficient,
5145 : * the bApproxOK flag can be set to true in which case overviews, or a
5146 : * subset of image tiles may be used in computing the statistics.
5147 : *
5148 : * If bForce is FALSE results will only be returned if it can be done
5149 : * quickly (i.e. without scanning the image, typically by using pre-existing
5150 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5151 : * returned efficiently, the method will return CE_Warning but no warning will
5152 : * be issued. This is a non-standard use of the CE_Warning return value
5153 : * to indicate "nothing done".
5154 : *
5155 : * If bForce is TRUE, and results are quickly available without scanning the
5156 : * image, they will be used. If bForce is TRUE and results are not quickly
5157 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5158 : * which will scan the image.
5159 : *
5160 : * To always force recomputation of statistics, use ComputeStatistics() instead
5161 : * of this method.
5162 : *
5163 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5164 : * will generally cache statistics in the .pam file allowing fast fetch
5165 : * after the first request.
5166 : *
5167 : * This method is the same as the C function GDALGetRasterStatistics().
5168 : *
5169 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5170 : * or a subset of all tiles.
5171 : *
5172 : * @param bForce If FALSE statistics will only be returned if it can
5173 : * be done without rescanning the image. If TRUE, statistics computation will
5174 : * be forced if pre-existing values are not quickly available.
5175 : *
5176 : * @param pdfMin Location into which to load image minimum (may be NULL).
5177 : *
5178 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5179 : *
5180 : * @param pdfMean Location into which to load image mean (may be NULL).
5181 : *
5182 : * @param pdfStdDev Location into which to load image standard deviation
5183 : * (may be NULL).
5184 : *
5185 : * @return CE_None on success, CE_Warning if no values returned,
5186 : * CE_Failure if an error occurs.
5187 : */
5188 :
5189 622 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5190 : double *pdfMax, double *pdfMean,
5191 : double *pdfStdDev)
5192 :
5193 : {
5194 : /* -------------------------------------------------------------------- */
5195 : /* Do we already have metadata items for the requested values? */
5196 : /* -------------------------------------------------------------------- */
5197 1244 : if ((pdfMin == nullptr ||
5198 622 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5199 202 : (pdfMax == nullptr ||
5200 202 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5201 1446 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5202 202 : (pdfStdDev == nullptr ||
5203 202 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5204 : {
5205 202 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5206 : {
5207 195 : if (pdfMin != nullptr)
5208 195 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5209 195 : if (pdfMax != nullptr)
5210 195 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5211 195 : if (pdfMean != nullptr)
5212 195 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5213 195 : if (pdfStdDev != nullptr)
5214 195 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5215 :
5216 195 : return CE_None;
5217 : }
5218 : }
5219 :
5220 : /* -------------------------------------------------------------------- */
5221 : /* Does the driver already know the min/max? */
5222 : /* -------------------------------------------------------------------- */
5223 427 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5224 : {
5225 0 : int bSuccessMin = FALSE;
5226 0 : int bSuccessMax = FALSE;
5227 :
5228 0 : const double dfMin = GetMinimum(&bSuccessMin);
5229 0 : const double dfMax = GetMaximum(&bSuccessMax);
5230 :
5231 0 : if (bSuccessMin && bSuccessMax)
5232 : {
5233 0 : if (pdfMin != nullptr)
5234 0 : *pdfMin = dfMin;
5235 0 : if (pdfMax != nullptr)
5236 0 : *pdfMax = dfMax;
5237 0 : return CE_None;
5238 : }
5239 : }
5240 :
5241 : /* -------------------------------------------------------------------- */
5242 : /* Either return without results, or force computation. */
5243 : /* -------------------------------------------------------------------- */
5244 427 : if (!bForce)
5245 172 : return CE_Warning;
5246 : else
5247 255 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5248 255 : GDALDummyProgress, nullptr);
5249 : }
5250 :
5251 : /************************************************************************/
5252 : /* GDALGetRasterStatistics() */
5253 : /************************************************************************/
5254 :
5255 : /**
5256 : * \brief Fetch image statistics.
5257 : *
5258 : * @see GDALRasterBand::GetStatistics()
5259 : */
5260 :
5261 271 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5262 : int bForce, double *pdfMin,
5263 : double *pdfMax, double *pdfMean,
5264 : double *pdfStdDev)
5265 :
5266 : {
5267 271 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5268 :
5269 271 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5270 271 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5271 271 : pdfStdDev);
5272 : }
5273 :
5274 : /************************************************************************/
5275 : /* GDALUInt128 */
5276 : /************************************************************************/
5277 :
5278 : #ifdef HAVE_UINT128_T
5279 : class GDALUInt128
5280 : {
5281 : __uint128_t val;
5282 :
5283 645 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5284 : {
5285 645 : }
5286 :
5287 : public:
5288 430 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5289 : {
5290 : // Evaluates to just a single mul on x86_64
5291 430 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5292 : }
5293 :
5294 215 : GDALUInt128 operator-(const GDALUInt128 &other) const
5295 : {
5296 215 : return GDALUInt128(val - other.val);
5297 : }
5298 :
5299 206 : operator double() const
5300 : {
5301 206 : return static_cast<double>(val);
5302 : }
5303 : };
5304 : #else
5305 :
5306 : #if defined(_MSC_VER) && defined(_M_X64)
5307 : #include <intrin.h>
5308 : #endif
5309 :
5310 : class GDALUInt128
5311 : {
5312 : GUIntBig low, high;
5313 :
5314 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5315 : {
5316 : }
5317 :
5318 : public:
5319 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5320 : {
5321 : #if defined(_MSC_VER) && defined(_M_X64)
5322 : GUIntBig highRes;
5323 : GUIntBig lowRes = _umul128(first, second, &highRes);
5324 : return GDALUInt128(lowRes, highRes);
5325 : #else
5326 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5327 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5328 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5329 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5330 : GUIntBig highRes = 0;
5331 : const GUIntBig firstLowSecondHigh =
5332 : static_cast<GUIntBig>(firstLow) * secondHigh;
5333 : const GUIntBig firstHighSecondLow =
5334 : static_cast<GUIntBig>(firstHigh) * secondLow;
5335 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5336 : if (middleTerm < firstLowSecondHigh) // check for overflow
5337 : highRes += static_cast<GUIntBig>(1) << 32;
5338 : const GUIntBig firstLowSecondLow =
5339 : static_cast<GUIntBig>(firstLow) * secondLow;
5340 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5341 : if (lowRes < firstLowSecondLow) // check for overflow
5342 : highRes++;
5343 : highRes +=
5344 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5345 : return GDALUInt128(lowRes, highRes);
5346 : #endif
5347 : }
5348 :
5349 : GDALUInt128 operator-(const GDALUInt128 &other) const
5350 : {
5351 : GUIntBig highRes = high - other.high;
5352 : GUIntBig lowRes = low - other.low;
5353 : if (lowRes > low) // check for underflow
5354 : --highRes;
5355 : return GDALUInt128(lowRes, highRes);
5356 : }
5357 :
5358 : operator double() const
5359 : {
5360 : const double twoPow64 = 18446744073709551616.0;
5361 : return high * twoPow64 + low;
5362 : }
5363 : };
5364 : #endif
5365 :
5366 : /************************************************************************/
5367 : /* ComputeStatisticsInternal() */
5368 : /************************************************************************/
5369 :
5370 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5371 : // not needed.
5372 : #define static_cast_for_coverity_scan static_cast
5373 :
5374 : // The rationale for below optimizations is detailed in statistics.txt
5375 :
5376 : // Use with T = GByte or GUInt16 only !
5377 : template <class T, bool COMPUTE_OTHER_STATS>
5378 : struct ComputeStatisticsInternalGeneric
5379 : {
5380 208 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5381 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5382 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5383 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5384 : {
5385 : static_assert(std::is_same<T, GByte>::value ||
5386 : std::is_same<T, GUInt16>::value,
5387 : "bad type for T");
5388 208 : if (bHasNoData)
5389 : {
5390 : // General case
5391 386 : for (int iY = 0; iY < nYCheck; iY++)
5392 : {
5393 81751 : for (int iX = 0; iX < nXCheck; iX++)
5394 : {
5395 81468 : const GPtrDiff_t iOffset =
5396 81468 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5397 81468 : const GUInt32 nValue = pData[iOffset];
5398 81468 : if (nValue == nNoDataValue)
5399 175 : continue;
5400 81293 : if (nValue < nMin)
5401 26 : nMin = nValue;
5402 81293 : if (nValue > nMax)
5403 57 : nMax = nValue;
5404 : if constexpr (COMPUTE_OTHER_STATS)
5405 : {
5406 79657 : nValidCount++;
5407 79657 : nSum += nValue;
5408 79657 : nSumSquare +=
5409 79657 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5410 79657 : nValue;
5411 : }
5412 : }
5413 : }
5414 : if constexpr (COMPUTE_OTHER_STATS)
5415 : {
5416 20 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5417 : }
5418 : }
5419 115 : else if (nMin == std::numeric_limits<T>::lowest() &&
5420 10 : nMax == std::numeric_limits<T>::max())
5421 : {
5422 : if constexpr (COMPUTE_OTHER_STATS)
5423 : {
5424 : // Optimization when there is no nodata and we know we have already
5425 : // reached the min and max
5426 208 : for (int iY = 0; iY < nYCheck; iY++)
5427 : {
5428 : int iX;
5429 1002 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5430 : {
5431 800 : const GPtrDiff_t iOffset =
5432 800 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5433 800 : const GUIntBig nValue = pData[iOffset];
5434 800 : const GUIntBig nValue2 = pData[iOffset + 1];
5435 800 : const GUIntBig nValue3 = pData[iOffset + 2];
5436 800 : const GUIntBig nValue4 = pData[iOffset + 3];
5437 800 : nSum += nValue;
5438 800 : nSumSquare += nValue * nValue;
5439 800 : nSum += nValue2;
5440 800 : nSumSquare += nValue2 * nValue2;
5441 800 : nSum += nValue3;
5442 800 : nSumSquare += nValue3 * nValue3;
5443 800 : nSum += nValue4;
5444 800 : nSumSquare += nValue4 * nValue4;
5445 : }
5446 207 : for (; iX < nXCheck; ++iX)
5447 : {
5448 5 : const GPtrDiff_t iOffset =
5449 5 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5450 5 : const GUIntBig nValue = pData[iOffset];
5451 5 : nSum += nValue;
5452 5 : nSumSquare += nValue * nValue;
5453 : }
5454 : }
5455 6 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5456 6 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5457 : }
5458 : }
5459 : else
5460 : {
5461 3434 : for (int iY = 0; iY < nYCheck; iY++)
5462 : {
5463 : int iX;
5464 643297 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5465 : {
5466 639962 : const GPtrDiff_t iOffset =
5467 639962 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5468 639962 : const GUInt32 nValue = pData[iOffset];
5469 639962 : const GUInt32 nValue2 = pData[iOffset + 1];
5470 639962 : if (nValue < nValue2)
5471 : {
5472 2320 : if (nValue < nMin)
5473 48 : nMin = nValue;
5474 2320 : if (nValue2 > nMax)
5475 116 : nMax = nValue2;
5476 : }
5477 : else
5478 : {
5479 637642 : if (nValue2 < nMin)
5480 66 : nMin = nValue2;
5481 637642 : if (nValue > nMax)
5482 215 : nMax = nValue;
5483 : }
5484 : if constexpr (COMPUTE_OTHER_STATS)
5485 : {
5486 632911 : nSum += nValue;
5487 632911 : nSumSquare +=
5488 632911 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5489 632911 : nValue;
5490 632911 : nSum += nValue2;
5491 632911 : nSumSquare +=
5492 632911 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5493 632911 : nValue2;
5494 : }
5495 : }
5496 3335 : if (iX < nXCheck)
5497 : {
5498 18 : const GPtrDiff_t iOffset =
5499 18 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5500 18 : const GUInt32 nValue = pData[iOffset];
5501 18 : if (nValue < nMin)
5502 13 : nMin = nValue;
5503 18 : if (nValue > nMax)
5504 14 : nMax = nValue;
5505 : if (COMPUTE_OTHER_STATS)
5506 : {
5507 9 : nSum += nValue;
5508 9 : nSumSquare +=
5509 9 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5510 9 : nValue;
5511 : }
5512 : }
5513 : }
5514 : if constexpr (COMPUTE_OTHER_STATS)
5515 : {
5516 44 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5517 44 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5518 : }
5519 : }
5520 208 : }
5521 : };
5522 :
5523 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5524 : // using 64bit accumulators in internal loops. This also slightly helps in
5525 : // 64bit mode.
5526 : template <bool COMPUTE_OTHER_STATS>
5527 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5528 : {
5529 13717 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5530 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5531 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5532 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5533 : {
5534 13717 : int nOuterLoops = nXCheck / 65536;
5535 13717 : if (nXCheck % 65536)
5536 13717 : nOuterLoops++;
5537 :
5538 13717 : if (bHasNoData)
5539 : {
5540 : // General case
5541 23475 : for (int iY = 0; iY < nYCheck; iY++)
5542 : {
5543 12901 : int iX = 0;
5544 25802 : for (int k = 0; k < nOuterLoops; k++)
5545 : {
5546 12901 : int iMax = iX + 65536;
5547 12901 : if (iMax > nXCheck)
5548 12901 : iMax = nXCheck;
5549 12901 : GUInt32 nSum32bit = 0;
5550 12901 : GUInt32 nSumSquare32bit = 0;
5551 12901 : GUInt32 nValidCount32bit = 0;
5552 12901 : GUInt32 nSampleCount32bit = 0;
5553 20707198 : for (; iX < iMax; iX++)
5554 : {
5555 20694346 : const GPtrDiff_t iOffset =
5556 20694346 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5557 20694346 : const GUInt32 nValue = pData[iOffset];
5558 :
5559 20694346 : nSampleCount32bit++;
5560 20694346 : if (nValue == nNoDataValue)
5561 20353472 : continue;
5562 340819 : if (nValue < nMin)
5563 357 : nMin = nValue;
5564 340819 : if (nValue > nMax)
5565 813 : nMax = nValue;
5566 : if constexpr (COMPUTE_OTHER_STATS)
5567 : {
5568 17074 : nValidCount32bit++;
5569 17074 : nSum32bit += nValue;
5570 17074 : nSumSquare32bit += nValue * nValue;
5571 : }
5572 : }
5573 : if constexpr (COMPUTE_OTHER_STATS)
5574 : {
5575 652 : nSampleCount += nSampleCount32bit;
5576 652 : nValidCount += nValidCount32bit;
5577 652 : nSum += nSum32bit;
5578 652 : nSumSquare += nSumSquare32bit;
5579 : }
5580 : }
5581 : }
5582 : }
5583 3143 : else if (nMin == 0 && nMax == 255)
5584 : {
5585 : if constexpr (COMPUTE_OTHER_STATS)
5586 : {
5587 : // Optimization when there is no nodata and we know we have already
5588 : // reached the min and max
5589 2644 : for (int iY = 0; iY < nYCheck; iY++)
5590 : {
5591 2617 : int iX = 0;
5592 5234 : for (int k = 0; k < nOuterLoops; k++)
5593 : {
5594 2617 : int iMax = iX + 65536;
5595 2617 : if (iMax > nXCheck)
5596 2617 : iMax = nXCheck;
5597 2617 : GUInt32 nSum32bit = 0;
5598 2617 : GUInt32 nSumSquare32bit = 0;
5599 176297 : for (; iX + 3 < iMax; iX += 4)
5600 : {
5601 173680 : const GPtrDiff_t iOffset =
5602 173680 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5603 173680 : const GUInt32 nValue = pData[iOffset];
5604 173680 : const GUInt32 nValue2 = pData[iOffset + 1];
5605 173680 : const GUInt32 nValue3 = pData[iOffset + 2];
5606 173680 : const GUInt32 nValue4 = pData[iOffset + 3];
5607 173680 : nSum32bit += nValue;
5608 173680 : nSumSquare32bit += nValue * nValue;
5609 173680 : nSum32bit += nValue2;
5610 173680 : nSumSquare32bit += nValue2 * nValue2;
5611 173680 : nSum32bit += nValue3;
5612 173680 : nSumSquare32bit += nValue3 * nValue3;
5613 173680 : nSum32bit += nValue4;
5614 173680 : nSumSquare32bit += nValue4 * nValue4;
5615 : }
5616 2617 : nSum += nSum32bit;
5617 2617 : nSumSquare += nSumSquare32bit;
5618 : }
5619 2620 : for (; iX < nXCheck; ++iX)
5620 : {
5621 3 : const GPtrDiff_t iOffset =
5622 3 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5623 3 : const GUIntBig nValue = pData[iOffset];
5624 3 : nSum += nValue;
5625 3 : nSumSquare += nValue * nValue;
5626 : }
5627 : }
5628 27 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5629 27 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5630 27 : }
5631 : }
5632 : else
5633 : {
5634 7923 : for (int iY = 0; iY < nYCheck; iY++)
5635 : {
5636 4807 : int iX = 0;
5637 9614 : for (int k = 0; k < nOuterLoops; k++)
5638 : {
5639 4807 : int iMax = iX + 65536;
5640 4807 : if (iMax > nXCheck)
5641 4807 : iMax = nXCheck;
5642 4807 : GUInt32 nSum32bit = 0;
5643 4807 : GUInt32 nSumSquare32bit = 0;
5644 159553 : for (; iX + 1 < iMax; iX += 2)
5645 : {
5646 154746 : const GPtrDiff_t iOffset =
5647 154746 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5648 154746 : const GUInt32 nValue = pData[iOffset];
5649 154746 : const GUInt32 nValue2 = pData[iOffset + 1];
5650 154746 : if (nValue < nValue2)
5651 : {
5652 8100 : if (nValue < nMin)
5653 232 : nMin = nValue;
5654 8100 : if (nValue2 > nMax)
5655 219 : nMax = nValue2;
5656 : }
5657 : else
5658 : {
5659 146646 : if (nValue2 < nMin)
5660 362 : nMin = nValue2;
5661 146646 : if (nValue > nMax)
5662 832 : nMax = nValue;
5663 : }
5664 : if constexpr (COMPUTE_OTHER_STATS)
5665 : {
5666 132609 : nSum32bit += nValue;
5667 132609 : nSumSquare32bit += nValue * nValue;
5668 132609 : nSum32bit += nValue2;
5669 132609 : nSumSquare32bit += nValue2 * nValue2;
5670 : }
5671 : }
5672 : if constexpr (COMPUTE_OTHER_STATS)
5673 : {
5674 1630 : nSum += nSum32bit;
5675 1630 : nSumSquare += nSumSquare32bit;
5676 : }
5677 : }
5678 4807 : if (iX < nXCheck)
5679 : {
5680 1515 : const GPtrDiff_t iOffset =
5681 1515 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5682 1515 : const GUInt32 nValue = pData[iOffset];
5683 1515 : if (nValue < nMin)
5684 108 : nMin = nValue;
5685 1515 : if (nValue > nMax)
5686 95 : nMax = nValue;
5687 : if constexpr (COMPUTE_OTHER_STATS)
5688 : {
5689 313 : nSum += nValue;
5690 313 : nSumSquare +=
5691 313 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5692 313 : nValue;
5693 : }
5694 : }
5695 : }
5696 : if constexpr (COMPUTE_OTHER_STATS)
5697 : {
5698 929 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5699 929 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5700 : }
5701 : }
5702 13717 : }
5703 : };
5704 :
5705 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5706 : {
5707 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5708 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5709 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5710 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5711 : {
5712 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5713 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5714 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5715 : }
5716 : };
5717 :
5718 : #if (defined(__x86_64__) || defined(_M_X64)) && \
5719 : (defined(__GNUC__) || defined(_MSC_VER))
5720 :
5721 : #include "gdal_avx2_emulation.hpp"
5722 :
5723 : #define ZERO256 GDALmm256_setzero_si256()
5724 :
5725 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5726 : static void
5727 21332 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5728 : // assumed to be aligned on 256 bits
5729 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5730 : GUIntBig &nSum, GUIntBig &nSumSquare,
5731 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5732 : {
5733 : // 32-byte alignment may not be enforced by linker, so do it at hand
5734 : GByte
5735 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5736 21332 : GByte *paby32ByteAligned =
5737 : aby32ByteUnaligned +
5738 21332 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5739 21332 : GByte *pabyMin = paby32ByteAligned;
5740 21332 : GByte *pabyMax = paby32ByteAligned + 32;
5741 21332 : GUInt32 *panSum =
5742 : COMPUTE_OTHER_STATS
5743 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5744 : : nullptr;
5745 21332 : GUInt32 *panSumSquare =
5746 : COMPUTE_OTHER_STATS
5747 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5748 : : nullptr;
5749 :
5750 21332 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5751 :
5752 21332 : GPtrDiff_t i = 0;
5753 : // Make sure that sumSquare can fit on uint32
5754 : // * 8 since we can hold 8 sums per vector register
5755 21332 : const int nMaxIterationsPerInnerLoop =
5756 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5757 21332 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5758 21332 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5759 21332 : nOuterLoops++;
5760 :
5761 : GDALm256i ymm_min =
5762 21332 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5763 21332 : GDALm256i ymm_max = ymm_min;
5764 21332 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5765 :
5766 42664 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5767 : {
5768 21332 : const auto iMax =
5769 21332 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5770 :
5771 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5772 21332 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5773 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5774 21332 : ZERO256; // holds 8 uint32 sums
5775 710963 : for (; i + 31 < iMax; i += 32)
5776 : {
5777 689631 : const GDALm256i ymm = GDALmm256_load_si256(
5778 689631 : reinterpret_cast<const GDALm256i *>(pData + i));
5779 : if (COMPUTE_MIN)
5780 : {
5781 231794 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5782 : }
5783 : if (COMPUTE_MAX)
5784 : {
5785 598690 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5786 : }
5787 :
5788 : if constexpr (COMPUTE_OTHER_STATS)
5789 : {
5790 : // Extract even-8bit values
5791 : const GDALm256i ymm_even =
5792 493495 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5793 : // Compute square of those 16 values as 32 bit result
5794 : // and add adjacent pairs
5795 : const GDALm256i ymm_even_square =
5796 493495 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5797 : // Add to the sumsquare accumulator
5798 : ymm_sumsquare =
5799 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5800 :
5801 : // Extract odd-8bit values
5802 493495 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5803 : const GDALm256i ymm_odd_square =
5804 493495 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5805 : ymm_sumsquare =
5806 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5807 :
5808 : // Now compute the sums
5809 493495 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5810 : GDALmm256_sad_epu8(ymm, ZERO256));
5811 : }
5812 : }
5813 :
5814 : if constexpr (COMPUTE_OTHER_STATS)
5815 : {
5816 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5817 : ymm_sum);
5818 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5819 : ymm_sumsquare);
5820 :
5821 10649 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5822 10649 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5823 10649 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5824 10649 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5825 : panSumSquare[7];
5826 : }
5827 : }
5828 :
5829 : if constexpr (COMPUTE_MIN)
5830 : {
5831 8458 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5832 : }
5833 : if constexpr (COMPUTE_MAX)
5834 : {
5835 17335 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5836 : }
5837 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5838 : {
5839 589545 : for (int j = 0; j < 32; j++)
5840 : {
5841 : if constexpr (COMPUTE_MIN)
5842 : {
5843 270656 : if (pabyMin[j] < nMin)
5844 1261 : nMin = pabyMin[j];
5845 : }
5846 : if constexpr (COMPUTE_MAX)
5847 : {
5848 554720 : if (pabyMax[j] > nMax)
5849 1813 : nMax = pabyMax[j];
5850 : }
5851 : }
5852 : }
5853 :
5854 234398 : for (; i < nBlockPixels; i++)
5855 : {
5856 213066 : const GUInt32 nValue = pData[i];
5857 : if constexpr (COMPUTE_MIN)
5858 : {
5859 88390 : if (nValue < nMin)
5860 1 : nMin = nValue;
5861 : }
5862 : if constexpr (COMPUTE_MAX)
5863 : {
5864 210291 : if (nValue > nMax)
5865 1149 : nMax = nValue;
5866 : }
5867 : if constexpr (COMPUTE_OTHER_STATS)
5868 : {
5869 77195 : nSum += nValue;
5870 77195 : nSumSquare +=
5871 77195 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5872 : }
5873 : }
5874 :
5875 : if constexpr (COMPUTE_OTHER_STATS)
5876 : {
5877 10649 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5878 10649 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5879 : }
5880 21332 : }
5881 :
5882 : // SSE2/AVX2 optimization for GByte case
5883 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5884 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5885 : // there are strictly equivalent to 2 parallel SSE2 streams.
5886 : template <bool COMPUTE_OTHER_STATS>
5887 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5888 : {
5889 30185 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5890 : // assumed to be aligned on 256 bits
5891 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5892 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5893 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5894 : GUIntBig &nValidCount)
5895 : {
5896 30185 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5897 30185 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5898 11574 : nMin <= nMax)
5899 : {
5900 : // 32-byte alignment may not be enforced by linker, so do it at hand
5901 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5902 1459 : GByte *paby32ByteAligned =
5903 : aby32ByteUnaligned +
5904 1459 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5905 1459 : GByte *pabyMin = paby32ByteAligned;
5906 1459 : GByte *pabyMax = paby32ByteAligned + 32;
5907 1459 : GUInt32 *panSum =
5908 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5909 1459 : GUInt32 *panSumSquare =
5910 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5911 :
5912 1459 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5913 :
5914 1459 : GPtrDiff_t i = 0;
5915 : // Make sure that sumSquare can fit on uint32
5916 : // * 8 since we can hold 8 sums per vector register
5917 1459 : const int nMaxIterationsPerInnerLoop =
5918 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5919 1459 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5920 1459 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5921 1459 : nOuterLoops++;
5922 :
5923 : const GDALm256i ymm_nodata =
5924 1459 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5925 : // any non noData value in [min,max] would do.
5926 : const GDALm256i ymm_neutral =
5927 1459 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5928 1459 : GDALm256i ymm_min = ymm_neutral;
5929 1459 : GDALm256i ymm_max = ymm_neutral;
5930 : [[maybe_unused]] const auto ymm_mask_8bits =
5931 1459 : GDALmm256_set1_epi16(0xFF);
5932 :
5933 1459 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5934 1459 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5935 1459 : const bool bComputeMinMax =
5936 1459 : nMin > nMinThreshold || nMax < nMaxThreshold;
5937 :
5938 2918 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5939 : {
5940 1459 : const auto iMax =
5941 1459 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5942 :
5943 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5944 1459 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5945 : // holds 8 uint32 sums
5946 1459 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5947 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5948 1459 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5949 1459 : const auto iInit = i;
5950 14435 : for (; i + 31 < iMax; i += 32)
5951 : {
5952 12976 : const GDALm256i ymm = GDALmm256_load_si256(
5953 12976 : reinterpret_cast<const GDALm256i *>(pData + i));
5954 :
5955 : // Check which values are nodata
5956 : const GDALm256i ymm_eq_nodata =
5957 12976 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5958 : if constexpr (COMPUTE_OTHER_STATS)
5959 : {
5960 : // Count how many values are nodata (due to cmpeq
5961 : // putting 255 when condition is met, this will actually
5962 : // be 255 times the number of nodata value, spread in 4
5963 : // 64 bits words). We can use add_epi32 as the counter
5964 : // will not overflow uint32
5965 4634 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5966 : ymm_count_nodata_mul_255,
5967 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5968 : }
5969 : // Replace all nodata values by zero for the purpose of sum
5970 : // and sumquare.
5971 : const GDALm256i ymm_nodata_by_zero =
5972 12976 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5973 12976 : if (bComputeMinMax)
5974 : {
5975 : // Replace all nodata values by a neutral value for the
5976 : // purpose of min and max.
5977 : const GDALm256i ymm_nodata_by_neutral =
5978 8591 : GDALmm256_or_si256(
5979 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5980 : ymm_nodata_by_zero);
5981 :
5982 : ymm_min =
5983 8591 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5984 : ymm_max =
5985 8591 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
5986 : }
5987 :
5988 : if constexpr (COMPUTE_OTHER_STATS)
5989 : {
5990 : // Extract even-8bit values
5991 4634 : const GDALm256i ymm_even = GDALmm256_and_si256(
5992 : ymm_nodata_by_zero, ymm_mask_8bits);
5993 : // Compute square of those 16 values as 32 bit result
5994 : // and add adjacent pairs
5995 : const GDALm256i ymm_even_square =
5996 4634 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5997 : // Add to the sumsquare accumulator
5998 : ymm_sumsquare =
5999 4634 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6000 :
6001 : // Extract odd-8bit values
6002 : const GDALm256i ymm_odd =
6003 4634 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6004 : const GDALm256i ymm_odd_square =
6005 4634 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6006 : ymm_sumsquare =
6007 4634 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6008 :
6009 : // Now compute the sums
6010 4634 : ymm_sum = GDALmm256_add_epi32(
6011 : ymm_sum,
6012 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6013 : }
6014 : }
6015 :
6016 : if constexpr (COMPUTE_OTHER_STATS)
6017 : {
6018 153 : GUInt32 *panCoutNoDataMul255 = panSum;
6019 153 : GDALmm256_store_si256(
6020 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6021 : ymm_count_nodata_mul_255);
6022 :
6023 153 : nSampleCount += (i - iInit);
6024 :
6025 153 : nValidCount +=
6026 153 : (i - iInit) -
6027 153 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6028 153 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6029 : 255;
6030 :
6031 153 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6032 : ymm_sum);
6033 153 : GDALmm256_store_si256(
6034 : reinterpret_cast<GDALm256i *>(panSumSquare),
6035 : ymm_sumsquare);
6036 153 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6037 153 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6038 153 : panSumSquare[1] + panSumSquare[2] +
6039 153 : panSumSquare[3] + panSumSquare[4] +
6040 153 : panSumSquare[5] + panSumSquare[6] +
6041 : panSumSquare[7];
6042 : }
6043 : }
6044 :
6045 1459 : if (bComputeMinMax)
6046 : {
6047 1428 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6048 : ymm_min);
6049 1428 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6050 : ymm_max);
6051 47124 : for (int j = 0; j < 32; j++)
6052 : {
6053 45696 : if (pabyMin[j] < nMin)
6054 40 : nMin = pabyMin[j];
6055 45696 : if (pabyMax[j] > nMax)
6056 159 : nMax = pabyMax[j];
6057 : }
6058 : }
6059 :
6060 : if constexpr (COMPUTE_OTHER_STATS)
6061 : {
6062 153 : nSampleCount += nBlockPixels - i;
6063 : }
6064 33905 : for (; i < nBlockPixels; i++)
6065 : {
6066 32446 : const GUInt32 nValue = pData[i];
6067 32446 : if (nValue == nNoDataValue)
6068 24923 : continue;
6069 7523 : if (nValue < nMin)
6070 1 : nMin = nValue;
6071 7523 : if (nValue > nMax)
6072 13 : nMax = nValue;
6073 : if constexpr (COMPUTE_OTHER_STATS)
6074 : {
6075 3590 : nValidCount++;
6076 3590 : nSum += nValue;
6077 3590 : nSumSquare +=
6078 3590 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6079 3590 : nValue;
6080 : }
6081 1459 : }
6082 : }
6083 28726 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6084 : {
6085 14976 : if (nMin > 0)
6086 : {
6087 2102 : if (nMax < 255)
6088 : {
6089 : ComputeStatisticsByteNoNodata<true, true,
6090 1572 : COMPUTE_OTHER_STATS>(
6091 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6092 : nSampleCount, nValidCount);
6093 : }
6094 : else
6095 : {
6096 : ComputeStatisticsByteNoNodata<true, false,
6097 530 : COMPUTE_OTHER_STATS>(
6098 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6099 : nSampleCount, nValidCount);
6100 : }
6101 : }
6102 : else
6103 : {
6104 12874 : if (nMax < 255)
6105 : {
6106 : ComputeStatisticsByteNoNodata<false, true,
6107 9407 : COMPUTE_OTHER_STATS>(
6108 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6109 : nSampleCount, nValidCount);
6110 : }
6111 : else
6112 : {
6113 : ComputeStatisticsByteNoNodata<false, false,
6114 3467 : COMPUTE_OTHER_STATS>(
6115 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6116 : nSampleCount, nValidCount);
6117 : }
6118 : }
6119 : }
6120 12475 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6121 33 : (nBlockXSize % 32) == 0)
6122 : {
6123 6389 : for (int iY = 0; iY < nYCheck; iY++)
6124 : {
6125 6356 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6126 6356 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6127 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6128 33 : }
6129 : }
6130 : else
6131 : {
6132 13717 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6133 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6134 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6135 : }
6136 30185 : }
6137 : };
6138 :
6139 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6140 400 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6141 : GUIntBig i)
6142 : {
6143 400 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6144 400 : }
6145 :
6146 : // AVX2/SSE2 optimization for GUInt16 case
6147 : template <bool COMPUTE_OTHER_STATS>
6148 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6149 : {
6150 1626 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
6151 : // assumed to be aligned on 128 bits
6152 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6153 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6154 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6155 : GUIntBig &nValidCount)
6156 : {
6157 1626 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6158 1626 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6159 : {
6160 1418 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6161 :
6162 1418 : GPtrDiff_t i = 0;
6163 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6164 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6165 : // Furthermore the shift is also needed to use madd_epi16
6166 1418 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6167 1418 : GDALm256i ymm_min = GDALmm256_load_si256(
6168 1418 : reinterpret_cast<const GDALm256i *>(pData + i));
6169 1418 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6170 1418 : GDALm256i ymm_max = ymm_min;
6171 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6172 1418 : ZERO256; // holds 4 uint64 sums
6173 :
6174 : // Make sure that sum can fit on uint32
6175 : // * 8 since we can hold 8 sums per vector register
6176 1418 : const int nMaxIterationsPerInnerLoop =
6177 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6178 1418 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6179 1418 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6180 1418 : nOuterLoops++;
6181 :
6182 1418 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6183 : [[maybe_unused]] const auto ymm_mask_16bits =
6184 1418 : GDALmm256_set1_epi32(0xFFFF);
6185 : [[maybe_unused]] const auto ymm_mask_32bits =
6186 1418 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6187 :
6188 1418 : GUIntBig nSumThis = 0;
6189 2860 : for (int k = 0; k < nOuterLoops; k++)
6190 : {
6191 1442 : const auto iMax =
6192 1442 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6193 :
6194 : [[maybe_unused]] GDALm256i ymm_sum =
6195 1442 : ZERO256; // holds 8 uint32 sums
6196 959774 : for (; i + 15 < iMax; i += 16)
6197 : {
6198 958332 : const GDALm256i ymm = GDALmm256_load_si256(
6199 958332 : reinterpret_cast<const GDALm256i *>(pData + i));
6200 : const GDALm256i ymm_shifted =
6201 958332 : GDALmm256_add_epi16(ymm, ymm_m32768);
6202 958332 : if (bComputeMinMax)
6203 : {
6204 949313 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6205 949313 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6206 : }
6207 :
6208 : if constexpr (COMPUTE_OTHER_STATS)
6209 : {
6210 : // Note: the int32 range can overflow for (0-32768)^2 +
6211 : // (0-32768)^2 = 0x80000000, but as we know the result
6212 : // is positive, this is OK as we interpret is a uint32.
6213 : const GDALm256i ymm_square =
6214 95410 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6215 95410 : ymm_sumsquare = GDALmm256_add_epi64(
6216 : ymm_sumsquare,
6217 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6218 95410 : ymm_sumsquare = GDALmm256_add_epi64(
6219 : ymm_sumsquare,
6220 : GDALmm256_srli_epi64(ymm_square, 32));
6221 :
6222 : // Now compute the sums
6223 95410 : ymm_sum = GDALmm256_add_epi32(
6224 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6225 95410 : ymm_sum = GDALmm256_add_epi32(
6226 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6227 : }
6228 : }
6229 :
6230 : if constexpr (COMPUTE_OTHER_STATS)
6231 : {
6232 : GUInt32 anSum[8];
6233 400 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6234 : ymm_sum);
6235 400 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6236 400 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6237 400 : anSum[6] + anSum[7];
6238 : }
6239 : }
6240 :
6241 1418 : if (bComputeMinMax)
6242 : {
6243 : GUInt16 anMin[16];
6244 : GUInt16 anMax[16];
6245 :
6246 : // Unshift the result
6247 1377 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6248 1377 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6249 1377 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6250 : ymm_min);
6251 1377 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6252 : ymm_max);
6253 23409 : for (int j = 0; j < 16; j++)
6254 : {
6255 22032 : if (anMin[j] < nMin)
6256 342 : nMin = anMin[j];
6257 22032 : if (anMax[j] > nMax)
6258 481 : nMax = anMax[j];
6259 : }
6260 : }
6261 :
6262 : if constexpr (COMPUTE_OTHER_STATS)
6263 : {
6264 : GUIntBig anSumSquare[4];
6265 400 : GDALmm256_storeu_si256(
6266 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6267 400 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6268 : anSumSquare[3];
6269 :
6270 : // Unshift the sum of squares
6271 400 : UnshiftSumSquare(nSumSquare, nSumThis,
6272 : static_cast<GUIntBig>(i));
6273 :
6274 400 : nSum += nSumThis;
6275 :
6276 722 : for (; i < nBlockPixels; i++)
6277 : {
6278 322 : const GUInt32 nValue = pData[i];
6279 322 : if (nValue < nMin)
6280 1 : nMin = nValue;
6281 322 : if (nValue > nMax)
6282 1 : nMax = nValue;
6283 322 : nSum += nValue;
6284 322 : nSumSquare +=
6285 322 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6286 322 : nValue;
6287 : }
6288 :
6289 400 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6290 400 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6291 1418 : }
6292 : }
6293 : else
6294 : {
6295 208 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6296 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6297 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6298 : }
6299 1626 : }
6300 : };
6301 :
6302 : #endif
6303 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6304 : // defined(_MSC_VER))
6305 :
6306 : /************************************************************************/
6307 : /* GetPixelValue() */
6308 : /************************************************************************/
6309 :
6310 23619100 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6311 : const void *pData, GPtrDiff_t iOffset,
6312 : const GDALNoDataValues &sNoDataValues,
6313 : bool &bValid)
6314 : {
6315 23619100 : bValid = true;
6316 23619100 : double dfValue = 0;
6317 23619100 : switch (eDataType)
6318 : {
6319 1413690 : case GDT_Byte:
6320 : {
6321 1413690 : if (bSignedByte)
6322 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6323 : else
6324 1413500 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6325 1413690 : break;
6326 : }
6327 10409 : case GDT_Int8:
6328 10409 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6329 10409 : break;
6330 4000 : case GDT_UInt16:
6331 4000 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6332 4000 : break;
6333 60192 : case GDT_Int16:
6334 60192 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6335 60192 : break;
6336 27600 : case GDT_UInt32:
6337 27600 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6338 27600 : break;
6339 455610 : case GDT_Int32:
6340 455610 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6341 455610 : break;
6342 2604 : case GDT_UInt64:
6343 2604 : dfValue = static_cast<double>(
6344 2604 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6345 2604 : break;
6346 7404 : case GDT_Int64:
6347 7404 : dfValue = static_cast<double>(
6348 7404 : static_cast<const std::int64_t *>(pData)[iOffset]);
6349 7404 : break;
6350 0 : case GDT_Float16:
6351 : {
6352 : using namespace std;
6353 0 : const GFloat16 hfValue =
6354 0 : static_cast<const GFloat16 *>(pData)[iOffset];
6355 0 : if (isnan(hfValue) ||
6356 0 : (sNoDataValues.bGotFloat16NoDataValue &&
6357 0 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6358 : {
6359 0 : bValid = false;
6360 0 : return 0.0;
6361 : }
6362 0 : dfValue = hfValue;
6363 0 : return dfValue;
6364 : }
6365 17931500 : case GDT_Float32:
6366 : {
6367 17931500 : const float fValue = static_cast<const float *>(pData)[iOffset];
6368 35836200 : if (std::isnan(fValue) ||
6369 31039700 : (sNoDataValues.bGotFloatNoDataValue &&
6370 13135100 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6371 : {
6372 26881 : bValid = false;
6373 26881 : return 0.0;
6374 : }
6375 17904600 : dfValue = fValue;
6376 17904600 : return dfValue;
6377 : }
6378 3688930 : case GDT_Float64:
6379 3688930 : dfValue = static_cast<const double *>(pData)[iOffset];
6380 3688930 : if (std::isnan(dfValue))
6381 : {
6382 52 : bValid = false;
6383 52 : return 0.0;
6384 : }
6385 3688880 : break;
6386 2692 : case GDT_CInt16:
6387 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6388 2692 : break;
6389 2692 : case GDT_CInt32:
6390 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6391 2692 : break;
6392 0 : case GDT_CFloat16:
6393 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6394 0 : if (std::isnan(dfValue))
6395 : {
6396 0 : bValid = false;
6397 0 : return 0.0;
6398 : }
6399 0 : break;
6400 5812 : case GDT_CFloat32:
6401 5812 : dfValue = static_cast<const float *>(pData)[iOffset * 2];
6402 5812 : if (std::isnan(dfValue))
6403 : {
6404 0 : bValid = false;
6405 0 : return 0.0;
6406 : }
6407 5812 : break;
6408 5892 : case GDT_CFloat64:
6409 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6410 5892 : if (std::isnan(dfValue))
6411 : {
6412 0 : bValid = false;
6413 0 : return 0.0;
6414 : }
6415 5892 : break;
6416 0 : case GDT_Unknown:
6417 : case GDT_TypeCount:
6418 0 : CPLAssert(false);
6419 : break;
6420 : }
6421 :
6422 9427660 : if (sNoDataValues.bGotNoDataValue &&
6423 3740190 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6424 : {
6425 3346220 : bValid = false;
6426 3346220 : return 0.0;
6427 : }
6428 2341250 : return dfValue;
6429 : }
6430 :
6431 : /************************************************************************/
6432 : /* SetValidPercent() */
6433 : /************************************************************************/
6434 :
6435 : //! @cond Doxygen_Suppress
6436 : /**
6437 : * \brief Set percentage of valid (not nodata) pixels.
6438 : *
6439 : * Stores the percentage of valid pixels in the metadata item
6440 : * STATISTICS_VALID_PERCENT
6441 : *
6442 : * @param nSampleCount Number of sampled pixels.
6443 : *
6444 : * @param nValidCount Number of valid pixels.
6445 : */
6446 :
6447 495 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6448 : GUIntBig nValidCount)
6449 : {
6450 495 : if (nValidCount == 0)
6451 : {
6452 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6453 : }
6454 483 : else if (nValidCount == nSampleCount)
6455 : {
6456 436 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6457 : }
6458 : else /* nValidCount < nSampleCount */
6459 : {
6460 47 : char szValue[128] = {0};
6461 :
6462 : /* percentage is only an indicator: limit precision */
6463 47 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6464 47 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6465 :
6466 47 : if (EQUAL(szValue, "100"))
6467 : {
6468 : /* don't set 100 percent valid
6469 : * because some of the sampled pixels were nodata */
6470 0 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6471 : }
6472 : else
6473 : {
6474 47 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6475 : }
6476 : }
6477 495 : }
6478 :
6479 : //! @endcond
6480 :
6481 : /************************************************************************/
6482 : /* ComputeStatistics() */
6483 : /************************************************************************/
6484 :
6485 : /**
6486 : * \brief Compute image statistics.
6487 : *
6488 : * Returns the minimum, maximum, mean and standard deviation of all
6489 : * pixel values in this band. If approximate statistics are sufficient,
6490 : * the bApproxOK flag can be set to true in which case overviews, or a
6491 : * subset of image tiles may be used in computing the statistics.
6492 : *
6493 : * Once computed, the statistics will generally be "set" back on the
6494 : * raster band using SetStatistics().
6495 : *
6496 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6497 : *
6498 : * This method is the same as the C function GDALComputeRasterStatistics().
6499 : *
6500 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6501 : * or a subset of all tiles.
6502 : *
6503 : * @param pdfMin Location into which to load image minimum (may be NULL).
6504 : *
6505 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6506 : *
6507 : * @param pdfMean Location into which to load image mean (may be NULL).
6508 : *
6509 : * @param pdfStdDev Location into which to load image standard deviation
6510 : * (may be NULL).
6511 : *
6512 : * @param pfnProgress a function to call to report progress, or NULL.
6513 : *
6514 : * @param pProgressData application data to pass to the progress function.
6515 : *
6516 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6517 : * is terminated by the user.
6518 : */
6519 :
6520 473 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6521 : double *pdfMax, double *pdfMean,
6522 : double *pdfStdDev,
6523 : GDALProgressFunc pfnProgress,
6524 : void *pProgressData)
6525 :
6526 : {
6527 473 : if (pfnProgress == nullptr)
6528 171 : pfnProgress = GDALDummyProgress;
6529 :
6530 : /* -------------------------------------------------------------------- */
6531 : /* If we have overview bands, use them for statistics. */
6532 : /* -------------------------------------------------------------------- */
6533 473 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6534 : {
6535 : GDALRasterBand *poBand =
6536 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6537 :
6538 3 : if (poBand != this)
6539 : {
6540 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6541 : pdfMean, pdfStdDev,
6542 3 : pfnProgress, pProgressData);
6543 3 : if (eErr == CE_None)
6544 : {
6545 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6546 : {
6547 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6548 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6549 : }
6550 :
6551 : /* transfer metadata from overview band to this */
6552 : const char *pszPercentValid =
6553 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6554 :
6555 3 : if (pszPercentValid != nullptr)
6556 : {
6557 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6558 3 : pszPercentValid);
6559 : }
6560 : }
6561 3 : return eErr;
6562 : }
6563 : }
6564 :
6565 470 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6566 : {
6567 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6568 0 : return CE_Failure;
6569 : }
6570 :
6571 : /* -------------------------------------------------------------------- */
6572 : /* Read actual data and compute statistics. */
6573 : /* -------------------------------------------------------------------- */
6574 : // Using Welford algorithm:
6575 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6576 : // to compute standard deviation in a more numerically robust way than
6577 : // the difference of the sum of square values with the square of the sum.
6578 : // dfMean and dfM2 are updated at each sample.
6579 : // dfM2 is the sum of square of differences to the current mean.
6580 470 : double dfMin = std::numeric_limits<double>::infinity();
6581 470 : double dfMax = -std::numeric_limits<double>::infinity();
6582 470 : double dfMean = 0.0;
6583 470 : double dfM2 = 0.0;
6584 :
6585 : GDALRasterIOExtraArg sExtraArg;
6586 470 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6587 :
6588 470 : GDALNoDataValues sNoDataValues(this, eDataType);
6589 470 : GDALRasterBand *poMaskBand = nullptr;
6590 470 : if (!sNoDataValues.bGotNoDataValue)
6591 : {
6592 443 : const int l_nMaskFlags = GetMaskFlags();
6593 488 : if (l_nMaskFlags != GMF_ALL_VALID &&
6594 45 : GetColorInterpretation() != GCI_AlphaBand)
6595 : {
6596 45 : poMaskBand = GetMaskBand();
6597 : }
6598 : }
6599 :
6600 470 : bool bSignedByte = false;
6601 470 : if (eDataType == GDT_Byte)
6602 : {
6603 204 : EnablePixelTypeSignedByteWarning(false);
6604 : const char *pszPixelType =
6605 204 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6606 204 : EnablePixelTypeSignedByteWarning(true);
6607 204 : bSignedByte =
6608 204 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6609 : }
6610 :
6611 470 : GUIntBig nSampleCount = 0;
6612 470 : GUIntBig nValidCount = 0;
6613 :
6614 470 : if (bApproxOK && HasArbitraryOverviews())
6615 : {
6616 : /* --------------------------------------------------------------------
6617 : */
6618 : /* Figure out how much the image should be reduced to get an */
6619 : /* approximate value. */
6620 : /* --------------------------------------------------------------------
6621 : */
6622 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6623 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6624 :
6625 0 : int nXReduced = nRasterXSize;
6626 0 : int nYReduced = nRasterYSize;
6627 0 : if (dfReduction > 1.0)
6628 : {
6629 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6630 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6631 :
6632 : // Catch the case of huge resizing ratios here
6633 0 : if (nXReduced == 0)
6634 0 : nXReduced = 1;
6635 0 : if (nYReduced == 0)
6636 0 : nYReduced = 1;
6637 : }
6638 :
6639 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
6640 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6641 :
6642 : const CPLErr eErr =
6643 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6644 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6645 0 : if (eErr != CE_None)
6646 : {
6647 0 : CPLFree(pData);
6648 0 : return eErr;
6649 : }
6650 :
6651 0 : GByte *pabyMaskData = nullptr;
6652 0 : if (poMaskBand)
6653 : {
6654 : pabyMaskData =
6655 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6656 0 : if (!pabyMaskData)
6657 : {
6658 0 : CPLFree(pData);
6659 0 : return CE_Failure;
6660 : }
6661 :
6662 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6663 : pabyMaskData, nXReduced, nYReduced,
6664 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
6665 : {
6666 0 : CPLFree(pData);
6667 0 : CPLFree(pabyMaskData);
6668 0 : return CE_Failure;
6669 : }
6670 : }
6671 :
6672 : /* this isn't the fastest way to do this, but is easier for now */
6673 0 : for (int iY = 0; iY < nYReduced; iY++)
6674 : {
6675 0 : for (int iX = 0; iX < nXReduced; iX++)
6676 : {
6677 0 : const int iOffset = iX + iY * nXReduced;
6678 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6679 0 : continue;
6680 :
6681 0 : bool bValid = true;
6682 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
6683 0 : iOffset, sNoDataValues, bValid);
6684 0 : if (!bValid)
6685 0 : continue;
6686 :
6687 0 : dfMin = std::min(dfMin, dfValue);
6688 0 : dfMax = std::max(dfMax, dfValue);
6689 :
6690 0 : nValidCount++;
6691 0 : if (dfMin == dfMax)
6692 : {
6693 0 : if (nValidCount == 1)
6694 0 : dfMean = dfMin;
6695 : }
6696 : else
6697 : {
6698 0 : const double dfDelta = dfValue - dfMean;
6699 0 : dfMean += dfDelta / nValidCount;
6700 0 : dfM2 += dfDelta * (dfValue - dfMean);
6701 : }
6702 : }
6703 : }
6704 :
6705 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6706 :
6707 0 : CPLFree(pData);
6708 0 : CPLFree(pabyMaskData);
6709 : }
6710 :
6711 : else // No arbitrary overviews.
6712 : {
6713 470 : if (!InitBlockInfo())
6714 0 : return CE_Failure;
6715 :
6716 : /* --------------------------------------------------------------------
6717 : */
6718 : /* Figure out the ratio of blocks we will read to get an */
6719 : /* approximate value. */
6720 : /* --------------------------------------------------------------------
6721 : */
6722 470 : int nSampleRate = 1;
6723 470 : if (bApproxOK)
6724 : {
6725 42 : nSampleRate = static_cast<int>(std::max(
6726 84 : 1.0,
6727 42 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6728 : // We want to avoid probing only the first column of blocks for
6729 : // a square shaped raster, because it is not unlikely that it may
6730 : // be padding only (#6378)
6731 42 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6732 1 : nSampleRate += 1;
6733 : }
6734 470 : if (nSampleRate == 1)
6735 436 : bApproxOK = false;
6736 :
6737 : // Particular case for GDT_Byte that only use integral types for all
6738 : // intermediate computations. Only possible if the number of pixels
6739 : // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6740 : // can fit on a uint64. Should be 99.99999% of cases.
6741 : // For GUInt16, this limits to raster of 4 giga pixels
6742 470 : if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6743 186 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6744 186 : nSampleRate <
6745 186 : GUINTBIG_MAX / (255U * 255U) /
6746 186 : (static_cast<GUInt64>(nBlockXSize) *
6747 186 : static_cast<GUInt64>(nBlockYSize))) ||
6748 284 : (eDataType == GDT_UInt16 &&
6749 29 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6750 29 : nSampleRate <
6751 29 : GUINTBIG_MAX / (65535U * 65535U) /
6752 29 : (static_cast<GUInt64>(nBlockXSize) *
6753 29 : static_cast<GUInt64>(nBlockYSize))))
6754 : {
6755 215 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6756 215 : GUInt32 nMin = nMaxValueType;
6757 215 : GUInt32 nMax = 0;
6758 215 : GUIntBig nSum = 0;
6759 215 : GUIntBig nSumSquare = 0;
6760 : // If no valid nodata, map to invalid value (256 for Byte)
6761 215 : const GUInt32 nNoDataValue =
6762 238 : (sNoDataValues.bGotNoDataValue &&
6763 23 : sNoDataValues.dfNoDataValue >= 0 &&
6764 23 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
6765 23 : fabs(sNoDataValues.dfNoDataValue -
6766 23 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
6767 : 1e-10)) < 1e-10)
6768 238 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
6769 : : nMaxValueType + 1;
6770 :
6771 215 : for (GIntBig iSampleBlock = 0;
6772 12762 : iSampleBlock <
6773 12762 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6774 12547 : iSampleBlock += nSampleRate)
6775 : {
6776 12547 : const int iYBlock =
6777 12547 : static_cast<int>(iSampleBlock / nBlocksPerRow);
6778 12547 : const int iXBlock =
6779 12547 : static_cast<int>(iSampleBlock % nBlocksPerRow);
6780 :
6781 : GDALRasterBlock *const poBlock =
6782 12547 : GetLockedBlockRef(iXBlock, iYBlock);
6783 12546 : if (poBlock == nullptr)
6784 0 : return CE_Failure;
6785 :
6786 12546 : void *const pData = poBlock->GetDataRef();
6787 :
6788 12546 : int nXCheck = 0, nYCheck = 0;
6789 12546 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6790 :
6791 12546 : if (eDataType == GDT_Byte)
6792 : {
6793 : ComputeStatisticsInternal<
6794 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
6795 12076 : f(nXCheck, nBlockXSize, nYCheck,
6796 : static_cast<const GByte *>(pData),
6797 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6798 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6799 : }
6800 : else
6801 : {
6802 : ComputeStatisticsInternal<
6803 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6804 470 : f(nXCheck, nBlockXSize, nYCheck,
6805 : static_cast<const GUInt16 *>(pData),
6806 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6807 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6808 : }
6809 :
6810 12547 : poBlock->DropLock();
6811 :
6812 12547 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
6813 12547 : (static_cast<double>(nBlocksPerRow) *
6814 12547 : nBlocksPerColumn),
6815 : "Compute Statistics", pProgressData))
6816 : {
6817 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
6818 : "User terminated");
6819 0 : return CE_Failure;
6820 : }
6821 : }
6822 :
6823 215 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6824 : {
6825 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6826 0 : return CE_Failure;
6827 : }
6828 :
6829 : /* --------------------------------------------------------------------
6830 : */
6831 : /* Save computed information. */
6832 : /* --------------------------------------------------------------------
6833 : */
6834 215 : if (nValidCount)
6835 206 : dfMean = static_cast<double>(nSum) / nValidCount;
6836 :
6837 : // To avoid potential precision issues when doing the difference,
6838 : // we need to do that computation on 128 bit rather than casting
6839 : // to double
6840 : const GDALUInt128 nTmpForStdDev(
6841 215 : GDALUInt128::Mul(nSumSquare, nValidCount) -
6842 430 : GDALUInt128::Mul(nSum, nSum));
6843 : const double dfStdDev =
6844 215 : nValidCount > 0
6845 215 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6846 215 : : 0.0;
6847 :
6848 215 : if (nValidCount > 0)
6849 : {
6850 206 : if (bApproxOK)
6851 : {
6852 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6853 : }
6854 182 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6855 : {
6856 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6857 : }
6858 206 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
6859 : }
6860 :
6861 215 : SetValidPercent(nSampleCount, nValidCount);
6862 :
6863 : /* --------------------------------------------------------------------
6864 : */
6865 : /* Record results. */
6866 : /* --------------------------------------------------------------------
6867 : */
6868 215 : if (pdfMin != nullptr)
6869 212 : *pdfMin = nValidCount ? nMin : 0;
6870 215 : if (pdfMax != nullptr)
6871 212 : *pdfMax = nValidCount ? nMax : 0;
6872 :
6873 215 : if (pdfMean != nullptr)
6874 208 : *pdfMean = dfMean;
6875 :
6876 215 : if (pdfStdDev != nullptr)
6877 208 : *pdfStdDev = dfStdDev;
6878 :
6879 215 : if (nValidCount > 0)
6880 206 : return CE_None;
6881 :
6882 9 : ReportError(CE_Failure, CPLE_AppDefined,
6883 : "Failed to compute statistics, no valid pixels found "
6884 : "in sampling.");
6885 9 : return CE_Failure;
6886 : }
6887 :
6888 255 : GByte *pabyMaskData = nullptr;
6889 255 : if (poMaskBand)
6890 : {
6891 : pabyMaskData = static_cast<GByte *>(
6892 45 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6893 45 : if (!pabyMaskData)
6894 : {
6895 0 : return CE_Failure;
6896 : }
6897 : }
6898 :
6899 255 : for (GIntBig iSampleBlock = 0;
6900 5889 : iSampleBlock <
6901 5889 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6902 5634 : iSampleBlock += nSampleRate)
6903 : {
6904 5634 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6905 5634 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6906 :
6907 5634 : int nXCheck = 0, nYCheck = 0;
6908 5634 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6909 :
6910 6219 : if (poMaskBand &&
6911 585 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6912 585 : iYBlock * nBlockYSize, nXCheck, nYCheck,
6913 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6914 585 : 0, nBlockXSize, nullptr) != CE_None)
6915 : {
6916 0 : CPLFree(pabyMaskData);
6917 0 : return CE_Failure;
6918 : }
6919 :
6920 : GDALRasterBlock *const poBlock =
6921 5634 : GetLockedBlockRef(iXBlock, iYBlock);
6922 5634 : if (poBlock == nullptr)
6923 : {
6924 0 : CPLFree(pabyMaskData);
6925 0 : return CE_Failure;
6926 : }
6927 :
6928 5634 : void *const pData = poBlock->GetDataRef();
6929 :
6930 : // This isn't the fastest way to do this, but is easier for now.
6931 13492 : for (int iY = 0; iY < nYCheck; iY++)
6932 : {
6933 4891200 : for (int iX = 0; iX < nXCheck; iX++)
6934 : {
6935 4883340 : const GPtrDiff_t iOffset =
6936 4883340 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6937 4883340 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6938 111829 : continue;
6939 :
6940 4779080 : bool bValid = true;
6941 : double dfValue =
6942 4779080 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6943 4779080 : sNoDataValues, bValid);
6944 :
6945 4779080 : if (!bValid)
6946 7574 : continue;
6947 :
6948 4771510 : dfMin = std::min(dfMin, dfValue);
6949 4771510 : dfMax = std::max(dfMax, dfValue);
6950 :
6951 4771510 : nValidCount++;
6952 4771510 : if (dfMin == dfMax)
6953 : {
6954 2173320 : if (nValidCount == 1)
6955 254 : dfMean = dfMin;
6956 : }
6957 : else
6958 : {
6959 2598180 : const double dfDelta = dfValue - dfMean;
6960 2598180 : dfMean += dfDelta / nValidCount;
6961 2598180 : dfM2 += dfDelta * (dfValue - dfMean);
6962 : }
6963 : }
6964 : }
6965 :
6966 5634 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6967 :
6968 5634 : poBlock->DropLock();
6969 :
6970 5634 : if (!pfnProgress(
6971 5634 : static_cast<double>(iSampleBlock) /
6972 5634 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6973 : "Compute Statistics", pProgressData))
6974 : {
6975 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6976 0 : CPLFree(pabyMaskData);
6977 0 : return CE_Failure;
6978 : }
6979 : }
6980 :
6981 255 : CPLFree(pabyMaskData);
6982 : }
6983 :
6984 255 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6985 : {
6986 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6987 0 : return CE_Failure;
6988 : }
6989 :
6990 : /* -------------------------------------------------------------------- */
6991 : /* Save computed information. */
6992 : /* -------------------------------------------------------------------- */
6993 255 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
6994 :
6995 255 : if (nValidCount > 0)
6996 : {
6997 254 : if (bApproxOK)
6998 : {
6999 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7000 : }
7001 246 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7002 : {
7003 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7004 : }
7005 254 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7006 : }
7007 : else
7008 : {
7009 1 : dfMin = 0.0;
7010 1 : dfMax = 0.0;
7011 : }
7012 :
7013 255 : SetValidPercent(nSampleCount, nValidCount);
7014 :
7015 : /* -------------------------------------------------------------------- */
7016 : /* Record results. */
7017 : /* -------------------------------------------------------------------- */
7018 255 : if (pdfMin != nullptr)
7019 252 : *pdfMin = dfMin;
7020 255 : if (pdfMax != nullptr)
7021 252 : *pdfMax = dfMax;
7022 :
7023 255 : if (pdfMean != nullptr)
7024 250 : *pdfMean = dfMean;
7025 :
7026 255 : if (pdfStdDev != nullptr)
7027 250 : *pdfStdDev = dfStdDev;
7028 :
7029 255 : if (nValidCount > 0)
7030 254 : return CE_None;
7031 :
7032 1 : ReportError(
7033 : CE_Failure, CPLE_AppDefined,
7034 : "Failed to compute statistics, no valid pixels found in sampling.");
7035 1 : return CE_Failure;
7036 : }
7037 :
7038 : /************************************************************************/
7039 : /* GDALComputeRasterStatistics() */
7040 : /************************************************************************/
7041 :
7042 : /**
7043 : * \brief Compute image statistics.
7044 : *
7045 : * @see GDALRasterBand::ComputeStatistics()
7046 : */
7047 :
7048 157 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7049 : int bApproxOK, double *pdfMin,
7050 : double *pdfMax, double *pdfMean,
7051 : double *pdfStdDev,
7052 : GDALProgressFunc pfnProgress,
7053 : void *pProgressData)
7054 :
7055 : {
7056 157 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7057 :
7058 157 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7059 :
7060 157 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7061 157 : pdfStdDev, pfnProgress, pProgressData);
7062 : }
7063 :
7064 : /************************************************************************/
7065 : /* SetStatistics() */
7066 : /************************************************************************/
7067 :
7068 : /**
7069 : * \brief Set statistics on band.
7070 : *
7071 : * This method can be used to store min/max/mean/standard deviation
7072 : * statistics on a raster band.
7073 : *
7074 : * The default implementation stores them as metadata, and will only work
7075 : * on formats that can save arbitrary metadata. This method cannot detect
7076 : * whether metadata will be properly saved and so may return CE_None even
7077 : * if the statistics will never be saved.
7078 : *
7079 : * This method is the same as the C function GDALSetRasterStatistics().
7080 : *
7081 : * @param dfMin minimum pixel value.
7082 : *
7083 : * @param dfMax maximum pixel value.
7084 : *
7085 : * @param dfMean mean (average) of all pixel values.
7086 : *
7087 : * @param dfStdDev Standard deviation of all pixel values.
7088 : *
7089 : * @return CE_None on success or CE_Failure on failure.
7090 : */
7091 :
7092 493 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7093 : double dfStdDev)
7094 :
7095 : {
7096 493 : char szValue[128] = {0};
7097 :
7098 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7099 493 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
7100 :
7101 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7102 493 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7103 :
7104 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7105 493 : SetMetadataItem("STATISTICS_MEAN", szValue);
7106 :
7107 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7108 493 : SetMetadataItem("STATISTICS_STDDEV", szValue);
7109 :
7110 493 : return CE_None;
7111 : }
7112 :
7113 : /************************************************************************/
7114 : /* GDALSetRasterStatistics() */
7115 : /************************************************************************/
7116 :
7117 : /**
7118 : * \brief Set statistics on band.
7119 : *
7120 : * @see GDALRasterBand::SetStatistics()
7121 : */
7122 :
7123 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7124 : double dfMax, double dfMean,
7125 : double dfStdDev)
7126 :
7127 : {
7128 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7129 :
7130 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7131 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7132 : }
7133 :
7134 : /************************************************************************/
7135 : /* ComputeRasterMinMax() */
7136 : /************************************************************************/
7137 :
7138 : template <class T, bool HAS_NODATA>
7139 120175 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7140 : T *pMax)
7141 : {
7142 120175 : T min0 = *pMin;
7143 120175 : T max0 = *pMax;
7144 120175 : T min1 = *pMin;
7145 120175 : T max1 = *pMax;
7146 : size_t i;
7147 214453 : for (i = 0; i + 1 < nElts; i += 2)
7148 : {
7149 81892 : if (!HAS_NODATA || buffer[i] != nodataValue)
7150 : {
7151 94278 : min0 = std::min(min0, buffer[i]);
7152 94278 : max0 = std::max(max0, buffer[i]);
7153 : }
7154 81892 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7155 : {
7156 94278 : min1 = std::min(min1, buffer[i + 1]);
7157 94278 : max1 = std::max(max1, buffer[i + 1]);
7158 : }
7159 : }
7160 120175 : T min = std::min(min0, min1);
7161 120175 : T max = std::max(max0, max1);
7162 120175 : if (i < nElts)
7163 : {
7164 118460 : if (!HAS_NODATA || buffer[i] != nodataValue)
7165 : {
7166 118480 : min = std::min(min, buffer[i]);
7167 118480 : max = std::max(max, buffer[i]);
7168 : }
7169 : }
7170 120175 : *pMin = min;
7171 120175 : *pMax = max;
7172 120175 : }
7173 :
7174 : template <GDALDataType eDataType, bool bSignedByte>
7175 : static void
7176 11416 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7177 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7178 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
7179 : {
7180 11416 : double dfLocalMin = dfMin;
7181 11416 : double dfLocalMax = dfMax;
7182 :
7183 40981 : for (int iY = 0; iY < nYCheck; iY++)
7184 : {
7185 18964243 : for (int iX = 0; iX < nXCheck; iX++)
7186 : {
7187 18934695 : const GPtrDiff_t iOffset =
7188 18934695 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7189 18934695 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7190 3460312 : continue;
7191 18839952 : bool bValid = true;
7192 18839952 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7193 : iOffset, sNoDataValues, bValid);
7194 18839952 : if (!bValid)
7195 3365580 : continue;
7196 :
7197 15474340 : dfLocalMin = std::min(dfLocalMin, dfValue);
7198 15474340 : dfLocalMax = std::max(dfLocalMax, dfValue);
7199 : }
7200 : }
7201 :
7202 11416 : dfMin = dfLocalMin;
7203 11416 : dfMax = dfLocalMax;
7204 11416 : }
7205 :
7206 11416 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
7207 : bool bSignedByte, int nXCheck, int nYCheck,
7208 : int nBlockXSize,
7209 : const GDALNoDataValues &sNoDataValues,
7210 : const GByte *pabyMaskData, double &dfMin,
7211 : double &dfMax)
7212 : {
7213 11416 : switch (eDataType)
7214 : {
7215 0 : case GDT_Unknown:
7216 0 : CPLAssert(false);
7217 : break;
7218 672 : case GDT_Byte:
7219 672 : if (bSignedByte)
7220 : {
7221 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
7222 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7223 : pabyMaskData, dfMin, dfMax);
7224 : }
7225 : else
7226 : {
7227 669 : ComputeMinMaxGeneric<GDT_Byte, false>(
7228 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7229 : pabyMaskData, dfMin, dfMax);
7230 : }
7231 672 : break;
7232 106 : case GDT_Int8:
7233 106 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
7234 : nBlockXSize, sNoDataValues,
7235 : pabyMaskData, dfMin, dfMax);
7236 106 : break;
7237 200 : case GDT_UInt16:
7238 200 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
7239 : nBlockXSize, sNoDataValues,
7240 : pabyMaskData, dfMin, dfMax);
7241 200 : break;
7242 1 : case GDT_Int16:
7243 1 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
7244 : nBlockXSize, sNoDataValues,
7245 : pabyMaskData, dfMin, dfMax);
7246 1 : break;
7247 201 : case GDT_UInt32:
7248 201 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
7249 : nBlockXSize, sNoDataValues,
7250 : pabyMaskData, dfMin, dfMax);
7251 201 : break;
7252 1048 : case GDT_Int32:
7253 1048 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
7254 : nBlockXSize, sNoDataValues,
7255 : pabyMaskData, dfMin, dfMax);
7256 1048 : break;
7257 17 : case GDT_UInt64:
7258 17 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
7259 : nBlockXSize, sNoDataValues,
7260 : pabyMaskData, dfMin, dfMax);
7261 17 : break;
7262 29 : case GDT_Int64:
7263 29 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
7264 : nBlockXSize, sNoDataValues,
7265 : pabyMaskData, dfMin, dfMax);
7266 29 : break;
7267 0 : case GDT_Float16:
7268 0 : ComputeMinMaxGeneric<GDT_Float16, false>(
7269 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7270 : pabyMaskData, dfMin, dfMax);
7271 0 : break;
7272 5550 : case GDT_Float32:
7273 5550 : ComputeMinMaxGeneric<GDT_Float32, false>(
7274 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7275 : pabyMaskData, dfMin, dfMax);
7276 5550 : break;
7277 3482 : case GDT_Float64:
7278 3482 : ComputeMinMaxGeneric<GDT_Float64, false>(
7279 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7280 : pabyMaskData, dfMin, dfMax);
7281 3482 : break;
7282 9 : case GDT_CInt16:
7283 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
7284 : nBlockXSize, sNoDataValues,
7285 : pabyMaskData, dfMin, dfMax);
7286 9 : break;
7287 9 : case GDT_CInt32:
7288 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
7289 : nBlockXSize, sNoDataValues,
7290 : pabyMaskData, dfMin, dfMax);
7291 9 : break;
7292 0 : case GDT_CFloat16:
7293 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
7294 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7295 : pabyMaskData, dfMin, dfMax);
7296 0 : break;
7297 75 : case GDT_CFloat32:
7298 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
7299 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7300 : pabyMaskData, dfMin, dfMax);
7301 75 : break;
7302 17 : case GDT_CFloat64:
7303 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
7304 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7305 : pabyMaskData, dfMin, dfMax);
7306 17 : break;
7307 0 : case GDT_TypeCount:
7308 0 : CPLAssert(false);
7309 : break;
7310 : }
7311 11416 : }
7312 :
7313 765 : static bool ComputeMinMaxGenericIterBlocks(
7314 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
7315 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
7316 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
7317 : double &dfMin, double &dfMax)
7318 :
7319 : {
7320 765 : GByte *pabyMaskData = nullptr;
7321 : int nBlockXSize, nBlockYSize;
7322 765 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7323 :
7324 765 : if (poMaskBand)
7325 : {
7326 : pabyMaskData =
7327 106 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7328 106 : if (!pabyMaskData)
7329 : {
7330 0 : return false;
7331 : }
7332 : }
7333 :
7334 12181 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7335 11416 : iSampleBlock += nSampleRate)
7336 : {
7337 11416 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7338 11416 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7339 :
7340 11416 : int nXCheck = 0, nYCheck = 0;
7341 11416 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7342 :
7343 17148 : if (poMaskBand &&
7344 5732 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7345 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7346 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7347 : nBlockXSize, nullptr) != CE_None)
7348 : {
7349 0 : CPLFree(pabyMaskData);
7350 0 : return false;
7351 : }
7352 :
7353 11416 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7354 11416 : if (poBlock == nullptr)
7355 : {
7356 0 : CPLFree(pabyMaskData);
7357 0 : return false;
7358 : }
7359 :
7360 11416 : void *const pData = poBlock->GetDataRef();
7361 :
7362 11416 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7363 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
7364 : dfMax);
7365 :
7366 11416 : poBlock->DropLock();
7367 : }
7368 :
7369 765 : CPLFree(pabyMaskData);
7370 765 : return true;
7371 : }
7372 :
7373 : /**
7374 : * \brief Compute the min/max values for a band.
7375 : *
7376 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7377 : * be trusted. If it doesn't work, a subsample of blocks will be read to
7378 : * get an approximate min/max. If the band has a nodata value it will
7379 : * be excluded from the minimum and maximum.
7380 : *
7381 : * If bApprox is FALSE, then all pixels will be read and used to compute
7382 : * an exact range.
7383 : *
7384 : * This method is the same as the C function GDALComputeRasterMinMax().
7385 : *
7386 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7387 : * FALSE.
7388 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7389 : * maximum (adfMinMax[1]) are returned.
7390 : *
7391 : * @return CE_None on success or CE_Failure on failure.
7392 : */
7393 :
7394 1752 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7395 : {
7396 : /* -------------------------------------------------------------------- */
7397 : /* Does the driver already know the min/max? */
7398 : /* -------------------------------------------------------------------- */
7399 1752 : if (bApproxOK)
7400 : {
7401 23 : int bSuccessMin = FALSE;
7402 23 : int bSuccessMax = FALSE;
7403 :
7404 23 : double dfMin = GetMinimum(&bSuccessMin);
7405 23 : double dfMax = GetMaximum(&bSuccessMax);
7406 :
7407 23 : if (bSuccessMin && bSuccessMax)
7408 : {
7409 1 : adfMinMax[0] = dfMin;
7410 1 : adfMinMax[1] = dfMax;
7411 1 : return CE_None;
7412 : }
7413 : }
7414 :
7415 : /* -------------------------------------------------------------------- */
7416 : /* If we have overview bands, use them for min/max. */
7417 : /* -------------------------------------------------------------------- */
7418 : // cppcheck-suppress knownConditionTrueFalse
7419 1751 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7420 : {
7421 : GDALRasterBand *poBand =
7422 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7423 :
7424 0 : if (poBand != this)
7425 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7426 : }
7427 :
7428 : /* -------------------------------------------------------------------- */
7429 : /* Read actual data and compute minimum and maximum. */
7430 : /* -------------------------------------------------------------------- */
7431 1751 : GDALNoDataValues sNoDataValues(this, eDataType);
7432 1751 : GDALRasterBand *poMaskBand = nullptr;
7433 1751 : if (!sNoDataValues.bGotNoDataValue)
7434 : {
7435 1502 : const int l_nMaskFlags = GetMaskFlags();
7436 1608 : if (l_nMaskFlags != GMF_ALL_VALID &&
7437 106 : GetColorInterpretation() != GCI_AlphaBand)
7438 : {
7439 106 : poMaskBand = GetMaskBand();
7440 : }
7441 : }
7442 :
7443 1751 : bool bSignedByte = false;
7444 1751 : if (eDataType == GDT_Byte)
7445 : {
7446 776 : EnablePixelTypeSignedByteWarning(false);
7447 : const char *pszPixelType =
7448 776 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7449 776 : EnablePixelTypeSignedByteWarning(true);
7450 776 : bSignedByte =
7451 776 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7452 : }
7453 :
7454 : GDALRasterIOExtraArg sExtraArg;
7455 1751 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7456 :
7457 3502 : GUInt32 nMin = (eDataType == GDT_Byte)
7458 1751 : ? 255
7459 : : 65535; // used for GByte & GUInt16 cases
7460 1751 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
7461 1751 : GInt16 nMinInt16 =
7462 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
7463 1751 : GInt16 nMaxInt16 =
7464 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
7465 1751 : double dfMin =
7466 : std::numeric_limits<double>::infinity(); // used for generic code path
7467 1751 : double dfMax =
7468 : -std::numeric_limits<double>::infinity(); // used for generic code path
7469 1751 : const bool bUseOptimizedPath =
7470 2651 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7471 900 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7472 :
7473 : const auto ComputeMinMaxForBlock =
7474 20652 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
7475 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
7476 241357 : int nYCheck)
7477 : {
7478 20652 : if (eDataType == GDT_Byte && !bSignedByte)
7479 : {
7480 : const bool bHasNoData =
7481 11561 : sNoDataValues.bGotNoDataValue &&
7482 29669 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
7483 11561 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
7484 11561 : sNoDataValues.dfNoDataValue;
7485 18108 : const GUInt32 nNoDataValue =
7486 18108 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
7487 : : 0;
7488 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7489 : ComputeStatisticsInternal<GByte,
7490 : /* COMPUTE_OTHER_STATS = */ false>::
7491 18108 : f(nXCheck, nBufferWidth, nYCheck,
7492 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7493 18108 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7494 : }
7495 2544 : else if (eDataType == GDT_UInt16)
7496 : {
7497 : const bool bHasNoData =
7498 83 : sNoDataValues.bGotNoDataValue &&
7499 1239 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
7500 83 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
7501 83 : sNoDataValues.dfNoDataValue;
7502 1156 : const GUInt32 nNoDataValue =
7503 1156 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
7504 : : 0;
7505 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7506 : ComputeStatisticsInternal<GUInt16,
7507 : /* COMPUTE_OTHER_STATS = */ false>::
7508 1156 : f(nXCheck, nBufferWidth, nYCheck,
7509 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7510 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7511 : }
7512 1388 : else if (eDataType == GDT_Int16)
7513 : {
7514 : const bool bHasNoData =
7515 1214 : sNoDataValues.bGotNoDataValue &&
7516 2602 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
7517 1214 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
7518 1214 : sNoDataValues.dfNoDataValue;
7519 1388 : if (bHasNoData)
7520 : {
7521 1214 : const int16_t nNoDataValue =
7522 1214 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
7523 120117 : for (int iY = 0; iY < nYCheck; iY++)
7524 : {
7525 118903 : ComputeMinMax<int16_t, true>(
7526 118903 : static_cast<const int16_t *>(pData) +
7527 118903 : static_cast<size_t>(iY) * nBufferWidth,
7528 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7529 : }
7530 : }
7531 : else
7532 : {
7533 1446 : for (int iY = 0; iY < nYCheck; iY++)
7534 : {
7535 1272 : ComputeMinMax<int16_t, false>(
7536 1272 : static_cast<const int16_t *>(pData) +
7537 1272 : static_cast<size_t>(iY) * nBufferWidth,
7538 : nXCheck, 0, &nMinInt16, &nMaxInt16);
7539 : }
7540 : }
7541 : }
7542 20652 : };
7543 :
7544 1751 : if (bApproxOK && HasArbitraryOverviews())
7545 : {
7546 : /* --------------------------------------------------------------------
7547 : */
7548 : /* Figure out how much the image should be reduced to get an */
7549 : /* approximate value. */
7550 : /* --------------------------------------------------------------------
7551 : */
7552 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7553 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7554 :
7555 0 : int nXReduced = nRasterXSize;
7556 0 : int nYReduced = nRasterYSize;
7557 0 : if (dfReduction > 1.0)
7558 : {
7559 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7560 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7561 :
7562 : // Catch the case of huge resizing ratios here
7563 0 : if (nXReduced == 0)
7564 0 : nXReduced = 1;
7565 0 : if (nYReduced == 0)
7566 0 : nYReduced = 1;
7567 : }
7568 :
7569 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
7570 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7571 :
7572 : const CPLErr eErr =
7573 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7574 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7575 0 : if (eErr != CE_None)
7576 : {
7577 0 : CPLFree(pData);
7578 0 : return eErr;
7579 : }
7580 :
7581 0 : GByte *pabyMaskData = nullptr;
7582 0 : if (poMaskBand)
7583 : {
7584 : pabyMaskData =
7585 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7586 0 : if (!pabyMaskData)
7587 : {
7588 0 : CPLFree(pData);
7589 0 : return CE_Failure;
7590 : }
7591 :
7592 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7593 : pabyMaskData, nXReduced, nYReduced,
7594 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
7595 : {
7596 0 : CPLFree(pData);
7597 0 : CPLFree(pabyMaskData);
7598 0 : return CE_Failure;
7599 : }
7600 : }
7601 :
7602 0 : if (bUseOptimizedPath)
7603 : {
7604 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7605 : }
7606 : else
7607 : {
7608 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
7609 : nYReduced, nXReduced, sNoDataValues,
7610 : pabyMaskData, dfMin, dfMax);
7611 : }
7612 :
7613 0 : CPLFree(pData);
7614 0 : CPLFree(pabyMaskData);
7615 : }
7616 :
7617 : else // No arbitrary overviews
7618 : {
7619 1751 : if (!InitBlockInfo())
7620 0 : return CE_Failure;
7621 :
7622 : /* --------------------------------------------------------------------
7623 : */
7624 : /* Figure out the ratio of blocks we will read to get an */
7625 : /* approximate value. */
7626 : /* --------------------------------------------------------------------
7627 : */
7628 1751 : int nSampleRate = 1;
7629 :
7630 1751 : if (bApproxOK)
7631 : {
7632 22 : nSampleRate = static_cast<int>(std::max(
7633 44 : 1.0,
7634 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7635 : // We want to avoid probing only the first column of blocks for
7636 : // a square shaped raster, because it is not unlikely that it may
7637 : // be padding only (#6378).
7638 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7639 0 : nSampleRate += 1;
7640 : }
7641 :
7642 1751 : if (bUseOptimizedPath)
7643 : {
7644 986 : for (GIntBig iSampleBlock = 0;
7645 21560 : iSampleBlock <
7646 21560 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7647 20574 : iSampleBlock += nSampleRate)
7648 : {
7649 20653 : const int iYBlock =
7650 20653 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7651 20653 : const int iXBlock =
7652 20653 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7653 :
7654 20653 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7655 20653 : if (poBlock == nullptr)
7656 1 : return CE_Failure;
7657 :
7658 20652 : void *const pData = poBlock->GetDataRef();
7659 :
7660 20652 : int nXCheck = 0, nYCheck = 0;
7661 20652 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7662 :
7663 20652 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7664 :
7665 20652 : poBlock->DropLock();
7666 :
7667 20652 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7668 4108 : nMax == 255)
7669 78 : break;
7670 : }
7671 : }
7672 : else
7673 : {
7674 765 : const GIntBig nTotalBlocks =
7675 765 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7676 765 : if (!ComputeMinMaxGenericIterBlocks(
7677 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7678 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
7679 : {
7680 0 : return CE_Failure;
7681 : }
7682 : }
7683 : }
7684 :
7685 1750 : if (bUseOptimizedPath)
7686 : {
7687 985 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7688 : {
7689 883 : dfMin = nMin;
7690 883 : dfMax = nMax;
7691 : }
7692 102 : else if (eDataType == GDT_Int16)
7693 : {
7694 102 : dfMin = nMinInt16;
7695 102 : dfMax = nMaxInt16;
7696 : }
7697 : }
7698 :
7699 1750 : if (dfMin > dfMax)
7700 : {
7701 9 : adfMinMax[0] = 0;
7702 9 : adfMinMax[1] = 0;
7703 9 : ReportError(
7704 : CE_Failure, CPLE_AppDefined,
7705 : "Failed to compute min/max, no valid pixels found in sampling.");
7706 9 : return CE_Failure;
7707 : }
7708 :
7709 1741 : adfMinMax[0] = dfMin;
7710 1741 : adfMinMax[1] = dfMax;
7711 :
7712 1741 : return CE_None;
7713 : }
7714 :
7715 : /************************************************************************/
7716 : /* GDALComputeRasterMinMax() */
7717 : /************************************************************************/
7718 :
7719 : /**
7720 : * \brief Compute the min/max values for a band.
7721 : *
7722 : * @see GDALRasterBand::ComputeRasterMinMax()
7723 : *
7724 : * @note Prior to GDAL 3.6, this function returned void
7725 : */
7726 :
7727 1601 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7728 : double adfMinMax[2])
7729 :
7730 : {
7731 1601 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7732 :
7733 1601 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7734 1601 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7735 : }
7736 :
7737 : /************************************************************************/
7738 : /* ComputeRasterMinMaxLocation() */
7739 : /************************************************************************/
7740 :
7741 : /**
7742 : * \brief Compute the min/max values for a band, and their location.
7743 : *
7744 : * Pixels whose value matches the nodata value or are masked by the mask
7745 : * band are ignored.
7746 : *
7747 : * If the minimum or maximum value is hit in several locations, it is not
7748 : * specified which one will be returned.
7749 : *
7750 : * @param[out] pdfMin Pointer to the minimum value.
7751 : * @param[out] pdfMax Pointer to the maximum value.
7752 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7753 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7754 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7755 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7756 : *
7757 : * @return CE_None in case of success, CE_Warning if there are no valid values,
7758 : * CE_Failure in case of error.
7759 : *
7760 : * @since GDAL 3.11
7761 : */
7762 :
7763 8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7764 : double *pdfMax, int *pnMinX,
7765 : int *pnMinY, int *pnMaxX,
7766 : int *pnMaxY)
7767 : {
7768 8 : int nMinX = -1;
7769 8 : int nMinY = -1;
7770 8 : int nMaxX = -1;
7771 8 : int nMaxY = -1;
7772 8 : double dfMin = std::numeric_limits<double>::infinity();
7773 8 : double dfMax = -std::numeric_limits<double>::infinity();
7774 8 : if (pdfMin)
7775 5 : *pdfMin = dfMin;
7776 8 : if (pdfMax)
7777 5 : *pdfMax = dfMax;
7778 8 : if (pnMinX)
7779 6 : *pnMinX = nMinX;
7780 8 : if (pnMinY)
7781 6 : *pnMinY = nMinY;
7782 8 : if (pnMaxX)
7783 6 : *pnMaxX = nMaxX;
7784 8 : if (pnMaxY)
7785 6 : *pnMaxY = nMaxY;
7786 :
7787 8 : if (GDALDataTypeIsComplex(eDataType))
7788 : {
7789 0 : CPLError(CE_Failure, CPLE_NotSupported,
7790 : "Complex data type not supported");
7791 0 : return CE_Failure;
7792 : }
7793 :
7794 8 : if (!InitBlockInfo())
7795 0 : return CE_Failure;
7796 :
7797 8 : GDALNoDataValues sNoDataValues(this, eDataType);
7798 8 : GDALRasterBand *poMaskBand = nullptr;
7799 8 : if (!sNoDataValues.bGotNoDataValue)
7800 : {
7801 8 : const int l_nMaskFlags = GetMaskFlags();
7802 9 : if (l_nMaskFlags != GMF_ALL_VALID &&
7803 1 : GetColorInterpretation() != GCI_AlphaBand)
7804 : {
7805 1 : poMaskBand = GetMaskBand();
7806 : }
7807 : }
7808 :
7809 8 : bool bSignedByte = false;
7810 8 : if (eDataType == GDT_Byte)
7811 : {
7812 7 : EnablePixelTypeSignedByteWarning(false);
7813 : const char *pszPixelType =
7814 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7815 7 : EnablePixelTypeSignedByteWarning(true);
7816 7 : bSignedByte =
7817 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7818 : }
7819 :
7820 8 : GByte *pabyMaskData = nullptr;
7821 8 : if (poMaskBand)
7822 : {
7823 : pabyMaskData =
7824 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7825 1 : if (!pabyMaskData)
7826 : {
7827 0 : return CE_Failure;
7828 : }
7829 : }
7830 :
7831 8 : const GIntBig nTotalBlocks =
7832 8 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7833 8 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7834 8 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7835 16 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7836 : {
7837 11 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7838 11 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7839 :
7840 11 : int nXCheck = 0, nYCheck = 0;
7841 11 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7842 :
7843 13 : if (poMaskBand &&
7844 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7845 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7846 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7847 2 : nBlockXSize, nullptr) != CE_None)
7848 : {
7849 0 : CPLFree(pabyMaskData);
7850 0 : return CE_Failure;
7851 : }
7852 :
7853 11 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7854 11 : if (poBlock == nullptr)
7855 : {
7856 0 : CPLFree(pabyMaskData);
7857 0 : return CE_Failure;
7858 : }
7859 :
7860 11 : void *const pData = poBlock->GetDataRef();
7861 :
7862 11 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7863 : {
7864 4 : for (int iY = 0; iY < nYCheck; ++iY)
7865 : {
7866 6 : for (int iX = 0; iX < nXCheck; ++iX)
7867 : {
7868 4 : const GPtrDiff_t iOffset =
7869 4 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7870 4 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7871 2 : continue;
7872 2 : bool bValid = true;
7873 : double dfValue =
7874 2 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
7875 : sNoDataValues, bValid);
7876 2 : if (!bValid)
7877 0 : continue;
7878 2 : if (dfValue < dfMin)
7879 : {
7880 2 : dfMin = dfValue;
7881 2 : nMinX = iXBlock * nBlockXSize + iX;
7882 2 : nMinY = iYBlock * nBlockYSize + iY;
7883 : }
7884 2 : if (dfValue > dfMax)
7885 : {
7886 1 : dfMax = dfValue;
7887 1 : nMaxX = iXBlock * nBlockXSize + iX;
7888 1 : nMaxY = iYBlock * nBlockYSize + iY;
7889 : }
7890 : }
7891 2 : }
7892 : }
7893 : else
7894 : {
7895 9 : size_t pos_min = 0;
7896 9 : size_t pos_max = 0;
7897 9 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7898 9 : if (bNeedsMin && bNeedsMax)
7899 : {
7900 10 : std::tie(pos_min, pos_max) = gdal::minmax_element(
7901 5 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7902 5 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7903 10 : sNoDataValues.dfNoDataValue);
7904 : }
7905 4 : else if (bNeedsMin)
7906 : {
7907 1 : pos_min = gdal::min_element(
7908 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7909 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7910 : sNoDataValues.dfNoDataValue);
7911 : }
7912 3 : else if (bNeedsMax)
7913 : {
7914 2 : pos_max = gdal::max_element(
7915 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7916 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7917 : sNoDataValues.dfNoDataValue);
7918 : }
7919 :
7920 9 : if (bNeedsMin)
7921 : {
7922 6 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7923 6 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7924 6 : bool bValid = true;
7925 : const double dfMinValueBlock =
7926 6 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
7927 : sNoDataValues, bValid);
7928 6 : if (bValid && dfMinValueBlock < dfMin)
7929 : {
7930 5 : dfMin = dfMinValueBlock;
7931 5 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
7932 5 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
7933 : }
7934 : }
7935 :
7936 9 : if (bNeedsMax)
7937 : {
7938 7 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7939 7 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7940 7 : bool bValid = true;
7941 : const double dfMaxValueBlock =
7942 7 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
7943 : sNoDataValues, bValid);
7944 7 : if (bValid && dfMaxValueBlock > dfMax)
7945 : {
7946 5 : dfMax = dfMaxValueBlock;
7947 5 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7948 5 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7949 : }
7950 : }
7951 : }
7952 :
7953 11 : poBlock->DropLock();
7954 :
7955 11 : if (eDataType == GDT_Byte)
7956 : {
7957 10 : if (bNeedsMin && dfMin == 0)
7958 : {
7959 1 : bNeedsMin = false;
7960 : }
7961 10 : if (bNeedsMax && dfMax == 255)
7962 : {
7963 4 : bNeedsMax = false;
7964 : }
7965 10 : if (!bNeedsMin && !bNeedsMax)
7966 : {
7967 3 : break;
7968 : }
7969 : }
7970 : }
7971 :
7972 8 : CPLFree(pabyMaskData);
7973 :
7974 8 : if (pdfMin)
7975 5 : *pdfMin = dfMin;
7976 8 : if (pdfMax)
7977 5 : *pdfMax = dfMax;
7978 8 : if (pnMinX)
7979 6 : *pnMinX = nMinX;
7980 8 : if (pnMinY)
7981 6 : *pnMinY = nMinY;
7982 8 : if (pnMaxX)
7983 6 : *pnMaxX = nMaxX;
7984 8 : if (pnMaxY)
7985 6 : *pnMaxY = nMaxY;
7986 8 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
7987 8 : : CE_None;
7988 : }
7989 :
7990 : /************************************************************************/
7991 : /* GDALComputeRasterMinMaxLocation() */
7992 : /************************************************************************/
7993 :
7994 : /**
7995 : * \brief Compute the min/max values for a band, and their location.
7996 : *
7997 : * @see GDALRasterBand::ComputeRasterMinMax()
7998 : * @since GDAL 3.11
7999 : */
8000 :
8001 6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
8002 : double *pdfMax, int *pnMinX, int *pnMinY,
8003 : int *pnMaxX, int *pnMaxY)
8004 :
8005 : {
8006 6 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
8007 :
8008 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8009 6 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
8010 6 : pnMaxX, pnMaxY);
8011 : }
8012 :
8013 : /************************************************************************/
8014 : /* SetDefaultHistogram() */
8015 : /************************************************************************/
8016 :
8017 : /* FIXME : add proper documentation */
8018 : /**
8019 : * \brief Set default histogram.
8020 : *
8021 : * This method is the same as the C function GDALSetDefaultHistogram() and
8022 : * GDALSetDefaultHistogramEx()
8023 : */
8024 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
8025 : double /* dfMax */,
8026 : int /* nBuckets */,
8027 : GUIntBig * /* panHistogram */)
8028 :
8029 : {
8030 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8031 0 : ReportError(CE_Failure, CPLE_NotSupported,
8032 : "SetDefaultHistogram() not implemented for this format.");
8033 :
8034 0 : return CE_Failure;
8035 : }
8036 :
8037 : /************************************************************************/
8038 : /* GDALSetDefaultHistogram() */
8039 : /************************************************************************/
8040 :
8041 : /**
8042 : * \brief Set default histogram.
8043 : *
8044 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8045 : * 2 billion.
8046 : *
8047 : * @see GDALRasterBand::SetDefaultHistogram()
8048 : * @see GDALSetRasterHistogramEx()
8049 : */
8050 :
8051 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8052 : double dfMax, int nBuckets,
8053 : int *panHistogram)
8054 :
8055 : {
8056 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8057 :
8058 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8059 :
8060 : GUIntBig *panHistogramTemp =
8061 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8062 0 : if (panHistogramTemp == nullptr)
8063 : {
8064 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8065 : "Out of memory in GDALSetDefaultHistogram().");
8066 0 : return CE_Failure;
8067 : }
8068 :
8069 0 : for (int i = 0; i < nBuckets; ++i)
8070 : {
8071 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8072 : }
8073 :
8074 : const CPLErr eErr =
8075 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8076 :
8077 0 : CPLFree(panHistogramTemp);
8078 :
8079 0 : return eErr;
8080 : }
8081 :
8082 : /************************************************************************/
8083 : /* GDALSetDefaultHistogramEx() */
8084 : /************************************************************************/
8085 :
8086 : /**
8087 : * \brief Set default histogram.
8088 : *
8089 : * @see GDALRasterBand::SetDefaultHistogram()
8090 : *
8091 : * @since GDAL 2.0
8092 : */
8093 :
8094 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8095 : double dfMin, double dfMax,
8096 : int nBuckets,
8097 : GUIntBig *panHistogram)
8098 :
8099 : {
8100 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8101 :
8102 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8103 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8104 : }
8105 :
8106 : /************************************************************************/
8107 : /* GetDefaultRAT() */
8108 : /************************************************************************/
8109 :
8110 : /**
8111 : * \brief Fetch default Raster Attribute Table.
8112 : *
8113 : * A RAT will be returned if there is a default one associated with the
8114 : * band, otherwise NULL is returned. The returned RAT is owned by the
8115 : * band and should not be deleted by the application.
8116 : *
8117 : * This method is the same as the C function GDALGetDefaultRAT().
8118 : *
8119 : * @return NULL, or a pointer to an internal RAT owned by the band.
8120 : */
8121 :
8122 173 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8123 :
8124 : {
8125 173 : return nullptr;
8126 : }
8127 :
8128 : /************************************************************************/
8129 : /* GDALGetDefaultRAT() */
8130 : /************************************************************************/
8131 :
8132 : /**
8133 : * \brief Fetch default Raster Attribute Table.
8134 : *
8135 : * @see GDALRasterBand::GetDefaultRAT()
8136 : */
8137 :
8138 1067 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8139 :
8140 : {
8141 1067 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8142 :
8143 1067 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8144 1067 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8145 : }
8146 :
8147 : /************************************************************************/
8148 : /* SetDefaultRAT() */
8149 : /************************************************************************/
8150 :
8151 : /**
8152 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8153 : * \brief Set default Raster Attribute Table.
8154 : *
8155 : * Associates a default RAT with the band. If not implemented for the
8156 : * format a CPLE_NotSupported error will be issued. If successful a copy
8157 : * of the RAT is made, the original remains owned by the caller.
8158 : *
8159 : * This method is the same as the C function GDALSetDefaultRAT().
8160 : *
8161 : * @param poRAT the RAT to assign to the band.
8162 : *
8163 : * @return CE_None on success or CE_Failure if unsupported or otherwise
8164 : * failing.
8165 : */
8166 :
8167 : /**/
8168 : /**/
8169 :
8170 : CPLErr
8171 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8172 : {
8173 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8174 : {
8175 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
8176 0 : ReportError(CE_Failure, CPLE_NotSupported,
8177 : "SetDefaultRAT() not implemented for this format.");
8178 0 : CPLPopErrorHandler();
8179 : }
8180 0 : return CE_Failure;
8181 : }
8182 :
8183 : /************************************************************************/
8184 : /* GDALSetDefaultRAT() */
8185 : /************************************************************************/
8186 :
8187 : /**
8188 : * \brief Set default Raster Attribute Table.
8189 : *
8190 : * @see GDALRasterBand::GDALSetDefaultRAT()
8191 : */
8192 :
8193 18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
8194 : GDALRasterAttributeTableH hRAT)
8195 :
8196 : {
8197 18 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
8198 :
8199 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8200 :
8201 18 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
8202 : }
8203 :
8204 : /************************************************************************/
8205 : /* GetMaskBand() */
8206 : /************************************************************************/
8207 :
8208 : /**
8209 : * \brief Return the mask band associated with the band.
8210 : *
8211 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8212 : * that returns one of four default implementations :
8213 : * <ul>
8214 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8215 : * </li>
8216 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8217 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8218 : * GMF_NODATA | GMF_PER_DATASET.
8219 : * </li>
8220 : * <li>If the band has a nodata value set, an instance of the new
8221 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8222 : * GMF_NODATA.
8223 : * </li>
8224 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
8225 : * to apply to this band (specific rules yet to be determined) and that is of
8226 : * type GDT_Byte then that alpha band will be returned, and the flags
8227 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8228 : * </li>
8229 : * <li>If neither of the above apply, an instance of the new
8230 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8231 : * pixels. The null flags will return GMF_ALL_VALID.
8232 : * </li>
8233 : * </ul>
8234 : *
8235 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
8236 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
8237 : *
8238 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8239 : * dataset, with the same name as the main dataset and suffixed with .msk,
8240 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8241 : * main dataset.
8242 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8243 : * level, where xx matches the band number of a band of the main dataset. The
8244 : * value of those items is a combination of the flags GMF_ALL_VALID,
8245 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8246 : * a band, then the other rules explained above will be used to generate a
8247 : * on-the-fly mask band.
8248 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8249 : *
8250 : * This method is the same as the C function GDALGetMaskBand().
8251 : *
8252 : * @return a valid mask band.
8253 : *
8254 : * @since GDAL 1.5.0
8255 : *
8256 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8257 : *
8258 : */
8259 803018 : GDALRasterBand *GDALRasterBand::GetMaskBand()
8260 :
8261 : {
8262 384337 : const auto HasNoData = [this]()
8263 : {
8264 127785 : int bHaveNoDataRaw = FALSE;
8265 127785 : bool bHaveNoData = false;
8266 127785 : if (eDataType == GDT_Int64)
8267 : {
8268 65 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
8269 65 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8270 : }
8271 127720 : else if (eDataType == GDT_UInt64)
8272 : {
8273 47 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
8274 47 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8275 : }
8276 : else
8277 : {
8278 127673 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
8279 127664 : if (bHaveNoDataRaw &&
8280 127664 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
8281 : {
8282 1006 : bHaveNoData = true;
8283 : }
8284 : }
8285 127782 : return bHaveNoData;
8286 803018 : };
8287 :
8288 803018 : if (poMask != nullptr)
8289 : {
8290 685023 : if (poMask.IsOwned())
8291 : {
8292 318692 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
8293 : {
8294 33202 : if (HasNoData())
8295 : {
8296 9 : InvalidateMaskBand();
8297 : }
8298 : }
8299 288614 : else if (auto poNoDataMaskBand =
8300 288309 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
8301 : {
8302 346 : int bHaveNoDataRaw = FALSE;
8303 346 : bool bIsSame = false;
8304 346 : if (eDataType == GDT_Int64)
8305 11 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
8306 15 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
8307 4 : bHaveNoDataRaw;
8308 335 : else if (eDataType == GDT_UInt64)
8309 11 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8310 15 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8311 4 : bHaveNoDataRaw;
8312 : else
8313 : {
8314 : const double dfNoDataValue =
8315 324 : GetNoDataValue(&bHaveNoDataRaw);
8316 324 : if (bHaveNoDataRaw)
8317 : {
8318 321 : bIsSame =
8319 321 : std::isnan(dfNoDataValue)
8320 321 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8321 290 : : poNoDataMaskBand->m_dfNoDataValue ==
8322 : dfNoDataValue;
8323 : }
8324 : }
8325 346 : if (!bIsSame)
8326 23 : InvalidateMaskBand();
8327 : }
8328 : }
8329 :
8330 695025 : if (poMask)
8331 699956 : return poMask.get();
8332 : }
8333 :
8334 : /* -------------------------------------------------------------------- */
8335 : /* Check for a mask in a .msk file. */
8336 : /* -------------------------------------------------------------------- */
8337 94699 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8338 : {
8339 46 : poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
8340 46 : if (poMask != nullptr)
8341 : {
8342 44 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8343 44 : return poMask.get();
8344 : }
8345 : }
8346 :
8347 : /* -------------------------------------------------------------------- */
8348 : /* Check for NODATA_VALUES metadata. */
8349 : /* -------------------------------------------------------------------- */
8350 94654 : if (poDS != nullptr)
8351 : {
8352 : const char *pszGDALNoDataValues =
8353 94642 : poDS->GetMetadataItem("NODATA_VALUES");
8354 94642 : if (pszGDALNoDataValues != nullptr)
8355 : {
8356 68 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
8357 : pszGDALNoDataValues, " ", FALSE, FALSE);
8358 :
8359 : // Make sure we have as many values as bands.
8360 136 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
8361 68 : poDS->GetRasterCount() != 0)
8362 : {
8363 : // Make sure that all bands have the same data type
8364 : // This is clearly not a fundamental condition, just a
8365 : // condition to make implementation easier.
8366 68 : GDALDataType eDT = GDT_Unknown;
8367 68 : int i = 0; // Used after for.
8368 270 : for (; i < poDS->GetRasterCount(); ++i)
8369 : {
8370 202 : if (i == 0)
8371 68 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8372 134 : else if (eDT !=
8373 134 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
8374 : {
8375 0 : break;
8376 : }
8377 : }
8378 68 : if (i == poDS->GetRasterCount())
8379 : {
8380 68 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8381 : try
8382 : {
8383 68 : poMask.reset(
8384 136 : std::make_unique<GDALNoDataValuesMaskBand>(poDS));
8385 : }
8386 0 : catch (const std::bad_alloc &)
8387 : {
8388 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8389 0 : poMask.reset();
8390 : }
8391 68 : CSLDestroy(papszGDALNoDataValues);
8392 68 : return poMask.get();
8393 : }
8394 : else
8395 : {
8396 0 : ReportError(CE_Warning, CPLE_AppDefined,
8397 : "All bands should have the same type in "
8398 : "order the NODATA_VALUES metadata item "
8399 : "to be used as a mask.");
8400 : }
8401 : }
8402 : else
8403 : {
8404 0 : ReportError(
8405 : CE_Warning, CPLE_AppDefined,
8406 : "NODATA_VALUES metadata item doesn't have the same number "
8407 : "of values as the number of bands. "
8408 : "Ignoring it for mask.");
8409 : }
8410 :
8411 0 : CSLDestroy(papszGDALNoDataValues);
8412 : }
8413 : }
8414 :
8415 : /* -------------------------------------------------------------------- */
8416 : /* Check for nodata case. */
8417 : /* -------------------------------------------------------------------- */
8418 94586 : if (HasNoData())
8419 : {
8420 1030 : nMaskFlags = GMF_NODATA;
8421 : try
8422 : {
8423 1030 : poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
8424 : }
8425 0 : catch (const std::bad_alloc &)
8426 : {
8427 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8428 0 : poMask.reset();
8429 : }
8430 1030 : return poMask.get();
8431 : }
8432 :
8433 : /* -------------------------------------------------------------------- */
8434 : /* Check for alpha case. */
8435 : /* -------------------------------------------------------------------- */
8436 93544 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8437 187688 : this == poDS->GetRasterBand(1) &&
8438 586 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8439 : {
8440 223 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8441 : {
8442 179 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8443 179 : poMask.resetNotOwned(poDS->GetRasterBand(2));
8444 179 : return poMask.get();
8445 : }
8446 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8447 : {
8448 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8449 : try
8450 : {
8451 23 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
8452 46 : poDS->GetRasterBand(2)));
8453 : }
8454 0 : catch (const std::bad_alloc &)
8455 : {
8456 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8457 0 : poMask.reset();
8458 : }
8459 23 : return poMask.get();
8460 : }
8461 : }
8462 :
8463 93343 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8464 2917 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8465 187395 : this == poDS->GetRasterBand(3)) &&
8466 2272 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8467 : {
8468 1398 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8469 : {
8470 1351 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8471 1351 : poMask.resetNotOwned(poDS->GetRasterBand(4));
8472 1350 : return poMask.get();
8473 : }
8474 47 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8475 : {
8476 35 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8477 : try
8478 : {
8479 35 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
8480 70 : poDS->GetRasterBand(4)));
8481 : }
8482 0 : catch (const std::bad_alloc &)
8483 : {
8484 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8485 0 : poMask.reset();
8486 : }
8487 35 : return poMask.get();
8488 : }
8489 : }
8490 :
8491 : /* -------------------------------------------------------------------- */
8492 : /* Fallback to all valid case. */
8493 : /* -------------------------------------------------------------------- */
8494 91969 : nMaskFlags = GMF_ALL_VALID;
8495 : try
8496 : {
8497 91969 : poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
8498 : }
8499 0 : catch (const std::bad_alloc &)
8500 : {
8501 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8502 0 : poMask.reset();
8503 : }
8504 :
8505 91969 : return poMask.get();
8506 : }
8507 :
8508 : /************************************************************************/
8509 : /* GDALGetMaskBand() */
8510 : /************************************************************************/
8511 :
8512 : /**
8513 : * \brief Return the mask band associated with the band.
8514 : *
8515 : * @see GDALRasterBand::GetMaskBand()
8516 : */
8517 :
8518 10994 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8519 :
8520 : {
8521 10994 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8522 :
8523 10994 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8524 10994 : return poBand->GetMaskBand();
8525 : }
8526 :
8527 : /************************************************************************/
8528 : /* GetMaskFlags() */
8529 : /************************************************************************/
8530 :
8531 : /**
8532 : * \brief Return the status flags of the mask band associated with the band.
8533 : *
8534 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8535 : * the following available definitions that may be extended in the future:
8536 : * <ul>
8537 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8538 : * 255. When used this will normally be the only flag set.
8539 : * </li>
8540 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8541 : * dataset.
8542 : * </li>
8543 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8544 : * and may have values other than 0 and 255.
8545 : * </li>
8546 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8547 : * nodata values. (mutually exclusive of GMF_ALPHA)
8548 : * </li>
8549 : * </ul>
8550 : *
8551 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8552 : * that returns one of four default implementations:
8553 : * <ul>
8554 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8555 : * </li>
8556 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8557 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8558 : * GMF_NODATA | GMF_PER_DATASET.
8559 : * </li>
8560 : * <li>If the band has a nodata value set, an instance of the new
8561 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8562 : * GMF_NODATA.
8563 : * </li>
8564 : * <li>If there is no nodata value, but the dataset has an alpha band that
8565 : * seems to apply to this band (specific rules yet to be determined) and that is
8566 : * of type GDT_Byte then that alpha band will be returned, and the flags
8567 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8568 : * </li>
8569 : * <li>If neither of the above apply, an instance of the new
8570 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8571 : * pixels. The null flags will return GMF_ALL_VALID.
8572 : * </li>
8573 : * </ul>
8574 : *
8575 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8576 : * dataset, with the same name as the main dataset and suffixed with .msk,
8577 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8578 : * main dataset.
8579 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8580 : * level, where xx matches the band number of a band of the main dataset. The
8581 : * value of those items is a combination of the flags GMF_ALL_VALID,
8582 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8583 : * a band, then the other rules explained above will be used to generate a
8584 : * on-the-fly mask band.
8585 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8586 : *
8587 : * This method is the same as the C function GDALGetMaskFlags().
8588 : *
8589 : * @since GDAL 1.5.0
8590 : *
8591 : * @return a valid mask band.
8592 : *
8593 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8594 : *
8595 : */
8596 149571 : int GDALRasterBand::GetMaskFlags()
8597 :
8598 : {
8599 : // If we don't have a band yet, force this now so that the masks value
8600 : // will be initialized.
8601 :
8602 149571 : if (poMask == nullptr)
8603 93407 : GetMaskBand();
8604 :
8605 149567 : return nMaskFlags;
8606 : }
8607 :
8608 : /************************************************************************/
8609 : /* GDALGetMaskFlags() */
8610 : /************************************************************************/
8611 :
8612 : /**
8613 : * \brief Return the status flags of the mask band associated with the band.
8614 : *
8615 : * @see GDALRasterBand::GetMaskFlags()
8616 : */
8617 :
8618 6798 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8619 :
8620 : {
8621 6798 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8622 :
8623 6798 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8624 6798 : return poBand->GetMaskFlags();
8625 : }
8626 :
8627 : /************************************************************************/
8628 : /* InvalidateMaskBand() */
8629 : /************************************************************************/
8630 :
8631 : //! @cond Doxygen_Suppress
8632 1910140 : void GDALRasterBand::InvalidateMaskBand()
8633 : {
8634 1910140 : poMask.reset();
8635 1910130 : nMaskFlags = 0;
8636 1910130 : }
8637 :
8638 : //! @endcond
8639 :
8640 : /************************************************************************/
8641 : /* CreateMaskBand() */
8642 : /************************************************************************/
8643 :
8644 : /**
8645 : * \brief Adds a mask band to the current band
8646 : *
8647 : * The default implementation of the CreateMaskBand() method is implemented
8648 : * based on similar rules to the .ovr handling implemented using the
8649 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8650 : * be created with the same basename as the original file, and it will have
8651 : * as many bands as the original image (or just one for GMF_PER_DATASET).
8652 : * The mask images will be deflate compressed tiled images with the same
8653 : * block size as the original image if possible.
8654 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8655 : * level, where xx matches the band number of a band of the main dataset. The
8656 : * value of those items will be the one of the nFlagsIn parameter.
8657 : *
8658 : * Note that if you got a mask band with a previous call to GetMaskBand(),
8659 : * it might be invalidated by CreateMaskBand(). So you have to call
8660 : * GetMaskBand() again.
8661 : *
8662 : * This method is the same as the C function GDALCreateMaskBand().
8663 : *
8664 : * @since GDAL 1.5.0
8665 : *
8666 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8667 : *
8668 : * @return CE_None on success or CE_Failure on an error.
8669 : *
8670 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8671 : * @see GDALDataset::CreateMaskBand()
8672 : *
8673 : */
8674 :
8675 9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8676 :
8677 : {
8678 9 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8679 : {
8680 9 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8681 9 : if (eErr != CE_None)
8682 1 : return eErr;
8683 :
8684 8 : InvalidateMaskBand();
8685 :
8686 8 : return CE_None;
8687 : }
8688 :
8689 0 : ReportError(CE_Failure, CPLE_NotSupported,
8690 : "CreateMaskBand() not supported for this band.");
8691 :
8692 0 : return CE_Failure;
8693 : }
8694 :
8695 : /************************************************************************/
8696 : /* GDALCreateMaskBand() */
8697 : /************************************************************************/
8698 :
8699 : /**
8700 : * \brief Adds a mask band to the current band
8701 : *
8702 : * @see GDALRasterBand::CreateMaskBand()
8703 : */
8704 :
8705 33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8706 :
8707 : {
8708 33 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8709 :
8710 33 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8711 33 : return poBand->CreateMaskBand(nFlags);
8712 : }
8713 :
8714 : /************************************************************************/
8715 : /* IsMaskBand() */
8716 : /************************************************************************/
8717 :
8718 : /**
8719 : * \brief Returns whether a band is a mask band.
8720 : *
8721 : * Mask band must be understood in the broad term: it can be a per-dataset
8722 : * mask band, an alpha band, or an implicit mask band.
8723 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8724 : *
8725 : * This method is the same as the C function GDALIsMaskBand().
8726 : *
8727 : * @return true if the band is a mask band.
8728 : *
8729 : * @see GDALDataset::CreateMaskBand()
8730 : *
8731 : * @since GDAL 3.5.0
8732 : *
8733 : */
8734 :
8735 439 : bool GDALRasterBand::IsMaskBand() const
8736 : {
8737 : // The GeoTIFF driver, among others, override this method to
8738 : // also handle external .msk bands.
8739 439 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8740 439 : GCI_AlphaBand;
8741 : }
8742 :
8743 : /************************************************************************/
8744 : /* GDALIsMaskBand() */
8745 : /************************************************************************/
8746 :
8747 : /**
8748 : * \brief Returns whether a band is a mask band.
8749 : *
8750 : * Mask band must be understood in the broad term: it can be a per-dataset
8751 : * mask band, an alpha band, or an implicit mask band.
8752 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8753 : *
8754 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8755 : *
8756 : * @return true if the band is a mask band.
8757 : *
8758 : * @see GDALRasterBand::IsMaskBand()
8759 : *
8760 : * @since GDAL 3.5.0
8761 : *
8762 : */
8763 :
8764 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
8765 :
8766 : {
8767 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8768 :
8769 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8770 37 : return poBand->IsMaskBand();
8771 : }
8772 :
8773 : /************************************************************************/
8774 : /* GetMaskValueRange() */
8775 : /************************************************************************/
8776 :
8777 : /**
8778 : * \brief Returns the range of values that a mask band can take.
8779 : *
8780 : * @return the range of values that a mask band can take.
8781 : *
8782 : * @since GDAL 3.5.0
8783 : *
8784 : */
8785 :
8786 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8787 : {
8788 0 : return GMVR_UNKNOWN;
8789 : }
8790 :
8791 : /************************************************************************/
8792 : /* GetIndexColorTranslationTo() */
8793 : /************************************************************************/
8794 :
8795 : /**
8796 : * \brief Compute translation table for color tables.
8797 : *
8798 : * When the raster band has a palette index, it may be useful to compute
8799 : * the "translation" of this palette to the palette of another band.
8800 : * The translation tries to do exact matching first, and then approximate
8801 : * matching if no exact matching is possible.
8802 : * This method returns a table such that table[i] = j where i is an index
8803 : * of the 'this' rasterband and j the corresponding index for the reference
8804 : * rasterband.
8805 : *
8806 : * This method is thought as internal to GDAL and is used for drivers
8807 : * like RPFTOC.
8808 : *
8809 : * The implementation only supports 1-byte palette rasterbands.
8810 : *
8811 : * @param poReferenceBand the raster band
8812 : * @param pTranslationTable an already allocated translation table (at least 256
8813 : * bytes), or NULL to let the method allocate it
8814 : * @param pApproximateMatching a pointer to a flag that is set if the matching
8815 : * is approximate. May be NULL.
8816 : *
8817 : * @return a translation table if the two bands are palette index and that they
8818 : * do not match or NULL in other cases. The table must be freed with CPLFree if
8819 : * NULL was passed for pTranslationTable.
8820 : */
8821 :
8822 : unsigned char *
8823 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8824 : unsigned char *pTranslationTable,
8825 : int *pApproximateMatching)
8826 : {
8827 4 : if (poReferenceBand == nullptr)
8828 0 : return nullptr;
8829 :
8830 : // cppcheck-suppress knownConditionTrueFalse
8831 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8832 : // cppcheck-suppress knownConditionTrueFalse
8833 4 : GetColorInterpretation() == GCI_PaletteIndex &&
8834 12 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
8835 4 : GetRasterDataType() == GDT_Byte)
8836 : {
8837 4 : const GDALColorTable *srcColorTable = GetColorTable();
8838 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8839 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
8840 : {
8841 4 : const int nEntries = srcColorTable->GetColorEntryCount();
8842 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
8843 :
8844 4 : int bHasNoDataValueSrc = FALSE;
8845 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8846 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8847 4 : dfNoDataValueSrc <= 255 &&
8848 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8849 0 : bHasNoDataValueSrc = FALSE;
8850 4 : const int noDataValueSrc =
8851 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8852 :
8853 4 : int bHasNoDataValueRef = FALSE;
8854 : const double dfNoDataValueRef =
8855 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8856 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8857 3 : dfNoDataValueRef <= 255 &&
8858 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8859 1 : bHasNoDataValueRef = FALSE;
8860 4 : const int noDataValueRef =
8861 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8862 :
8863 4 : bool samePalette = false;
8864 :
8865 4 : if (pApproximateMatching)
8866 3 : *pApproximateMatching = FALSE;
8867 :
8868 4 : if (nEntries == nRefEntries &&
8869 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
8870 3 : (bHasNoDataValueSrc == FALSE ||
8871 : noDataValueSrc == noDataValueRef))
8872 : {
8873 3 : samePalette = true;
8874 654 : for (int i = 0; i < nEntries; ++i)
8875 : {
8876 651 : if (noDataValueSrc == i)
8877 3 : continue;
8878 : const GDALColorEntry *entry =
8879 648 : srcColorTable->GetColorEntry(i);
8880 : const GDALColorEntry *entryRef =
8881 648 : destColorTable->GetColorEntry(i);
8882 648 : if (entry->c1 != entryRef->c1 ||
8883 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8884 : {
8885 0 : samePalette = false;
8886 : }
8887 : }
8888 : }
8889 :
8890 4 : if (!samePalette)
8891 : {
8892 1 : if (pTranslationTable == nullptr)
8893 : {
8894 : pTranslationTable = static_cast<unsigned char *>(
8895 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8896 1 : if (pTranslationTable == nullptr)
8897 1 : return nullptr;
8898 : }
8899 :
8900 : // Trying to remap the product palette on the subdataset
8901 : // palette.
8902 5 : for (int i = 0; i < nEntries; ++i)
8903 : {
8904 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8905 : noDataValueSrc == i)
8906 0 : continue;
8907 : const GDALColorEntry *entry =
8908 4 : srcColorTable->GetColorEntry(i);
8909 4 : bool bMatchFound = false;
8910 13 : for (int j = 0; j < nRefEntries; ++j)
8911 : {
8912 10 : if (bHasNoDataValueRef && noDataValueRef == j)
8913 0 : continue;
8914 : const GDALColorEntry *entryRef =
8915 10 : destColorTable->GetColorEntry(j);
8916 10 : if (entry->c1 == entryRef->c1 &&
8917 2 : entry->c2 == entryRef->c2 &&
8918 2 : entry->c3 == entryRef->c3)
8919 : {
8920 1 : pTranslationTable[i] =
8921 : static_cast<unsigned char>(j);
8922 1 : bMatchFound = true;
8923 1 : break;
8924 : }
8925 : }
8926 4 : if (!bMatchFound)
8927 : {
8928 : // No exact match. Looking for closest color now.
8929 3 : int best_j = 0;
8930 3 : int best_distance = 0;
8931 3 : if (pApproximateMatching)
8932 0 : *pApproximateMatching = TRUE;
8933 12 : for (int j = 0; j < nRefEntries; ++j)
8934 : {
8935 : const GDALColorEntry *entryRef =
8936 9 : destColorTable->GetColorEntry(j);
8937 9 : int distance = (entry->c1 - entryRef->c1) *
8938 9 : (entry->c1 - entryRef->c1) +
8939 9 : (entry->c2 - entryRef->c2) *
8940 9 : (entry->c2 - entryRef->c2) +
8941 9 : (entry->c3 - entryRef->c3) *
8942 9 : (entry->c3 - entryRef->c3);
8943 9 : if (j == 0 || distance < best_distance)
8944 : {
8945 7 : best_j = j;
8946 7 : best_distance = distance;
8947 : }
8948 : }
8949 3 : pTranslationTable[i] =
8950 : static_cast<unsigned char>(best_j);
8951 : }
8952 : }
8953 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
8954 0 : pTranslationTable[noDataValueSrc] =
8955 : static_cast<unsigned char>(noDataValueRef);
8956 :
8957 1 : return pTranslationTable;
8958 : }
8959 : }
8960 : }
8961 3 : return nullptr;
8962 : }
8963 :
8964 : /************************************************************************/
8965 : /* SetFlushBlockErr() */
8966 : /************************************************************************/
8967 :
8968 : /**
8969 : * \brief Store that an error occurred while writing a dirty block.
8970 : *
8971 : * This function stores the fact that an error occurred while writing a dirty
8972 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8973 : * flushed when the block cache get full, it is not convenient/possible to
8974 : * report that a dirty block could not be written correctly. This function
8975 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8976 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8977 : * places where the user can easily match the error with the relevant dataset.
8978 : */
8979 :
8980 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8981 : {
8982 0 : eFlushBlockErr = eErr;
8983 0 : }
8984 :
8985 : /************************************************************************/
8986 : /* IncDirtyBlocks() */
8987 : /************************************************************************/
8988 :
8989 : /**
8990 : * \brief Increment/decrement the number of dirty blocks
8991 : */
8992 :
8993 750060 : void GDALRasterBand::IncDirtyBlocks(int nInc)
8994 : {
8995 750060 : if (poBandBlockCache)
8996 750060 : poBandBlockCache->IncDirtyBlocks(nInc);
8997 750059 : }
8998 :
8999 : /************************************************************************/
9000 : /* ReportError() */
9001 : /************************************************************************/
9002 :
9003 : #ifndef DOXYGEN_XML
9004 : /**
9005 : * \brief Emits an error related to a raster band.
9006 : *
9007 : * This function is a wrapper for regular CPLError(). The only difference
9008 : * with CPLError() is that it prepends the error message with the dataset
9009 : * name and the band number.
9010 : *
9011 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
9012 : * @param err_no the error number (CPLE_*) from cpl_error.h.
9013 : * @param fmt a printf() style format string. Any additional arguments
9014 : * will be treated as arguments to fill in this format in a manner
9015 : * similar to printf().
9016 : *
9017 : * @since GDAL 1.9.0
9018 : */
9019 :
9020 2471 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
9021 : const char *fmt, ...) const
9022 : {
9023 : va_list args;
9024 :
9025 2471 : va_start(args, fmt);
9026 :
9027 2471 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
9028 2471 : pszDSName = CPLGetFilename(pszDSName);
9029 2471 : if (pszDSName[0] != '\0')
9030 : {
9031 2402 : CPLError(eErrClass, err_no, "%s",
9032 4804 : CPLString()
9033 2402 : .Printf("%s, band %d: ", pszDSName, GetBand())
9034 4804 : .append(CPLString().vPrintf(fmt, args))
9035 : .c_str());
9036 : }
9037 : else
9038 : {
9039 69 : CPLErrorV(eErrClass, err_no, fmt, args);
9040 : }
9041 :
9042 2471 : va_end(args);
9043 2471 : }
9044 : #endif
9045 :
9046 : /************************************************************************/
9047 : /* GetVirtualMemAuto() */
9048 : /************************************************************************/
9049 :
9050 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9051 : *
9052 : * Only supported on Linux and Unix systems with mmap() for now.
9053 : *
9054 : * This method allows creating a virtual memory object for a GDALRasterBand,
9055 : * that exposes the whole image data as a virtual array.
9056 : *
9057 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9058 : * specialized implementation, such as for raw files, may also directly use
9059 : * mechanisms of the operating system to create a view of the underlying file
9060 : * into virtual memory ( CPLVirtualMemFileMapNew() )
9061 : *
9062 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9063 : * offer a specialized implementation with direct file mapping, provided that
9064 : * some requirements are met :
9065 : * - for all drivers, the dataset must be backed by a "real" file in the file
9066 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9067 : * must match the native ordering of the CPU.
9068 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9069 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9070 : * the file in sequential order, and be equally spaced (which is generally the
9071 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9072 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9073 : *
9074 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
9075 : * CPLVirtualMemFree() must be called before the raster band object is
9076 : * destroyed.
9077 : *
9078 : * If p is such a pointer and base_type the type matching
9079 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9080 : * accessed with
9081 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9082 : *
9083 : * This method is the same as the C GDALGetVirtualMemAuto() function.
9084 : *
9085 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9086 : * read/write the band.
9087 : *
9088 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
9089 : * one pixel value in the buffer to the start of the next pixel value within a
9090 : * scanline.
9091 : *
9092 : * @param pnLineSpace Output parameter giving the byte offset from the start of
9093 : * one scanline in the buffer to the start of the next.
9094 : *
9095 : * @param papszOptions NULL terminated list of options.
9096 : * If a specialized implementation exists, defining
9097 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9098 : * used. On the contrary, starting with GDAL 2.2, defining
9099 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9100 : * being used (thus only allowing efficient implementations to be used). When
9101 : * requiring or falling back to the default implementation, the following
9102 : * options are available : CACHE_SIZE (in bytes, defaults to
9103 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9104 : * to FALSE)
9105 : *
9106 : * @return a virtual memory object that must be unreferenced by
9107 : * CPLVirtualMemFree(), or NULL in case of failure.
9108 : *
9109 : * @since GDAL 1.11
9110 : */
9111 :
9112 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9113 : int *pnPixelSpace,
9114 : GIntBig *pnLineSpace,
9115 : char **papszOptions)
9116 : {
9117 9 : const char *pszImpl = CSLFetchNameValueDef(
9118 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9119 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9120 8 : EQUAL(pszImpl, "FALSE"))
9121 : {
9122 1 : return nullptr;
9123 : }
9124 :
9125 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9126 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9127 8 : if (pnPixelSpace)
9128 8 : *pnPixelSpace = nPixelSpace;
9129 8 : if (pnLineSpace)
9130 8 : *pnLineSpace = nLineSpace;
9131 : const size_t nCacheSize =
9132 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9133 : const size_t nPageSizeHint =
9134 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9135 8 : const bool bSingleThreadUsage = CPLTestBool(
9136 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9137 8 : return GDALRasterBandGetVirtualMem(
9138 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9139 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9140 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9141 8 : papszOptions);
9142 : }
9143 :
9144 : /************************************************************************/
9145 : /* GDALGetVirtualMemAuto() */
9146 : /************************************************************************/
9147 :
9148 : /**
9149 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9150 : *
9151 : * @see GDALRasterBand::GetVirtualMemAuto()
9152 : */
9153 :
9154 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9155 : int *pnPixelSpace, GIntBig *pnLineSpace,
9156 : CSLConstList papszOptions)
9157 : {
9158 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9159 :
9160 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9161 :
9162 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9163 31 : const_cast<char **>(papszOptions));
9164 : }
9165 :
9166 : /************************************************************************/
9167 : /* GDALGetDataCoverageStatus() */
9168 : /************************************************************************/
9169 :
9170 : /**
9171 : * \brief Get the coverage status of a sub-window of the raster.
9172 : *
9173 : * Returns whether a sub-window of the raster contains only data, only empty
9174 : * blocks or a mix of both. This function can be used to determine quickly
9175 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9176 : * be sparse.
9177 : *
9178 : * Empty blocks are blocks that are generally not physically present in the
9179 : * file, and when read through GDAL, contain only pixels whose value is the
9180 : * nodata value when it is set, or whose value is 0 when the nodata value is
9181 : * not set.
9182 : *
9183 : * The query is done in an efficient way without reading the actual pixel
9184 : * values. If not possible, or not implemented at all by the driver,
9185 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9186 : * be returned.
9187 : *
9188 : * The values that can be returned by the function are the following,
9189 : * potentially combined with the binary or operator :
9190 : * <ul>
9191 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9192 : * GetDataCoverageStatus(). This flag should be returned together with
9193 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9194 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9195 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9196 : * the queried window. This is typically identified by the concept of missing
9197 : * block in formats that supports it.
9198 : * </li>
9199 : * </ul>
9200 : *
9201 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9202 : * should be interpreted more as hint of potential presence of data. For example
9203 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9204 : * nodata value), instead of using the missing block mechanism,
9205 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9206 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9207 : *
9208 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9209 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9210 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9211 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9212 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9213 : * the function will exit, so that you can potentially refine the requested area
9214 : * to find which particular region(s) have missing blocks.
9215 : *
9216 : * @see GDALRasterBand::GetDataCoverageStatus()
9217 : *
9218 : * @param hBand raster band
9219 : *
9220 : * @param nXOff The pixel offset to the top left corner of the region
9221 : * of the band to be queried. This would be zero to start from the left side.
9222 : *
9223 : * @param nYOff The line offset to the top left corner of the region
9224 : * of the band to be queried. This would be zero to start from the top.
9225 : *
9226 : * @param nXSize The width of the region of the band to be queried in pixels.
9227 : *
9228 : * @param nYSize The height of the region of the band to be queried in lines.
9229 : *
9230 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9231 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9232 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9233 : * as the computation of the coverage matches the mask, the computation will be
9234 : * stopped. *pdfDataPct will not be valid in that case.
9235 : *
9236 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9237 : * to the (approximate) percentage in [0,100] of pixels in the queried
9238 : * sub-window that have valid values. The implementation might not always be
9239 : * able to compute it, in which case it will be set to a negative value.
9240 : *
9241 : * @return a binary-or'ed combination of possible values
9242 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9243 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9244 : *
9245 : * @note Added in GDAL 2.2
9246 : */
9247 :
9248 26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
9249 : int nYOff, int nXSize, int nYSize,
9250 : int nMaskFlagStop, double *pdfDataPct)
9251 : {
9252 26 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
9253 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
9254 :
9255 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9256 :
9257 26 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
9258 26 : nMaskFlagStop, pdfDataPct);
9259 : }
9260 :
9261 : /************************************************************************/
9262 : /* GetDataCoverageStatus() */
9263 : /************************************************************************/
9264 :
9265 : /**
9266 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
9267 : * int nYOff,
9268 : * int nXSize,
9269 : * int nYSize,
9270 : * int nMaskFlagStop,
9271 : * double* pdfDataPct)
9272 : * \brief Get the coverage status of a sub-window of the raster.
9273 : *
9274 : * Returns whether a sub-window of the raster contains only data, only empty
9275 : * blocks or a mix of both. This function can be used to determine quickly
9276 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9277 : * be sparse.
9278 : *
9279 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9280 : * value when it is set, or whose value is 0 when the nodata value is not set.
9281 : *
9282 : * The query is done in an efficient way without reading the actual pixel
9283 : * values. If not possible, or not implemented at all by the driver,
9284 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9285 : * be returned.
9286 : *
9287 : * The values that can be returned by the function are the following,
9288 : * potentially combined with the binary or operator :
9289 : * <ul>
9290 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9291 : * GetDataCoverageStatus(). This flag should be returned together with
9292 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9293 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9294 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9295 : * the queried window. This is typically identified by the concept of missing
9296 : * block in formats that supports it.
9297 : * </li>
9298 : * </ul>
9299 : *
9300 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9301 : * should be interpreted more as hint of potential presence of data. For example
9302 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9303 : * nodata value), instead of using the missing block mechanism,
9304 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9305 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9306 : *
9307 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9308 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9309 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9310 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9311 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9312 : * the function will exit, so that you can potentially refine the requested area
9313 : * to find which particular region(s) have missing blocks.
9314 : *
9315 : * @see GDALGetDataCoverageStatus()
9316 : *
9317 : * @param nXOff The pixel offset to the top left corner of the region
9318 : * of the band to be queried. This would be zero to start from the left side.
9319 : *
9320 : * @param nYOff The line offset to the top left corner of the region
9321 : * of the band to be queried. This would be zero to start from the top.
9322 : *
9323 : * @param nXSize The width of the region of the band to be queried in pixels.
9324 : *
9325 : * @param nYSize The height of the region of the band to be queried in lines.
9326 : *
9327 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9328 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9329 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9330 : * as the computation of the coverage matches the mask, the computation will be
9331 : * stopped. *pdfDataPct will not be valid in that case.
9332 : *
9333 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9334 : * to the (approximate) percentage in [0,100] of pixels in the queried
9335 : * sub-window that have valid values. The implementation might not always be
9336 : * able to compute it, in which case it will be set to a negative value.
9337 : *
9338 : * @return a binary-or'ed combination of possible values
9339 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9340 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9341 : *
9342 : * @note Added in GDAL 2.2
9343 : */
9344 :
9345 : /**
9346 : * \brief Get the coverage status of a sub-window of the raster.
9347 : *
9348 : * Returns whether a sub-window of the raster contains only data, only empty
9349 : * blocks or a mix of both. This function can be used to determine quickly
9350 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9351 : * be sparse.
9352 : *
9353 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9354 : * value when it is set, or whose value is 0 when the nodata value is not set.
9355 : *
9356 : * The query is done in an efficient way without reading the actual pixel
9357 : * values. If not possible, or not implemented at all by the driver,
9358 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9359 : * be returned.
9360 : *
9361 : * The values that can be returned by the function are the following,
9362 : * potentially combined with the binary or operator :
9363 : * <ul>
9364 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9365 : * GetDataCoverageStatus(). This flag should be returned together with
9366 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9367 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9368 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9369 : * the queried window. This is typically identified by the concept of missing
9370 : * block in formats that supports it.
9371 : * </li>
9372 : * </ul>
9373 : *
9374 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9375 : * should be interpreted more as hint of potential presence of data. For example
9376 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9377 : * nodata value), instead of using the missing block mechanism,
9378 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9379 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9380 : *
9381 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9382 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9383 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9384 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9385 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9386 : * the function will exit, so that you can potentially refine the requested area
9387 : * to find which particular region(s) have missing blocks.
9388 : *
9389 : * @see GDALGetDataCoverageStatus()
9390 : *
9391 : * @param nXOff The pixel offset to the top left corner of the region
9392 : * of the band to be queried. This would be zero to start from the left side.
9393 : *
9394 : * @param nYOff The line offset to the top left corner of the region
9395 : * of the band to be queried. This would be zero to start from the top.
9396 : *
9397 : * @param nXSize The width of the region of the band to be queried in pixels.
9398 : *
9399 : * @param nYSize The height of the region of the band to be queried in lines.
9400 : *
9401 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9402 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9403 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9404 : * as the computation of the coverage matches the mask, the computation will be
9405 : * stopped. *pdfDataPct will not be valid in that case.
9406 : *
9407 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9408 : * to the (approximate) percentage in [0,100] of pixels in the queried
9409 : * sub-window that have valid values. The implementation might not always be
9410 : * able to compute it, in which case it will be set to a negative value.
9411 : *
9412 : * @return a binary-or'ed combination of possible values
9413 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9414 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9415 : *
9416 : * @note Added in GDAL 2.2
9417 : */
9418 :
9419 4615 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9420 : int nYSize, int nMaskFlagStop,
9421 : double *pdfDataPct)
9422 : {
9423 4615 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9424 4615 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9425 4615 : nYOff + nYSize > nRasterYSize)
9426 : {
9427 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9428 0 : if (pdfDataPct)
9429 0 : *pdfDataPct = 0.0;
9430 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9431 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
9432 : }
9433 4615 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9434 4615 : pdfDataPct);
9435 : }
9436 :
9437 : /************************************************************************/
9438 : /* IGetDataCoverageStatus() */
9439 : /************************************************************************/
9440 :
9441 684 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9442 : int /*nXSize*/, int /*nYSize*/,
9443 : int /*nMaskFlagStop*/,
9444 : double *pdfDataPct)
9445 : {
9446 684 : if (pdfDataPct != nullptr)
9447 0 : *pdfDataPct = 100.0;
9448 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9449 684 : GDAL_DATA_COVERAGE_STATUS_DATA;
9450 : }
9451 :
9452 : //! @cond Doxygen_Suppress
9453 : /************************************************************************/
9454 : /* EnterReadWrite() */
9455 : /************************************************************************/
9456 :
9457 7780160 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9458 : {
9459 7780160 : if (poDS != nullptr)
9460 7025350 : return poDS->EnterReadWrite(eRWFlag);
9461 754809 : return FALSE;
9462 : }
9463 :
9464 : /************************************************************************/
9465 : /* LeaveReadWrite() */
9466 : /************************************************************************/
9467 :
9468 1127910 : void GDALRasterBand::LeaveReadWrite()
9469 : {
9470 1127910 : if (poDS != nullptr)
9471 1127910 : poDS->LeaveReadWrite();
9472 1127910 : }
9473 :
9474 : /************************************************************************/
9475 : /* InitRWLock() */
9476 : /************************************************************************/
9477 :
9478 3954920 : void GDALRasterBand::InitRWLock()
9479 : {
9480 3954920 : if (poDS != nullptr)
9481 3954520 : poDS->InitRWLock();
9482 3954920 : }
9483 :
9484 : //! @endcond
9485 :
9486 : // clang-format off
9487 :
9488 : /**
9489 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9490 : * \brief Set metadata.
9491 : *
9492 : * CAUTION: depending on the format, older values of the updated information
9493 : * might still be found in the file in a "ghost" state, even if no longer
9494 : * accessible through the GDAL API. This is for example the case of the GTiff
9495 : * format (this is not a exhaustive list)
9496 : *
9497 : * The C function GDALSetMetadata() does the same thing as this method.
9498 : *
9499 : * @param papszMetadata the metadata in name=value string list format to
9500 : * apply.
9501 : * @param pszDomain the domain of interest. Use "" or NULL for the default
9502 : * domain.
9503 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9504 : * metadata has been accepted, but is likely not maintained persistently
9505 : * by the underlying object between sessions.
9506 : */
9507 :
9508 : /**
9509 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9510 : * \brief Set single metadata item.
9511 : *
9512 : * CAUTION: depending on the format, older values of the updated information
9513 : * might still be found in the file in a "ghost" state, even if no longer
9514 : * accessible through the GDAL API. This is for example the case of the GTiff
9515 : * format (this is not a exhaustive list)
9516 : *
9517 : * The C function GDALSetMetadataItem() does the same thing as this method.
9518 : *
9519 : * @param pszName the key for the metadata item to fetch.
9520 : * @param pszValue the value to assign to the key.
9521 : * @param pszDomain the domain to set within, use NULL for the default domain.
9522 : *
9523 : * @return CE_None on success, or an error code on failure.
9524 : */
9525 :
9526 : // clang-format on
9527 :
9528 : //! @cond Doxygen_Suppress
9529 : /************************************************************************/
9530 : /* EnablePixelTypeSignedByteWarning() */
9531 : /************************************************************************/
9532 :
9533 156050 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9534 : {
9535 156050 : m_bEnablePixelTypeSignedByteWarning = b;
9536 156050 : }
9537 :
9538 4878 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9539 : {
9540 4878 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9541 4878 : }
9542 :
9543 : //! @endcond
9544 :
9545 : /************************************************************************/
9546 : /* GetMetadataItem() */
9547 : /************************************************************************/
9548 :
9549 487243 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9550 : const char *pszDomain)
9551 : {
9552 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9553 487243 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9554 330123 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9555 321092 : EQUAL(pszName, "PIXELTYPE"))
9556 : {
9557 2 : CPLError(CE_Warning, CPLE_AppDefined,
9558 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9559 : "used to signal signed 8-bit raster. Change your code to "
9560 : "test for the new GDT_Int8 data type instead.");
9561 : }
9562 487243 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9563 : }
9564 :
9565 : /************************************************************************/
9566 : /* WindowIterator */
9567 : /************************************************************************/
9568 :
9569 : //! @cond Doxygen_Suppress
9570 :
9571 2 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
9572 : int nRasterYSize,
9573 : int nBlockXSize, int nBlockYSize,
9574 2 : int nRow, int nCol)
9575 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
9576 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
9577 2 : m_col(nCol)
9578 : {
9579 2 : }
9580 :
9581 10 : bool GDALRasterBand::WindowIterator::operator==(
9582 : const WindowIterator &other) const
9583 : {
9584 1 : return m_row == other.m_row && m_col == other.m_col &&
9585 1 : m_nRasterXSize == other.m_nRasterXSize &&
9586 1 : m_nRasterYSize == other.m_nRasterYSize &&
9587 12 : m_nBlockXSize == other.m_nBlockXSize &&
9588 11 : m_nBlockYSize == other.m_nBlockYSize;
9589 : }
9590 :
9591 10 : bool GDALRasterBand::WindowIterator::operator!=(
9592 : const WindowIterator &other) const
9593 : {
9594 10 : return !(*this == other);
9595 : }
9596 :
9597 : GDALRasterBand::WindowIterator::value_type
9598 9 : GDALRasterBand::WindowIterator::operator*() const
9599 : {
9600 : GDALRasterWindow ret;
9601 9 : ret.nXOff = m_col * m_nBlockXSize;
9602 9 : ret.nYOff = m_row * m_nBlockYSize;
9603 9 : ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
9604 9 : ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
9605 :
9606 9 : return ret;
9607 : }
9608 :
9609 9 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
9610 : {
9611 9 : m_col++;
9612 9 : if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
9613 : {
9614 3 : m_col = 0;
9615 3 : m_row++;
9616 : }
9617 9 : return *this;
9618 : }
9619 :
9620 2 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
9621 2 : const GDALRasterBand &band)
9622 2 : : m_nRasterXSize(band.GetDataset()->GetRasterXSize()),
9623 2 : m_nRasterYSize(band.GetDataset()->GetRasterYSize()), m_nBlockXSize(-1),
9624 2 : m_nBlockYSize(-1)
9625 : {
9626 2 : band.GetBlockSize(&m_nBlockXSize, &m_nBlockYSize);
9627 2 : }
9628 :
9629 : GDALRasterBand::WindowIterator
9630 1 : GDALRasterBand::WindowIteratorWrapper::begin() const
9631 : {
9632 1 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
9633 1 : m_nBlockYSize, 0, 0);
9634 : }
9635 :
9636 : GDALRasterBand::WindowIterator
9637 1 : GDALRasterBand::WindowIteratorWrapper::end() const
9638 : {
9639 1 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
9640 1 : m_nBlockYSize,
9641 1 : DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
9642 : }
9643 :
9644 : //! @endcond
9645 :
9646 : /** Return an object whose begin() and end() methods can be used to iterate
9647 : * over a GDALRasterWindow for each block in this raster band. The iteration
9648 : * order is from left to right, then from top to bottom.
9649 : *
9650 : \code{.cpp}
9651 : std::vector<double> pixelValues;
9652 : for (const auto& window : poBand->IterateWindows()) {
9653 : CPLErr eErr = window.ReadRaster(pixelValues, window.nXOff, window.nYOff,
9654 : window.nXSize, window.nYSize);
9655 : // check eErr
9656 : }
9657 : \endcode
9658 : *
9659 : *
9660 : * @since GDAL 3.12
9661 : */
9662 2 : GDALRasterBand::WindowIteratorWrapper GDALRasterBand::IterateWindows() const
9663 : {
9664 2 : return WindowIteratorWrapper(*this);
9665 : }
9666 :
9667 : /************************************************************************/
9668 : /* GDALMDArrayFromRasterBand */
9669 : /************************************************************************/
9670 :
9671 : class GDALMDArrayFromRasterBand final : public GDALMDArray
9672 : {
9673 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9674 :
9675 : GDALDataset *m_poDS;
9676 : GDALRasterBand *m_poBand;
9677 : GDALExtendedDataType m_dt;
9678 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9679 : std::string m_osUnit;
9680 : std::vector<GByte> m_pabyNoData{};
9681 : std::shared_ptr<GDALMDArray> m_varX{};
9682 : std::shared_ptr<GDALMDArray> m_varY{};
9683 : std::string m_osFilename{};
9684 :
9685 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9686 : const size_t *count, const GInt64 *arrayStep,
9687 : const GPtrDiff_t *bufferStride,
9688 : const GDALExtendedDataType &bufferDataType,
9689 : void *pBuffer) const;
9690 :
9691 : protected:
9692 23 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9693 46 : : GDALAbstractMDArray(std::string(),
9694 46 : std::string(poDS->GetDescription()) +
9695 : CPLSPrintf(" band %d", poBand->GetBand())),
9696 46 : GDALMDArray(std::string(),
9697 46 : std::string(poDS->GetDescription()) +
9698 : CPLSPrintf(" band %d", poBand->GetBand())),
9699 : m_poDS(poDS), m_poBand(poBand),
9700 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9701 115 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9702 : {
9703 23 : m_poDS->Reference();
9704 :
9705 23 : int bHasNoData = false;
9706 23 : if (m_poBand->GetRasterDataType() == GDT_Int64)
9707 : {
9708 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9709 0 : if (bHasNoData)
9710 : {
9711 0 : m_pabyNoData.resize(m_dt.GetSize());
9712 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9713 : m_dt.GetNumericDataType(), 0, 1);
9714 : }
9715 : }
9716 23 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9717 : {
9718 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9719 0 : if (bHasNoData)
9720 : {
9721 0 : m_pabyNoData.resize(m_dt.GetSize());
9722 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9723 : m_dt.GetNumericDataType(), 0, 1);
9724 : }
9725 : }
9726 : else
9727 : {
9728 23 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9729 23 : if (bHasNoData)
9730 : {
9731 1 : m_pabyNoData.resize(m_dt.GetSize());
9732 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9733 : m_dt.GetNumericDataType(), 0, 1);
9734 : }
9735 : }
9736 :
9737 23 : const int nXSize = poBand->GetXSize();
9738 23 : const int nYSize = poBand->GetYSize();
9739 :
9740 23 : auto poSRS = m_poDS->GetSpatialRef();
9741 46 : std::string osTypeY;
9742 46 : std::string osTypeX;
9743 46 : std::string osDirectionY;
9744 46 : std::string osDirectionX;
9745 23 : if (poSRS && poSRS->GetAxesCount() == 2)
9746 : {
9747 21 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9748 21 : OGRAxisOrientation eOrientation1 = OAO_Other;
9749 21 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
9750 21 : OGRAxisOrientation eOrientation2 = OAO_Other;
9751 21 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
9752 21 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9753 : {
9754 5 : if (mapping == std::vector<int>{1, 2})
9755 : {
9756 5 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9757 5 : osDirectionY = "NORTH";
9758 5 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9759 5 : osDirectionX = "EAST";
9760 : }
9761 : }
9762 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9763 : {
9764 16 : if (mapping == std::vector<int>{2, 1})
9765 : {
9766 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9767 16 : osDirectionY = "NORTH";
9768 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9769 16 : osDirectionX = "EAST";
9770 : }
9771 : }
9772 : }
9773 :
9774 115 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9775 : "/", "Y", osTypeY, osDirectionY, nYSize),
9776 46 : std::make_shared<GDALDimensionWeakIndexingVar>(
9777 69 : "/", "X", osTypeX, osDirectionX, nXSize)};
9778 :
9779 23 : GDALGeoTransform gt;
9780 23 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
9781 : {
9782 44 : m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
9783 44 : gt[0], gt[1], 0.5);
9784 22 : m_dims[1]->SetIndexingVariable(m_varX);
9785 :
9786 44 : m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
9787 44 : gt[3], gt[5], 0.5);
9788 22 : m_dims[0]->SetIndexingVariable(m_varY);
9789 : }
9790 23 : }
9791 :
9792 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9793 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9794 : const GDALExtendedDataType &bufferDataType,
9795 : void *pDstBuffer) const override;
9796 :
9797 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9798 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9799 : const GDALExtendedDataType &bufferDataType,
9800 : const void *pSrcBuffer) override
9801 : {
9802 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9803 : bufferStride, bufferDataType,
9804 1 : const_cast<void *>(pSrcBuffer));
9805 : }
9806 :
9807 : public:
9808 46 : ~GDALMDArrayFromRasterBand()
9809 23 : {
9810 23 : m_poDS->ReleaseRef();
9811 46 : }
9812 :
9813 23 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9814 : GDALRasterBand *poBand)
9815 : {
9816 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9817 46 : new GDALMDArrayFromRasterBand(poDS, poBand)));
9818 23 : array->SetSelf(array);
9819 46 : return array;
9820 : }
9821 :
9822 2 : bool IsWritable() const override
9823 : {
9824 2 : return m_poDS->GetAccess() == GA_Update;
9825 : }
9826 :
9827 97 : const std::string &GetFilename() const override
9828 : {
9829 97 : return m_osFilename;
9830 : }
9831 :
9832 : const std::vector<std::shared_ptr<GDALDimension>> &
9833 299 : GetDimensions() const override
9834 : {
9835 299 : return m_dims;
9836 : }
9837 :
9838 138 : const GDALExtendedDataType &GetDataType() const override
9839 : {
9840 138 : return m_dt;
9841 : }
9842 :
9843 3 : const std::string &GetUnit() const override
9844 : {
9845 3 : return m_osUnit;
9846 : }
9847 :
9848 29 : const void *GetRawNoDataValue() const override
9849 : {
9850 29 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9851 : }
9852 :
9853 2 : double GetOffset(bool *pbHasOffset,
9854 : GDALDataType *peStorageType) const override
9855 : {
9856 2 : int bHasOffset = false;
9857 2 : double dfRes = m_poBand->GetOffset(&bHasOffset);
9858 2 : if (pbHasOffset)
9859 2 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9860 2 : if (peStorageType)
9861 1 : *peStorageType = GDT_Unknown;
9862 2 : return dfRes;
9863 : }
9864 :
9865 2 : double GetScale(bool *pbHasScale,
9866 : GDALDataType *peStorageType) const override
9867 : {
9868 2 : int bHasScale = false;
9869 2 : double dfRes = m_poBand->GetScale(&bHasScale);
9870 2 : if (pbHasScale)
9871 2 : *pbHasScale = CPL_TO_BOOL(bHasScale);
9872 2 : if (peStorageType)
9873 1 : *peStorageType = GDT_Unknown;
9874 2 : return dfRes;
9875 : }
9876 :
9877 84 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9878 : {
9879 84 : auto poSrcSRS = m_poDS->GetSpatialRef();
9880 84 : if (!poSrcSRS)
9881 2 : return nullptr;
9882 164 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9883 :
9884 164 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9885 82 : constexpr int iYDim = 0;
9886 82 : constexpr int iXDim = 1;
9887 246 : for (auto &m : axisMapping)
9888 : {
9889 164 : if (m == 1)
9890 82 : m = iXDim + 1;
9891 82 : else if (m == 2)
9892 82 : m = iYDim + 1;
9893 : else
9894 0 : m = 0;
9895 : }
9896 82 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9897 82 : return poSRS;
9898 : }
9899 :
9900 29 : std::vector<GUInt64> GetBlockSize() const override
9901 : {
9902 29 : int nBlockXSize = 0;
9903 29 : int nBlockYSize = 0;
9904 29 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9905 29 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9906 29 : static_cast<GUInt64>(nBlockXSize)};
9907 : }
9908 :
9909 : class MDIAsAttribute : public GDALAttribute
9910 : {
9911 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9912 : const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
9913 : std::string m_osValue;
9914 :
9915 : public:
9916 2 : MDIAsAttribute(const std::string &name, const std::string &value)
9917 2 : : GDALAbstractMDArray(std::string(), name),
9918 4 : GDALAttribute(std::string(), name), m_osValue(value)
9919 : {
9920 2 : }
9921 :
9922 : const std::vector<std::shared_ptr<GDALDimension>> &
9923 : GetDimensions() const override;
9924 :
9925 2 : const GDALExtendedDataType &GetDataType() const override
9926 : {
9927 2 : return m_dt;
9928 : }
9929 :
9930 1 : bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
9931 : const GPtrDiff_t *,
9932 : const GDALExtendedDataType &bufferDataType,
9933 : void *pDstBuffer) const override
9934 : {
9935 1 : const char *pszStr = m_osValue.c_str();
9936 1 : GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
9937 : bufferDataType);
9938 1 : return true;
9939 : }
9940 : };
9941 :
9942 : std::vector<std::shared_ptr<GDALAttribute>>
9943 14 : GetAttributes(CSLConstList) const override
9944 : {
9945 14 : std::vector<std::shared_ptr<GDALAttribute>> res;
9946 14 : auto papszMD = m_poBand->GetMetadata();
9947 16 : for (auto iter = papszMD; iter && iter[0]; ++iter)
9948 : {
9949 2 : char *pszKey = nullptr;
9950 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9951 2 : if (pszKey && pszValue)
9952 : {
9953 : res.emplace_back(
9954 2 : std::make_shared<MDIAsAttribute>(pszKey, pszValue));
9955 : }
9956 2 : CPLFree(pszKey);
9957 : }
9958 14 : return res;
9959 : }
9960 : };
9961 :
9962 31 : bool GDALMDArrayFromRasterBand::IRead(
9963 : const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
9964 : const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
9965 : void *pDstBuffer) const
9966 : {
9967 31 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9968 31 : bufferDataType, pDstBuffer);
9969 : }
9970 :
9971 : const std::vector<std::shared_ptr<GDALDimension>> &
9972 3 : GDALMDArrayFromRasterBand::MDIAsAttribute::GetDimensions() const
9973 : {
9974 3 : return m_dims;
9975 : }
9976 :
9977 : /************************************************************************/
9978 : /* ReadWrite() */
9979 : /************************************************************************/
9980 :
9981 32 : bool GDALMDArrayFromRasterBand::ReadWrite(
9982 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
9983 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9984 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
9985 : {
9986 32 : constexpr size_t iDimX = 1;
9987 32 : constexpr size_t iDimY = 0;
9988 32 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
9989 : arrayStartIdx, count, arrayStep, bufferStride,
9990 32 : bufferDataType, pBuffer);
9991 : }
9992 :
9993 : /************************************************************************/
9994 : /* GDALMDRasterIOFromBand() */
9995 : /************************************************************************/
9996 :
9997 65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
9998 : size_t iDimX, size_t iDimY,
9999 : const GUInt64 *arrayStartIdx, const size_t *count,
10000 : const GInt64 *arrayStep,
10001 : const GPtrDiff_t *bufferStride,
10002 : const GDALExtendedDataType &bufferDataType,
10003 : void *pBuffer)
10004 : {
10005 65 : const auto eDT(bufferDataType.GetNumericDataType());
10006 65 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
10007 65 : const int nX =
10008 65 : arrayStep[iDimX] > 0
10009 65 : ? static_cast<int>(arrayStartIdx[iDimX])
10010 2 : : static_cast<int>(arrayStartIdx[iDimX] -
10011 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
10012 65 : const int nY =
10013 65 : arrayStep[iDimY] > 0
10014 65 : ? static_cast<int>(arrayStartIdx[iDimY])
10015 2 : : static_cast<int>(arrayStartIdx[iDimY] -
10016 2 : (count[iDimY] - 1) * -arrayStep[iDimY]);
10017 65 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
10018 65 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
10019 65 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
10020 65 : int nStrideXSign = 1;
10021 65 : if (arrayStep[iDimX] < 0)
10022 : {
10023 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
10024 2 : nStrideXSign = -1;
10025 : }
10026 65 : int nStrideYSign = 1;
10027 65 : if (arrayStep[iDimY] < 0)
10028 : {
10029 2 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
10030 2 : nStrideYSign = -1;
10031 : }
10032 :
10033 130 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
10034 65 : static_cast<int>(count[iDimX]),
10035 65 : static_cast<int>(count[iDimY]), eDT,
10036 : static_cast<GSpacing>(
10037 65 : nStrideXSign * bufferStride[iDimX] * nDTSize),
10038 : static_cast<GSpacing>(
10039 65 : nStrideYSign * bufferStride[iDimY] * nDTSize),
10040 65 : nullptr) == CE_None;
10041 : }
10042 :
10043 : /************************************************************************/
10044 : /* AsMDArray() */
10045 : /************************************************************************/
10046 :
10047 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10048 : *
10049 : * The band must be linked to a GDALDataset. If this dataset is not already
10050 : * marked as shared, it will be, so that the returned array holds a reference
10051 : * to it.
10052 : *
10053 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10054 : * returned array will have an associated indexing variable.
10055 : *
10056 : * This is the same as the C function GDALRasterBandAsMDArray().
10057 : *
10058 : * The "reverse" method is GDALMDArray::AsClassicDataset().
10059 : *
10060 : * @return a new array, or nullptr.
10061 : *
10062 : * @since GDAL 3.1
10063 : */
10064 23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
10065 : {
10066 23 : if (!poDS)
10067 : {
10068 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
10069 0 : return nullptr;
10070 : }
10071 23 : if (!poDS->GetShared())
10072 : {
10073 23 : poDS->MarkAsShared();
10074 : }
10075 : return GDALMDArrayFromRasterBand::Create(
10076 23 : poDS, const_cast<GDALRasterBand *>(this));
10077 : }
10078 :
10079 : /************************************************************************/
10080 : /* InterpolateAtPoint() */
10081 : /************************************************************************/
10082 :
10083 : /**
10084 : * \brief Interpolates the value between pixels using a resampling algorithm,
10085 : * taking pixel/line coordinates as input.
10086 : *
10087 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
10088 : * @param dfLine line coordinate as a double, where interpolation should be done.
10089 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10090 : * @param pdfRealValue pointer to real part of interpolated value
10091 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10092 : *
10093 : * @return CE_None on success, or an error code on failure.
10094 : * @since GDAL 3.10
10095 : */
10096 :
10097 167 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
10098 : GDALRIOResampleAlg eInterpolation,
10099 : double *pdfRealValue,
10100 : double *pdfImagValue) const
10101 : {
10102 167 : if (eInterpolation != GRIORA_NearestNeighbour &&
10103 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
10104 : eInterpolation != GRIORA_CubicSpline)
10105 : {
10106 2 : CPLError(CE_Failure, CPLE_AppDefined,
10107 : "Only nearest, bilinear, cubic and cubicspline interpolation "
10108 : "methods "
10109 : "allowed");
10110 :
10111 2 : return CE_Failure;
10112 : }
10113 :
10114 165 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
10115 165 : if (!m_poPointsCache)
10116 85 : m_poPointsCache = new GDALDoublePointsCache();
10117 :
10118 : const bool res =
10119 165 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
10120 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
10121 :
10122 165 : return res ? CE_None : CE_Failure;
10123 : }
10124 :
10125 : /************************************************************************/
10126 : /* GDALRasterInterpolateAtPoint() */
10127 : /************************************************************************/
10128 :
10129 : /**
10130 : * \brief Interpolates the value between pixels using
10131 : * a resampling algorithm
10132 : *
10133 : * @see GDALRasterBand::InterpolateAtPoint()
10134 : * @since GDAL 3.10
10135 : */
10136 :
10137 144 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10138 : double dfLine,
10139 : GDALRIOResampleAlg eInterpolation,
10140 : double *pdfRealValue, double *pdfImagValue)
10141 : {
10142 144 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10143 :
10144 144 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10145 144 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10146 144 : pdfRealValue, pdfImagValue);
10147 : }
10148 :
10149 : /************************************************************************/
10150 : /* InterpolateAtGeolocation() */
10151 : /************************************************************************/
10152 :
10153 : /**
10154 : * \brief Interpolates the value between pixels using a resampling algorithm,
10155 : * taking georeferenced coordinates as input.
10156 : *
10157 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
10158 : * must be in the "natural" SRS of the dataset, that is the one returned by
10159 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
10160 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
10161 : * array (generally WGS 84) if there is a geolocation array.
10162 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10163 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10164 : * be a easting, and dfGeolocY a northing.
10165 : *
10166 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10167 : * expressed in that CRS, and that tuple must be conformant with the
10168 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10169 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10170 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10171 : * before calling this method, and in that case, dfGeolocX must be a longitude
10172 : * or an easting value, and dfGeolocX a latitude or a northing value.
10173 : *
10174 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
10175 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
10176 : * it for details on how that transformation is done.
10177 : *
10178 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
10179 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10180 : * where interpolation should be done.
10181 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
10182 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10183 : * where interpolation should be done.
10184 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
10185 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10186 : * @param pdfRealValue pointer to real part of interpolated value
10187 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10188 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
10189 : *
10190 : * @return CE_None on success, or an error code on failure.
10191 : * @since GDAL 3.11
10192 : */
10193 :
10194 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
10195 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
10196 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
10197 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
10198 : {
10199 : double dfPixel;
10200 : double dfLine;
10201 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
10202 : &dfLine,
10203 15 : papszTransformerOptions) != CE_None)
10204 : {
10205 1 : return CE_Failure;
10206 : }
10207 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
10208 14 : pdfImagValue);
10209 : }
10210 :
10211 : /************************************************************************/
10212 : /* GDALRasterInterpolateAtGeolocation() */
10213 : /************************************************************************/
10214 :
10215 : /**
10216 : * \brief Interpolates the value between pixels using a resampling algorithm,
10217 : * taking georeferenced coordinates as input.
10218 : *
10219 : * @see GDALRasterBand::InterpolateAtGeolocation()
10220 : * @since GDAL 3.11
10221 : */
10222 :
10223 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
10224 : double dfGeolocX, double dfGeolocY,
10225 : OGRSpatialReferenceH hSRS,
10226 : GDALRIOResampleAlg eInterpolation,
10227 : double *pdfRealValue,
10228 : double *pdfImagValue,
10229 : CSLConstList papszTransformerOptions)
10230 : {
10231 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
10232 :
10233 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10234 15 : return poBand->InterpolateAtGeolocation(
10235 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
10236 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
10237 : }
10238 :
10239 : /************************************************************************/
10240 : /* GDALRasterBand::SplitRasterIO() */
10241 : /************************************************************************/
10242 :
10243 : //! @cond Doxygen_Suppress
10244 :
10245 : /** Implements IRasterIO() by dividing the request in 2.
10246 : *
10247 : * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
10248 : *
10249 : * Return CE_Warning if the split could not be done, CE_None in case of
10250 : * success and CE_Failure in case of error.
10251 : *
10252 : * @since 3.12
10253 : */
10254 999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
10255 : [[maybe_unused]] int nXSize,
10256 : [[maybe_unused]] int nYSize, void *pData,
10257 : int nBufXSize, int nBufYSize,
10258 : GDALDataType eBufType,
10259 : GSpacing nPixelSpace, GSpacing nLineSpace,
10260 : GDALRasterIOExtraArg *psExtraArg)
10261 : {
10262 999 : CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
10263 :
10264 999 : GByte *pabyData = static_cast<GByte *>(pData);
10265 999 : if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
10266 : {
10267 : GDALRasterIOExtraArg sArg;
10268 499 : INIT_RASTERIO_EXTRA_ARG(sArg);
10269 499 : const int nHalfHeight = nBufYSize / 2;
10270 :
10271 499 : sArg.pfnProgress = GDALScaledProgress;
10272 499 : sArg.pProgressData = GDALCreateScaledProgress(
10273 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10274 499 : if (sArg.pProgressData == nullptr)
10275 499 : sArg.pfnProgress = nullptr;
10276 998 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
10277 : pabyData, nBufXSize, nHalfHeight, eBufType,
10278 499 : nPixelSpace, nLineSpace, &sArg);
10279 499 : GDALDestroyScaledProgress(sArg.pProgressData);
10280 :
10281 499 : if (eErr == CE_None)
10282 : {
10283 499 : sArg.pfnProgress = GDALScaledProgress;
10284 499 : sArg.pProgressData = GDALCreateScaledProgress(
10285 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10286 499 : if (sArg.pProgressData == nullptr)
10287 499 : sArg.pfnProgress = nullptr;
10288 998 : eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
10289 : nBufYSize - nHalfHeight,
10290 499 : pabyData + nHalfHeight * nLineSpace, nBufXSize,
10291 : nBufYSize - nHalfHeight, eBufType, nPixelSpace,
10292 499 : nLineSpace, &sArg);
10293 499 : GDALDestroyScaledProgress(sArg.pProgressData);
10294 : }
10295 499 : return eErr;
10296 : }
10297 500 : else if (nBufXSize >= 2)
10298 : {
10299 : GDALRasterIOExtraArg sArg;
10300 500 : INIT_RASTERIO_EXTRA_ARG(sArg);
10301 500 : const int nHalfWidth = nBufXSize / 2;
10302 :
10303 500 : sArg.pfnProgress = GDALScaledProgress;
10304 500 : sArg.pProgressData = GDALCreateScaledProgress(
10305 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10306 500 : if (sArg.pProgressData == nullptr)
10307 500 : sArg.pfnProgress = nullptr;
10308 1000 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
10309 : pabyData, nHalfWidth, nBufYSize, eBufType,
10310 500 : nPixelSpace, nLineSpace, &sArg);
10311 500 : GDALDestroyScaledProgress(sArg.pProgressData);
10312 :
10313 500 : if (eErr == CE_None)
10314 : {
10315 500 : sArg.pfnProgress = GDALScaledProgress;
10316 500 : sArg.pProgressData = GDALCreateScaledProgress(
10317 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10318 500 : if (sArg.pProgressData == nullptr)
10319 500 : sArg.pfnProgress = nullptr;
10320 1000 : eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
10321 : nBufXSize - nHalfWidth, nBufYSize,
10322 500 : pabyData + nHalfWidth * nPixelSpace,
10323 : nBufXSize - nHalfWidth, nBufYSize, eBufType,
10324 500 : nPixelSpace, nLineSpace, &sArg);
10325 500 : GDALDestroyScaledProgress(sArg.pProgressData);
10326 : }
10327 500 : return eErr;
10328 : }
10329 :
10330 0 : return CE_Warning;
10331 : }
10332 :
10333 : //! @endcond
10334 :
10335 : /************************************************************************/
10336 : /* ThrowIfNotSameDimensions() */
10337 : /************************************************************************/
10338 :
10339 : //! @cond Doxygen_Suppress
10340 : /* static */
10341 157 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
10342 : const GDALRasterBand &second)
10343 : {
10344 297 : if (first.GetXSize() != second.GetXSize() ||
10345 140 : first.GetYSize() != second.GetYSize())
10346 : {
10347 34 : throw std::runtime_error("Bands do not have the same dimensions");
10348 : }
10349 123 : }
10350 :
10351 : //! @endcond
10352 :
10353 : /************************************************************************/
10354 : /* GDALRasterBandUnaryOp() */
10355 : /************************************************************************/
10356 :
10357 : /** Apply a unary operation on this band.
10358 : *
10359 : * The resulting band is lazy evaluated. A reference is taken on the input
10360 : * dataset.
10361 : *
10362 : * @since 3.12
10363 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10364 : */
10365 : GDALComputedRasterBandH
10366 2 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
10367 : GDALRasterAlgebraUnaryOperation eOp)
10368 : {
10369 2 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10370 2 : switch (eOp)
10371 : {
10372 2 : case GRAUO_LOGICAL_NOT:
10373 2 : break;
10374 : }
10375 : return new GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
10376 2 : *(GDALRasterBand::FromHandle(hBand)),
10377 2 : true);
10378 : }
10379 :
10380 : /************************************************************************/
10381 : /* ConvertGDALRasterAlgebraBinaryOperationToCpp() */
10382 : /************************************************************************/
10383 :
10384 : static GDALComputedRasterBand::Operation
10385 117 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
10386 : GDALRasterAlgebraBinaryOperation eOp)
10387 : {
10388 117 : switch (eOp)
10389 : {
10390 26 : case GRABO_ADD:
10391 26 : return GDALComputedRasterBand::Operation::OP_ADD;
10392 2 : case GRABO_SUB:
10393 2 : return GDALComputedRasterBand::Operation::OP_SUBTRACT;
10394 24 : case GRABO_MUL:
10395 24 : return GDALComputedRasterBand::Operation::OP_MULTIPLY;
10396 3 : case GRABO_DIV:
10397 3 : return GDALComputedRasterBand::Operation::OP_DIVIDE;
10398 6 : case GRABO_GT:
10399 6 : return GDALComputedRasterBand::Operation::OP_GT;
10400 8 : case GRABO_GE:
10401 8 : return GDALComputedRasterBand::Operation::OP_GE;
10402 6 : case GRABO_LT:
10403 6 : return GDALComputedRasterBand::Operation::OP_LT;
10404 6 : case GRABO_LE:
10405 6 : return GDALComputedRasterBand::Operation::OP_LE;
10406 6 : case GRABO_EQ:
10407 6 : return GDALComputedRasterBand::Operation::OP_EQ;
10408 6 : case GRABO_NE:
10409 6 : break;
10410 12 : case GRABO_LOGICAL_AND:
10411 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
10412 12 : case GRABO_LOGICAL_OR:
10413 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
10414 : }
10415 6 : return GDALComputedRasterBand::Operation::OP_NE;
10416 : }
10417 :
10418 : /************************************************************************/
10419 : /* GDALRasterBandBinaryOpBand() */
10420 : /************************************************************************/
10421 :
10422 : /** Apply a binary operation on this band with another one.
10423 : *
10424 : * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
10425 : * "hBand1 - hBand2".
10426 : *
10427 : * The resulting band is lazy evaluated. A reference is taken on both input
10428 : * datasets.
10429 : *
10430 : * @since 3.12
10431 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10432 : */
10433 : GDALComputedRasterBandH
10434 55 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
10435 : GDALRasterAlgebraBinaryOperation eOp,
10436 : GDALRasterBandH hOtherBand)
10437 : {
10438 55 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10439 55 : VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
10440 : #ifndef HAVE_MUPARSER
10441 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10442 : {
10443 : CPLError(
10444 : CE_Failure, CPLE_NotSupported,
10445 : "Band comparison operators not available on a GDAL build without "
10446 : "muparser");
10447 : return nullptr;
10448 : }
10449 : #endif
10450 55 : auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
10451 55 : auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
10452 : try
10453 : {
10454 55 : GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
10455 : }
10456 12 : catch (const std::exception &e)
10457 : {
10458 12 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
10459 12 : return nullptr;
10460 : }
10461 : return new GDALComputedRasterBand(
10462 43 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
10463 43 : secondBand);
10464 : }
10465 :
10466 : /************************************************************************/
10467 : /* GDALRasterBandBinaryOpDouble() */
10468 : /************************************************************************/
10469 :
10470 : /** Apply a binary operation on this band with a constant
10471 : *
10472 : * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
10473 : * "hBand - constant".
10474 : *
10475 : * The resulting band is lazy evaluated. A reference is taken on the input
10476 : * dataset.
10477 : *
10478 : * @since 3.12
10479 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10480 : */
10481 : GDALComputedRasterBandH
10482 58 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
10483 : GDALRasterAlgebraBinaryOperation eOp,
10484 : double constant)
10485 : {
10486 58 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10487 : #ifndef HAVE_MUPARSER
10488 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10489 : {
10490 : CPLError(
10491 : CE_Failure, CPLE_NotSupported,
10492 : "Band comparison operators not available on a GDAL build without "
10493 : "muparser");
10494 : return nullptr;
10495 : }
10496 : #endif
10497 : return new GDALComputedRasterBand(
10498 58 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
10499 58 : *(GDALRasterBand::FromHandle(hBand)), constant);
10500 : }
10501 :
10502 : /************************************************************************/
10503 : /* GDALRasterBandBinaryOpDoubleToBand() */
10504 : /************************************************************************/
10505 :
10506 : /** Apply a binary operation on the constant with this band
10507 : *
10508 : * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
10509 : * "constant - hBand".
10510 : *
10511 : * The resulting band is lazy evaluated. A reference is taken on the input
10512 : * dataset.
10513 : *
10514 : * @since 3.12
10515 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10516 : */
10517 : GDALComputedRasterBandH
10518 17 : GDALRasterBandBinaryOpDoubleToBand(double constant,
10519 : GDALRasterAlgebraBinaryOperation eOp,
10520 : GDALRasterBandH hBand)
10521 : {
10522 17 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10523 : #ifndef HAVE_MUPARSER
10524 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10525 : {
10526 : CPLError(
10527 : CE_Failure, CPLE_NotSupported,
10528 : "Band comparison operators not available on a GDAL build without "
10529 : "muparser");
10530 : return nullptr;
10531 : }
10532 : #endif
10533 17 : switch (eOp)
10534 : {
10535 15 : case GRABO_ADD:
10536 : case GRABO_MUL:
10537 : {
10538 : return new GDALComputedRasterBand(
10539 15 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
10540 15 : *(GDALRasterBand::FromHandle(hBand)), constant);
10541 : }
10542 :
10543 1 : case GRABO_DIV:
10544 : case GRABO_GT:
10545 : case GRABO_GE:
10546 : case GRABO_LT:
10547 : case GRABO_LE:
10548 : case GRABO_EQ:
10549 : case GRABO_NE:
10550 : case GRABO_LOGICAL_AND:
10551 : case GRABO_LOGICAL_OR:
10552 : {
10553 : return new GDALComputedRasterBand(
10554 1 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
10555 1 : *(GDALRasterBand::FromHandle(hBand)));
10556 : }
10557 :
10558 1 : case GRABO_SUB:
10559 : {
10560 1 : break;
10561 : }
10562 : }
10563 :
10564 : return new GDALComputedRasterBand(
10565 : GDALComputedRasterBand::Operation::OP_ADD,
10566 2 : GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
10567 1 : *(GDALRasterBand::FromHandle(hBand)), -1.0),
10568 1 : constant);
10569 : }
10570 :
10571 : /************************************************************************/
10572 : /* operator+() */
10573 : /************************************************************************/
10574 :
10575 : /** Add this band with another one.
10576 : *
10577 : * The resulting band is lazy evaluated. A reference is taken on both input
10578 : * datasets.
10579 : *
10580 : * @since 3.12
10581 : * @throw std::runtime_error if both bands do not have the same dimensions.
10582 : */
10583 : GDALComputedRasterBand
10584 2 : GDALRasterBand::operator+(const GDALRasterBand &other) const
10585 : {
10586 2 : ThrowIfNotSameDimensions(*this, other);
10587 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
10588 1 : *this, other);
10589 : }
10590 :
10591 : /************************************************************************/
10592 : /* operator+() */
10593 : /************************************************************************/
10594 :
10595 : /** Add this band with a constant.
10596 : *
10597 : * The resulting band is lazy evaluated. A reference is taken on the input
10598 : * dataset.
10599 : *
10600 : * @since 3.12
10601 : */
10602 11 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
10603 : {
10604 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
10605 11 : *this, constant);
10606 : }
10607 :
10608 : /************************************************************************/
10609 : /* operator+() */
10610 : /************************************************************************/
10611 :
10612 : /** Add a band with a constant.
10613 : *
10614 : * The resulting band is lazy evaluated. A reference is taken on the input
10615 : * dataset.
10616 : *
10617 : * @since 3.12
10618 : */
10619 1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
10620 : {
10621 1 : return other + constant;
10622 : }
10623 :
10624 : /************************************************************************/
10625 : /* operator-() */
10626 : /************************************************************************/
10627 :
10628 : /** Subtract this band with another one.
10629 : *
10630 : * The resulting band is lazy evaluated. A reference is taken on both input
10631 : * datasets.
10632 : *
10633 : * @since 3.12
10634 : * @throw std::runtime_error if both bands do not have the same dimensions.
10635 : */
10636 : GDALComputedRasterBand
10637 2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
10638 : {
10639 2 : ThrowIfNotSameDimensions(*this, other);
10640 : return GDALComputedRasterBand(
10641 2 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
10642 : }
10643 :
10644 : /************************************************************************/
10645 : /* operator-() */
10646 : /************************************************************************/
10647 :
10648 : /** Subtract this band with a constant.
10649 : *
10650 : * The resulting band is lazy evaluated. A reference is taken on the input
10651 : * dataset.
10652 : *
10653 : * @since 3.12
10654 : */
10655 1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
10656 : {
10657 : return GDALComputedRasterBand(
10658 1 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
10659 : }
10660 :
10661 : /************************************************************************/
10662 : /* operator-() */
10663 : /************************************************************************/
10664 :
10665 : /** Subtract a constant with a band.
10666 : *
10667 : * The resulting band is lazy evaluated. A reference is taken on the input
10668 : * dataset.
10669 : *
10670 : * @since 3.12
10671 : */
10672 1 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
10673 : {
10674 2 : return other * (-1.0) + constant;
10675 : }
10676 :
10677 : /************************************************************************/
10678 : /* operator*() */
10679 : /************************************************************************/
10680 :
10681 : /** Multiply this band with another one.
10682 : *
10683 : * The resulting band is lazy evaluated. A reference is taken on both input
10684 : * datasets.
10685 : *
10686 : * @since 3.12
10687 : * @throw std::runtime_error if both bands do not have the same dimensions.
10688 : */
10689 : GDALComputedRasterBand
10690 1 : GDALRasterBand::operator*(const GDALRasterBand &other) const
10691 : {
10692 1 : ThrowIfNotSameDimensions(*this, other);
10693 : return GDALComputedRasterBand(
10694 1 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
10695 : }
10696 :
10697 : /************************************************************************/
10698 : /* operator*() */
10699 : /************************************************************************/
10700 :
10701 : /** Multiply this band by a constant.
10702 : *
10703 : * The resulting band is lazy evaluated. A reference is taken on the input
10704 : * dataset.
10705 : *
10706 : * @since 3.12
10707 : */
10708 12 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
10709 : {
10710 : return GDALComputedRasterBand(
10711 12 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
10712 : }
10713 :
10714 : /************************************************************************/
10715 : /* operator*() */
10716 : /************************************************************************/
10717 :
10718 : /** Multiply a band with a constant.
10719 : *
10720 : * The resulting band is lazy evaluated. A reference is taken on the input
10721 : * dataset.
10722 : *
10723 : * @since 3.12
10724 : */
10725 2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
10726 : {
10727 2 : return other * constant;
10728 : }
10729 :
10730 : /************************************************************************/
10731 : /* operator/() */
10732 : /************************************************************************/
10733 :
10734 : /** Divide this band with another one.
10735 : *
10736 : * The resulting band is lazy evaluated. A reference is taken on both input
10737 : * datasets.
10738 : *
10739 : * @since 3.12
10740 : * @throw std::runtime_error if both bands do not have the same dimensions.
10741 : */
10742 : GDALComputedRasterBand
10743 1 : GDALRasterBand::operator/(const GDALRasterBand &other) const
10744 : {
10745 1 : ThrowIfNotSameDimensions(*this, other);
10746 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10747 1 : *this, other);
10748 : }
10749 :
10750 : /************************************************************************/
10751 : /* operator/() */
10752 : /************************************************************************/
10753 :
10754 : /** Divide this band by a constant.
10755 : *
10756 : * The resulting band is lazy evaluated. A reference is taken on the input
10757 : * dataset.
10758 : *
10759 : * @since 3.12
10760 : */
10761 1 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
10762 : {
10763 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10764 1 : *this, constant);
10765 : }
10766 :
10767 : /************************************************************************/
10768 : /* operator/() */
10769 : /************************************************************************/
10770 :
10771 : /** Divide a constant by a band.
10772 : *
10773 : * The resulting band is lazy evaluated. A reference is taken on the input
10774 : * dataset.
10775 : *
10776 : * @since 3.12
10777 : */
10778 1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
10779 : {
10780 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10781 1 : constant, other);
10782 : }
10783 :
10784 : /************************************************************************/
10785 : /* ThrowIfNotMuparser() */
10786 : /************************************************************************/
10787 :
10788 : #ifndef HAVE_MUPARSER
10789 : static GDALComputedRasterBand ThrowIfNotMuparser()
10790 : {
10791 : throw std::runtime_error("Band comparison operators not available on a "
10792 : "GDAL build without muparser");
10793 : }
10794 : #endif
10795 :
10796 : /************************************************************************/
10797 : /* operator>() */
10798 : /************************************************************************/
10799 :
10800 : /** Return a band whose value is 1 if the pixel value of the left operand
10801 : * is greater than the pixel value of the right operand.
10802 : *
10803 : * The resulting band is lazy evaluated. A reference is taken on the input
10804 : * dataset.
10805 : *
10806 : * @since 3.12
10807 : */
10808 : GDALComputedRasterBand
10809 3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
10810 : {
10811 : #ifndef HAVE_MUPARSER
10812 : (void)other;
10813 : return ThrowIfNotMuparser();
10814 : #else
10815 3 : ThrowIfNotSameDimensions(*this, other);
10816 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10817 2 : *this, other);
10818 : #endif
10819 : }
10820 :
10821 : /************************************************************************/
10822 : /* operator>() */
10823 : /************************************************************************/
10824 :
10825 : /** Return a band whose value is 1 if the pixel value of the left operand
10826 : * is greater than the constant.
10827 : *
10828 : * The resulting band is lazy evaluated. A reference is taken on the input
10829 : * dataset.
10830 : *
10831 : * @since 3.12
10832 : */
10833 3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
10834 : {
10835 : #ifndef HAVE_MUPARSER
10836 : (void)constant;
10837 : return ThrowIfNotMuparser();
10838 : #else
10839 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10840 3 : *this, constant);
10841 : #endif
10842 : }
10843 :
10844 : /************************************************************************/
10845 : /* operator>() */
10846 : /************************************************************************/
10847 :
10848 : /** Return a band whose value is 1 if the constant is greater than the pixel
10849 : * value of the right operand.
10850 : *
10851 : * The resulting band is lazy evaluated. A reference is taken on the input
10852 : * dataset.
10853 : *
10854 : * @since 3.12
10855 : */
10856 2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
10857 : {
10858 : #ifndef HAVE_MUPARSER
10859 : (void)constant;
10860 : (void)other;
10861 : return ThrowIfNotMuparser();
10862 : #else
10863 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10864 2 : constant, other);
10865 : #endif
10866 : }
10867 :
10868 : /************************************************************************/
10869 : /* operator>=() */
10870 : /************************************************************************/
10871 :
10872 : /** Return a band whose value is 1 if the pixel value of the left operand
10873 : * is greater or equal to the pixel value of the right operand.
10874 : *
10875 : * The resulting band is lazy evaluated. A reference is taken on the input
10876 : * dataset.
10877 : *
10878 : * @since 3.12
10879 : */
10880 : GDALComputedRasterBand
10881 4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
10882 : {
10883 : #ifndef HAVE_MUPARSER
10884 : (void)other;
10885 : return ThrowIfNotMuparser();
10886 : #else
10887 4 : ThrowIfNotSameDimensions(*this, other);
10888 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10889 3 : *this, other);
10890 : #endif
10891 : }
10892 :
10893 : /************************************************************************/
10894 : /* operator>=() */
10895 : /************************************************************************/
10896 :
10897 : /** Return a band whose value is 1 if the pixel value of the left operand
10898 : * is greater or equal to the constant.
10899 : *
10900 : * The resulting band is lazy evaluated. A reference is taken on the input
10901 : * dataset.
10902 : *
10903 : * @since 3.12
10904 : */
10905 3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
10906 : {
10907 : #ifndef HAVE_MUPARSER
10908 : (void)constant;
10909 : return ThrowIfNotMuparser();
10910 : #else
10911 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10912 3 : *this, constant);
10913 : #endif
10914 : }
10915 :
10916 : /************************************************************************/
10917 : /* operator>=() */
10918 : /************************************************************************/
10919 :
10920 : /** Return a band whose value is 1 if the constant is greater or equal to
10921 : * the pixel value of the right operand.
10922 : *
10923 : * The resulting band is lazy evaluated. A reference is taken on the input
10924 : * dataset.
10925 : *
10926 : * @since 3.12
10927 : */
10928 2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
10929 : {
10930 : #ifndef HAVE_MUPARSER
10931 : (void)constant;
10932 : (void)other;
10933 : return ThrowIfNotMuparser();
10934 : #else
10935 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10936 2 : constant, other);
10937 : #endif
10938 : }
10939 :
10940 : /************************************************************************/
10941 : /* operator<() */
10942 : /************************************************************************/
10943 :
10944 : /** Return a band whose value is 1 if the pixel value of the left operand
10945 : * is lesser than the pixel value of the right operand.
10946 : *
10947 : * The resulting band is lazy evaluated. A reference is taken on the input
10948 : * dataset.
10949 : *
10950 : * @since 3.12
10951 : */
10952 : GDALComputedRasterBand
10953 3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
10954 : {
10955 : #ifndef HAVE_MUPARSER
10956 : (void)other;
10957 : return ThrowIfNotMuparser();
10958 : #else
10959 3 : ThrowIfNotSameDimensions(*this, other);
10960 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
10961 2 : *this, other);
10962 : #endif
10963 : }
10964 :
10965 : /************************************************************************/
10966 : /* operator<() */
10967 : /************************************************************************/
10968 :
10969 : /** Return a band whose value is 1 if the pixel value of the left operand
10970 : * is lesser than the constant.
10971 : *
10972 : * The resulting band is lazy evaluated. A reference is taken on the input
10973 : * dataset.
10974 : *
10975 : * @since 3.12
10976 : */
10977 3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
10978 : {
10979 : #ifndef HAVE_MUPARSER
10980 : (void)constant;
10981 : return ThrowIfNotMuparser();
10982 : #else
10983 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
10984 3 : *this, constant);
10985 : #endif
10986 : }
10987 :
10988 : /************************************************************************/
10989 : /* operator<() */
10990 : /************************************************************************/
10991 :
10992 : /** Return a band whose value is 1 if the constant is lesser than the pixel
10993 : * value of the right operand.
10994 : *
10995 : * The resulting band is lazy evaluated. A reference is taken on the input
10996 : * dataset.
10997 : *
10998 : * @since 3.12
10999 : */
11000 2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
11001 : {
11002 : #ifndef HAVE_MUPARSER
11003 : (void)constant;
11004 : (void)other;
11005 : return ThrowIfNotMuparser();
11006 : #else
11007 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11008 2 : constant, other);
11009 : #endif
11010 : }
11011 :
11012 : /************************************************************************/
11013 : /* operator<=() */
11014 : /************************************************************************/
11015 :
11016 : /** Return a band whose value is 1 if the pixel value of the left operand
11017 : * is lesser or equal to the pixel value of the right operand.
11018 : *
11019 : * The resulting band is lazy evaluated. A reference is taken on the input
11020 : * dataset.
11021 : *
11022 : * @since 3.12
11023 : */
11024 : GDALComputedRasterBand
11025 4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
11026 : {
11027 : #ifndef HAVE_MUPARSER
11028 : (void)other;
11029 : return ThrowIfNotMuparser();
11030 : #else
11031 4 : ThrowIfNotSameDimensions(*this, other);
11032 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11033 3 : *this, other);
11034 : #endif
11035 : }
11036 :
11037 : /************************************************************************/
11038 : /* operator<=() */
11039 : /************************************************************************/
11040 :
11041 : /** Return a band whose value is 1 if the pixel value of the left operand
11042 : * is lesser or equal to the constant.
11043 : *
11044 : * The resulting band is lazy evaluated. A reference is taken on the input
11045 : * dataset.
11046 : *
11047 : * @since 3.12
11048 : */
11049 3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
11050 : {
11051 : #ifndef HAVE_MUPARSER
11052 : (void)constant;
11053 : return ThrowIfNotMuparser();
11054 : #else
11055 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11056 3 : *this, constant);
11057 : #endif
11058 : }
11059 :
11060 : /************************************************************************/
11061 : /* operator<=() */
11062 : /************************************************************************/
11063 :
11064 : /** Return a band whose value is 1 if the constant is lesser or equal to
11065 : * the pixel value of the right operand.
11066 : *
11067 : * The resulting band is lazy evaluated. A reference is taken on the input
11068 : * dataset.
11069 : *
11070 : * @since 3.12
11071 : */
11072 2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
11073 : {
11074 : #ifndef HAVE_MUPARSER
11075 : (void)constant;
11076 : (void)other;
11077 : return ThrowIfNotMuparser();
11078 : #else
11079 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11080 2 : constant, other);
11081 : #endif
11082 : }
11083 :
11084 : /************************************************************************/
11085 : /* operator==() */
11086 : /************************************************************************/
11087 :
11088 : /** Return a band whose value is 1 if the pixel value of the left operand
11089 : * is equal to the pixel value of the right operand.
11090 : *
11091 : * The resulting band is lazy evaluated. A reference is taken on the input
11092 : * dataset.
11093 : *
11094 : * @since 3.12
11095 : */
11096 : GDALComputedRasterBand
11097 3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
11098 : {
11099 : #ifndef HAVE_MUPARSER
11100 : (void)other;
11101 : return ThrowIfNotMuparser();
11102 : #else
11103 3 : ThrowIfNotSameDimensions(*this, other);
11104 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11105 2 : *this, other);
11106 : #endif
11107 : }
11108 :
11109 : /************************************************************************/
11110 : /* operator==() */
11111 : /************************************************************************/
11112 :
11113 : /** Return a band whose value is 1 if the pixel value of the left operand
11114 : * is equal to the constant.
11115 : *
11116 : * The resulting band is lazy evaluated. A reference is taken on the input
11117 : * dataset.
11118 : *
11119 : * @since 3.12
11120 : */
11121 8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
11122 : {
11123 : #ifndef HAVE_MUPARSER
11124 : (void)constant;
11125 : return ThrowIfNotMuparser();
11126 : #else
11127 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11128 8 : *this, constant);
11129 : #endif
11130 : }
11131 :
11132 : /************************************************************************/
11133 : /* operator==() */
11134 : /************************************************************************/
11135 :
11136 : /** Return a band whose value is 1 if the constant is equal to
11137 : * the pixel value of the right operand.
11138 : *
11139 : * The resulting band is lazy evaluated. A reference is taken on the input
11140 : * dataset.
11141 : *
11142 : * @since 3.12
11143 : */
11144 2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
11145 : {
11146 : #ifndef HAVE_MUPARSER
11147 : (void)constant;
11148 : (void)other;
11149 : return ThrowIfNotMuparser();
11150 : #else
11151 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11152 2 : constant, other);
11153 : #endif
11154 : }
11155 :
11156 : /************************************************************************/
11157 : /* operator!=() */
11158 : /************************************************************************/
11159 :
11160 : /** Return a band whose value is 1 if the pixel value of the left operand
11161 : * is different from the pixel value of the right operand.
11162 : *
11163 : * The resulting band is lazy evaluated. A reference is taken on the input
11164 : * dataset.
11165 : *
11166 : * @since 3.12
11167 : */
11168 : GDALComputedRasterBand
11169 3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
11170 : {
11171 : #ifndef HAVE_MUPARSER
11172 : (void)other;
11173 : return ThrowIfNotMuparser();
11174 : #else
11175 3 : ThrowIfNotSameDimensions(*this, other);
11176 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11177 2 : *this, other);
11178 : #endif
11179 : }
11180 :
11181 : /************************************************************************/
11182 : /* operator!=() */
11183 : /************************************************************************/
11184 :
11185 : /** Return a band whose value is 1 if the pixel value of the left operand
11186 : * is different from the constant.
11187 : *
11188 : * The resulting band is lazy evaluated. A reference is taken on the input
11189 : * dataset.
11190 : *
11191 : * @since 3.12
11192 : */
11193 6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
11194 : {
11195 : #ifndef HAVE_MUPARSER
11196 : (void)constant;
11197 : return ThrowIfNotMuparser();
11198 : #else
11199 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11200 6 : *this, constant);
11201 : #endif
11202 : }
11203 :
11204 : /************************************************************************/
11205 : /* operator!=() */
11206 : /************************************************************************/
11207 :
11208 : /** Return a band whose value is 1 if the constant is different from
11209 : * the pixel value of the right operand.
11210 : *
11211 : * The resulting band is lazy evaluated. A reference is taken on the input
11212 : * dataset.
11213 : *
11214 : * @since 3.12
11215 : */
11216 2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
11217 : {
11218 : #ifndef HAVE_MUPARSER
11219 : (void)constant;
11220 : (void)other;
11221 : return ThrowIfNotMuparser();
11222 : #else
11223 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11224 2 : constant, other);
11225 : #endif
11226 : }
11227 :
11228 : #if defined(__GNUC__)
11229 : #pragma GCC diagnostic push
11230 : #pragma GCC diagnostic ignored "-Weffc++"
11231 : #endif
11232 :
11233 : /************************************************************************/
11234 : /* operator&&() */
11235 : /************************************************************************/
11236 :
11237 : /** Return a band whose value is 1 if the pixel value of the left and right
11238 : * operands is true.
11239 : *
11240 : * The resulting band is lazy evaluated. A reference is taken on the input
11241 : * dataset.
11242 : *
11243 : * @since 3.12
11244 : */
11245 : GDALComputedRasterBand
11246 3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
11247 : {
11248 : #ifndef HAVE_MUPARSER
11249 : (void)other;
11250 : return ThrowIfNotMuparser();
11251 : #else
11252 3 : ThrowIfNotSameDimensions(*this, other);
11253 : return GDALComputedRasterBand(
11254 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
11255 : #endif
11256 : }
11257 :
11258 : /************************************************************************/
11259 : /* operator&&() */
11260 : /************************************************************************/
11261 :
11262 : /** Return a band whose value is 1 if the pixel value of the left operand
11263 : * is true, as well as the constant
11264 : *
11265 : * The resulting band is lazy evaluated. A reference is taken on the input
11266 : * dataset.
11267 : *
11268 : * @since 3.12
11269 : */
11270 2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
11271 : {
11272 : #ifndef HAVE_MUPARSER
11273 : (void)constant;
11274 : return ThrowIfNotMuparser();
11275 : #else
11276 : return GDALComputedRasterBand(
11277 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
11278 : #endif
11279 : }
11280 :
11281 : /************************************************************************/
11282 : /* operator&&() */
11283 : /************************************************************************/
11284 :
11285 : /** Return a band whose value is 1 if the constant is true, as well as
11286 : * the pixel value of the right operand.
11287 : *
11288 : * The resulting band is lazy evaluated. A reference is taken on the input
11289 : * dataset.
11290 : *
11291 : * @since 3.12
11292 : */
11293 2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
11294 : {
11295 : #ifndef HAVE_MUPARSER
11296 : (void)constant;
11297 : (void)other;
11298 : return ThrowIfNotMuparser();
11299 : #else
11300 : return GDALComputedRasterBand(
11301 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
11302 : #endif
11303 : }
11304 :
11305 : /************************************************************************/
11306 : /* operator||() */
11307 : /************************************************************************/
11308 :
11309 : /** Return a band whose value is 1 if the pixel value of the left or right
11310 : * operands is true.
11311 : *
11312 : * The resulting band is lazy evaluated. A reference is taken on the input
11313 : * dataset.
11314 : *
11315 : * @since 3.12
11316 : */
11317 : GDALComputedRasterBand
11318 4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
11319 : {
11320 : #ifndef HAVE_MUPARSER
11321 : (void)other;
11322 : return ThrowIfNotMuparser();
11323 : #else
11324 4 : ThrowIfNotSameDimensions(*this, other);
11325 : return GDALComputedRasterBand(
11326 3 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
11327 : #endif
11328 : }
11329 :
11330 : /************************************************************************/
11331 : /* operator||() */
11332 : /************************************************************************/
11333 :
11334 : /** Return a band whose value is 1 if the pixel value of the left operand
11335 : * is true, or if the constant is true
11336 : *
11337 : * The resulting band is lazy evaluated. A reference is taken on the input
11338 : * dataset.
11339 : *
11340 : * @since 3.12
11341 : */
11342 4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
11343 : {
11344 : #ifndef HAVE_MUPARSER
11345 : (void)constant;
11346 : return ThrowIfNotMuparser();
11347 : #else
11348 : return GDALComputedRasterBand(
11349 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
11350 : #endif
11351 : }
11352 :
11353 : /************************************************************************/
11354 : /* operator||() */
11355 : /************************************************************************/
11356 :
11357 : /** Return a band whose value is 1 if the constant is true, or
11358 : * the pixel value of the right operand is true
11359 : *
11360 : * The resulting band is lazy evaluated. A reference is taken on the input
11361 : * dataset.
11362 : *
11363 : * @since 3.12
11364 : */
11365 4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
11366 : {
11367 : #ifndef HAVE_MUPARSER
11368 : (void)constant;
11369 : (void)other;
11370 : return ThrowIfNotMuparser();
11371 : #else
11372 : return GDALComputedRasterBand(
11373 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
11374 : #endif
11375 : }
11376 :
11377 : #if defined(__GNUC__)
11378 : #pragma GCC diagnostic pop
11379 : #endif
11380 :
11381 : /************************************************************************/
11382 : /* operator!() */
11383 : /************************************************************************/
11384 :
11385 : /** Return a band whose value is the logical negation of the pixel value
11386 : *
11387 : * The resulting band is lazy evaluated. A reference is taken on the input
11388 : * dataset.
11389 : *
11390 : * @since 3.12
11391 : */
11392 2 : GDALComputedRasterBand GDALRasterBand::operator!() const
11393 : {
11394 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11395 2 : *this, true);
11396 : }
11397 :
11398 : namespace gdal
11399 : {
11400 :
11401 : /************************************************************************/
11402 : /* IfThenElse() */
11403 : /************************************************************************/
11404 :
11405 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
11406 : * is not zero, or the one from elseBand otherwise.
11407 : *
11408 : * Variants of this method exits where thenBand and/or elseBand can be double
11409 : * values.
11410 : *
11411 : * The resulting band is lazy evaluated. A reference is taken on the input
11412 : * datasets.
11413 : *
11414 : * This method is the same as the C function GDALRasterBandIfThenElse()
11415 : *
11416 : * @since 3.12
11417 : */
11418 5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11419 : const GDALRasterBand &thenBand,
11420 : const GDALRasterBand &elseBand)
11421 : {
11422 : #ifndef HAVE_MUPARSER
11423 : (void)condBand;
11424 : (void)thenBand;
11425 : (void)elseBand;
11426 : return ThrowIfNotMuparser();
11427 : #else
11428 5 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11429 4 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11430 : return GDALComputedRasterBand(
11431 : GDALComputedRasterBand::Operation::OP_TERNARY,
11432 6 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11433 : #endif
11434 : }
11435 :
11436 : //! @cond Doxygen_Suppress
11437 :
11438 : /************************************************************************/
11439 : /* IfThenElse() */
11440 : /************************************************************************/
11441 :
11442 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
11443 : * is not zero, or the one from elseBand otherwise.
11444 : *
11445 : * The resulting band is lazy evaluated. A reference is taken on the input
11446 : * datasets.
11447 : *
11448 : * This method is the same as the C function GDALRasterBandIfThenElse(),
11449 : * with thenBand = (condBand * 0) + thenValue
11450 : *
11451 : * @since 3.12
11452 : */
11453 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11454 : double thenValue,
11455 : const GDALRasterBand &elseBand)
11456 : {
11457 : #ifndef HAVE_MUPARSER
11458 : (void)condBand;
11459 : (void)thenValue;
11460 : (void)elseBand;
11461 : return ThrowIfNotMuparser();
11462 : #else
11463 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11464 : auto thenBand =
11465 1 : (condBand * 0)
11466 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
11467 1 : thenValue;
11468 : return GDALComputedRasterBand(
11469 : GDALComputedRasterBand::Operation::OP_TERNARY,
11470 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11471 : #endif
11472 : }
11473 :
11474 : /************************************************************************/
11475 : /* IfThenElse() */
11476 : /************************************************************************/
11477 :
11478 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
11479 : * is not zero, or the one from elseValue otherwise.
11480 : *
11481 : * The resulting band is lazy evaluated. A reference is taken on the input
11482 : * datasets.
11483 : *
11484 : * This method is the same as the C function GDALRasterBandIfThenElse(),
11485 : * with elseBand = (condBand * 0) + elseValue
11486 :
11487 : * @since 3.12
11488 : */
11489 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11490 : const GDALRasterBand &thenBand,
11491 : double elseValue)
11492 : {
11493 : #ifndef HAVE_MUPARSER
11494 : (void)condBand;
11495 : (void)thenBand;
11496 : (void)elseValue;
11497 : return ThrowIfNotMuparser();
11498 : #else
11499 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11500 : auto elseBand =
11501 1 : (condBand * 0)
11502 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
11503 1 : elseValue;
11504 : return GDALComputedRasterBand(
11505 : GDALComputedRasterBand::Operation::OP_TERNARY,
11506 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11507 : #endif
11508 : }
11509 :
11510 : /************************************************************************/
11511 : /* IfThenElse() */
11512 : /************************************************************************/
11513 :
11514 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
11515 : * is not zero, or the one from elseValue otherwise.
11516 : *
11517 : * The resulting band is lazy evaluated. A reference is taken on the input
11518 : * datasets.
11519 : *
11520 : * This method is the same as the C function GDALRasterBandIfThenElse(),
11521 : * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
11522 : *
11523 : * @since 3.12
11524 : */
11525 3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11526 : double thenValue, double elseValue)
11527 : {
11528 : #ifndef HAVE_MUPARSER
11529 : (void)condBand;
11530 : (void)thenValue;
11531 : (void)elseValue;
11532 : return ThrowIfNotMuparser();
11533 : #else
11534 : auto thenBand =
11535 3 : (condBand * 0)
11536 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
11537 6 : thenValue;
11538 : auto elseBand =
11539 3 : (condBand * 0)
11540 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
11541 3 : elseValue;
11542 : return GDALComputedRasterBand(
11543 : GDALComputedRasterBand::Operation::OP_TERNARY,
11544 9 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11545 : #endif
11546 : }
11547 :
11548 : //! @endcond
11549 :
11550 : } // namespace gdal
11551 :
11552 : /************************************************************************/
11553 : /* GDALRasterBandIfThenElse() */
11554 : /************************************************************************/
11555 :
11556 : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
11557 : * is not zero, or the one from hElseBand otherwise.
11558 : *
11559 : * The resulting band is lazy evaluated. A reference is taken on the input
11560 : * datasets.
11561 : *
11562 : * This function is the same as the C++ method gdal::IfThenElse()
11563 : *
11564 : * @since 3.12
11565 : */
11566 12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
11567 : GDALRasterBandH hThenBand,
11568 : GDALRasterBandH hElseBand)
11569 : {
11570 12 : VALIDATE_POINTER1(hCondBand, __func__, nullptr);
11571 12 : VALIDATE_POINTER1(hThenBand, __func__, nullptr);
11572 12 : VALIDATE_POINTER1(hElseBand, __func__, nullptr);
11573 : #ifndef HAVE_MUPARSER
11574 : CPLError(CE_Failure, CPLE_NotSupported,
11575 : "Band comparison operators not available on a GDAL build without "
11576 : "muparser");
11577 : return nullptr;
11578 : #else
11579 :
11580 12 : auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
11581 12 : auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
11582 12 : auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
11583 : try
11584 : {
11585 12 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11586 11 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11587 : }
11588 2 : catch (const std::exception &e)
11589 : {
11590 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11591 2 : return nullptr;
11592 : }
11593 : return new GDALComputedRasterBand(
11594 : GDALComputedRasterBand::Operation::OP_TERNARY,
11595 10 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11596 : #endif
11597 : }
11598 :
11599 : /************************************************************************/
11600 : /* GDALRasterBand::AsType() */
11601 : /************************************************************************/
11602 :
11603 : /** Cast this band to another type.
11604 : *
11605 : * The resulting band is lazy evaluated. A reference is taken on the input
11606 : * dataset.
11607 : *
11608 : * This method is the same as the C function GDALRasterBandAsDataType()
11609 : *
11610 : * @since 3.12
11611 : */
11612 10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
11613 : {
11614 10 : if (dt == GDT_Unknown)
11615 : {
11616 1 : throw std::runtime_error("AsType(GDT_Unknown) is not supported");
11617 : }
11618 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
11619 9 : *this, dt);
11620 : }
11621 :
11622 : /************************************************************************/
11623 : /* GDALRasterBandAsDataType() */
11624 : /************************************************************************/
11625 :
11626 : /** Cast this band to another type.
11627 : *
11628 : * The resulting band is lazy evaluated. A reference is taken on the input
11629 : * dataset.
11630 : *
11631 : * This function is the same as the C++ method GDALRasterBand::AsType()
11632 : *
11633 : * @since 3.12
11634 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11635 : */
11636 16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
11637 : GDALDataType eDT)
11638 : {
11639 16 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11640 16 : if (eDT == GDT_Unknown)
11641 : {
11642 1 : CPLError(CE_Failure, CPLE_NotSupported,
11643 : "GDALRasterBandAsDataType(GDT_Unknown) not supported");
11644 1 : return nullptr;
11645 : }
11646 : return new GDALComputedRasterBand(
11647 : GDALComputedRasterBand::Operation::OP_CAST,
11648 15 : *(GDALRasterBand::FromHandle(hBand)), eDT);
11649 : }
11650 :
11651 : /************************************************************************/
11652 : /* GetBandVector() */
11653 : /************************************************************************/
11654 :
11655 : static std::vector<const GDALRasterBand *>
11656 10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
11657 : {
11658 10 : std::vector<const GDALRasterBand *> bands;
11659 27 : for (size_t i = 0; i < nBandCount; ++i)
11660 : {
11661 20 : if (i > 0)
11662 : {
11663 10 : GDALRasterBand::ThrowIfNotSameDimensions(
11664 10 : *(GDALRasterBand::FromHandle(pahBands[0])),
11665 10 : *(GDALRasterBand::FromHandle(pahBands[i])));
11666 : }
11667 17 : bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
11668 : }
11669 7 : return bands;
11670 : }
11671 :
11672 : /************************************************************************/
11673 : /* GDALOperationOnNBands() */
11674 : /************************************************************************/
11675 :
11676 : static GDALComputedRasterBandH
11677 11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
11678 : GDALRasterBandH *pahBands)
11679 : {
11680 11 : VALIDATE_POINTER1(pahBands, __func__, nullptr);
11681 11 : if (nBandCount == 0)
11682 : {
11683 1 : CPLError(CE_Failure, CPLE_AppDefined,
11684 : "At least one band should be passed");
11685 1 : return nullptr;
11686 : }
11687 :
11688 20 : std::vector<const GDALRasterBand *> bands;
11689 : try
11690 : {
11691 10 : bands = GetBandVector(nBandCount, pahBands);
11692 : }
11693 3 : catch (const std::exception &e)
11694 : {
11695 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11696 3 : return nullptr;
11697 : }
11698 7 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
11699 : }
11700 :
11701 : /************************************************************************/
11702 : /* GDALMaximumOfNBands() */
11703 : /************************************************************************/
11704 :
11705 : /** Return a band whose each pixel value is the maximum of the corresponding
11706 : * pixel values in the input bands.
11707 : *
11708 : * The resulting band is lazy evaluated. A reference is taken on input
11709 : * datasets.
11710 : *
11711 : * This function is the same as the C ++ method gdal::max()
11712 : *
11713 : * @since 3.12
11714 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11715 : */
11716 4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
11717 : GDALRasterBandH *pahBands)
11718 : {
11719 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
11720 4 : nBandCount, pahBands);
11721 : }
11722 :
11723 : /************************************************************************/
11724 : /* gdal::max() */
11725 : /************************************************************************/
11726 :
11727 : namespace gdal
11728 : {
11729 : /** Return a band whose each pixel value is the maximum of the corresponding
11730 : * pixel values in the inputs (bands or constants)
11731 : *
11732 : * The resulting band is lazy evaluated. A reference is taken on input
11733 : * datasets.
11734 : *
11735 : * Two or more bands can be passed.
11736 : *
11737 : * This method is the same as the C function GDALMaximumOfNBands()
11738 : *
11739 : * @since 3.12
11740 : * @throw std::runtime_error if bands do not have the same dimensions.
11741 : */
11742 1 : GDALComputedRasterBand max(const GDALRasterBand &first,
11743 : const GDALRasterBand &second)
11744 : {
11745 1 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11746 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
11747 1 : first, second);
11748 : }
11749 : } // namespace gdal
11750 :
11751 : /************************************************************************/
11752 : /* GDALRasterBandMaxConstant() */
11753 : /************************************************************************/
11754 :
11755 : /** Return a band whose each pixel value is the maximum of the corresponding
11756 : * pixel values in the input band and the constant.
11757 : *
11758 : * The resulting band is lazy evaluated. A reference is taken on the input
11759 : * dataset.
11760 : *
11761 : * This function is the same as the C ++ method gdal::max()
11762 : *
11763 : * @since 3.12
11764 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11765 : */
11766 2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
11767 : double dfConstant)
11768 : {
11769 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
11770 : GDALComputedRasterBand::Operation::OP_MAX,
11771 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
11772 6 : dfConstant));
11773 : }
11774 :
11775 : /************************************************************************/
11776 : /* GDALMinimumOfNBands() */
11777 : /************************************************************************/
11778 :
11779 : /** Return a band whose each pixel value is the minimum of the corresponding
11780 : * pixel values in the input bands.
11781 : *
11782 : * The resulting band is lazy evaluated. A reference is taken on input
11783 : * datasets.
11784 : *
11785 : * This function is the same as the C ++ method gdal::min()
11786 : *
11787 : * @since 3.12
11788 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11789 : */
11790 4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
11791 : GDALRasterBandH *pahBands)
11792 : {
11793 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
11794 4 : nBandCount, pahBands);
11795 : }
11796 :
11797 : /************************************************************************/
11798 : /* gdal::min() */
11799 : /************************************************************************/
11800 :
11801 : namespace gdal
11802 : {
11803 : /** Return a band whose each pixel value is the minimum of the corresponding
11804 : * pixel values in the inputs (bands or constants)
11805 : *
11806 : * The resulting band is lazy evaluated. A reference is taken on input
11807 : * datasets.
11808 : *
11809 : * Two or more bands can be passed.
11810 : *
11811 : * This method is the same as the C function GDALMinimumOfNBands()
11812 : *
11813 : * @since 3.12
11814 : * @throw std::runtime_error if bands do not have the same dimensions.
11815 : */
11816 0 : GDALComputedRasterBand min(const GDALRasterBand &first,
11817 : const GDALRasterBand &second)
11818 : {
11819 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11820 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
11821 0 : first, second);
11822 : }
11823 : } // namespace gdal
11824 :
11825 : /************************************************************************/
11826 : /* GDALRasterBandMinConstant() */
11827 : /************************************************************************/
11828 :
11829 : /** Return a band whose each pixel value is the minimum of the corresponding
11830 : * pixel values in the input band and the constant.
11831 : *
11832 : * The resulting band is lazy evaluated. A reference is taken on the input
11833 : * dataset.
11834 : *
11835 : * This function is the same as the C ++ method gdal::min()
11836 : *
11837 : * @since 3.12
11838 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11839 : */
11840 2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
11841 : double dfConstant)
11842 : {
11843 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
11844 : GDALComputedRasterBand::Operation::OP_MIN,
11845 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
11846 6 : dfConstant));
11847 : }
11848 :
11849 : /************************************************************************/
11850 : /* GDALMeanOfNBands() */
11851 : /************************************************************************/
11852 :
11853 : /** Return a band whose each pixel value is the arithmetic mean of the
11854 : * corresponding pixel values in the input bands.
11855 : *
11856 : * The resulting band is lazy evaluated. A reference is taken on input
11857 : * datasets.
11858 : *
11859 : * This function is the same as the C ++ method gdal::mean()
11860 : *
11861 : * @since 3.12
11862 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11863 : */
11864 3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
11865 : GDALRasterBandH *pahBands)
11866 : {
11867 3 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
11868 3 : nBandCount, pahBands);
11869 : }
11870 :
11871 : /************************************************************************/
11872 : /* gdal::mean() */
11873 : /************************************************************************/
11874 :
11875 : namespace gdal
11876 : {
11877 :
11878 : /** Return a band whose each pixel value is the arithmetic mean of the
11879 : * corresponding pixel values in the input bands.
11880 : *
11881 : * The resulting band is lazy evaluated. A reference is taken on input
11882 : * datasets.
11883 : *
11884 : * Two or more bands can be passed.
11885 : *
11886 : * This method is the same as the C function GDALMeanOfNBands()
11887 : *
11888 : * @since 3.12
11889 : * @throw std::runtime_error if bands do not have the same dimensions.
11890 : */
11891 0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
11892 : const GDALRasterBand &second)
11893 : {
11894 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11895 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
11896 0 : first, second);
11897 : }
11898 : } // namespace gdal
|