Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Base class for format specific band class implementation. This
5 : * base class provides default implementation for many methods.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1998, Frank Warmerdam
10 : * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "cpl_port.h"
16 : #include "gdal_priv.h"
17 :
18 : #include <climits>
19 : #include <cmath>
20 : #include <cstdarg>
21 : #include <cstddef>
22 : #include <cstdio>
23 : #include <cstdlib>
24 : #include <cstring>
25 : #include <algorithm>
26 : #include <limits>
27 : #include <memory>
28 : #include <new>
29 : #include <type_traits>
30 :
31 : #include "cpl_conv.h"
32 : #include "cpl_error.h"
33 : #include "cpl_float.h"
34 : #include "cpl_progress.h"
35 : #include "cpl_string.h"
36 : #include "cpl_virtualmem.h"
37 : #include "cpl_vsi.h"
38 : #include "gdal.h"
39 : #include "gdal_rat.h"
40 : #include "gdal_priv_templates.hpp"
41 : #include "gdal_interpolateatpoint.h"
42 : #include "gdal_minmax_element.hpp"
43 :
44 : /************************************************************************/
45 : /* GDALRasterBand() */
46 : /************************************************************************/
47 :
48 : /*! Constructor. Applications should never create GDALRasterBands directly. */
49 :
50 1064690 : GDALRasterBand::GDALRasterBand()
51 : : GDALRasterBand(
52 1064690 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
53 : {
54 1064620 : }
55 :
56 : /** Constructor. Applications should never create GDALRasterBands directly.
57 : * @param bForceCachedIOIn Whether cached IO should be forced.
58 : */
59 1200720 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
60 1200720 : : bForceCachedIO(bForceCachedIOIn)
61 :
62 : {
63 1200610 : }
64 :
65 : /************************************************************************/
66 : /* ~GDALRasterBand() */
67 : /************************************************************************/
68 :
69 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
70 : instead destroy the GDALDataset. */
71 :
72 1200720 : GDALRasterBand::~GDALRasterBand()
73 :
74 : {
75 1200720 : if (poDS && poDS->IsMarkedSuppressOnClose())
76 : {
77 433 : if (poBandBlockCache)
78 384 : poBandBlockCache->DisableDirtyBlockWriting();
79 : }
80 1200720 : GDALRasterBand::FlushCache(true);
81 :
82 1200720 : delete poBandBlockCache;
83 :
84 1200730 : if (static_cast<GIntBig>(nBlockReads) >
85 1200730 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
86 214 : nBand == 1 && poDS != nullptr)
87 : {
88 302 : CPLDebug(
89 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
90 151 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
91 151 : poDS->GetDescription());
92 : }
93 :
94 1200730 : InvalidateMaskBand();
95 1200720 : nBand = -nBand;
96 :
97 1200720 : delete m_poPointsCache;
98 1200720 : }
99 :
100 : /************************************************************************/
101 : /* RasterIO() */
102 : /************************************************************************/
103 :
104 : /**
105 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
106 : * int nXOff, int nYOff, int nXSize, int nYSize,
107 : * void * pData, int nBufXSize, int nBufYSize,
108 : * GDALDataType eBufType,
109 : * GSpacing nPixelSpace,
110 : * GSpacing nLineSpace,
111 : * GDALRasterIOExtraArg* psExtraArg )
112 : * \brief Read/write a region of image data for this band.
113 : *
114 : * This method allows reading a region of a GDALRasterBand into a buffer,
115 : * or writing data from a buffer into a region of a GDALRasterBand. It
116 : * automatically takes care of data type translation if the data type
117 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
118 : * The method also takes care of image decimation / replication if the
119 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
120 : * region being accessed (nXSize x nYSize).
121 : *
122 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
123 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
124 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
125 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
126 : * Or use nLineSpace and a possibly shifted pData value.
127 : *
128 : * The nPixelSpace and nLineSpace parameters allow reading into or
129 : * writing from unusually organized buffers. This is primarily used
130 : * for buffers containing more than one bands raster data in interleaved
131 : * format.
132 : *
133 : * Some formats may efficiently implement decimation into a buffer by
134 : * reading from lower resolution overview images. The logic of the default
135 : * implementation in the base class GDALRasterBand is the following one. It
136 : * computes a target_downscaling_factor from the window of interest and buffer
137 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
138 : * It then walks through overviews and will select the first one whose
139 : * downscaling factor is greater than target_downscaling_factor / 1.2.
140 : *
141 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
142 : * The relationship between target_downscaling_factor and the select overview
143 : * level is the following one:
144 : *
145 : * target_downscaling_factor | selected_overview
146 : * ------------------------- | -----------------
147 : * ]0, 2 / 1.2] | full resolution band
148 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
149 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
150 : * ]8 / 1.2, infinity[ | 8x downsampled band
151 : *
152 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
153 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
154 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
155 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
156 : * this oversampling threshold defaults to 1. Consequently if there are overviews
157 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
158 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
159 : *
160 : * For highest performance full resolution data access, read and write
161 : * on "block boundaries" as returned by GetBlockSize(), or use the
162 : * ReadBlock() and WriteBlock() methods.
163 : *
164 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
165 : * functions.
166 : *
167 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
168 : * write a region of data.
169 : *
170 : * @param nXOff The pixel offset to the top left corner of the region
171 : * of the band to be accessed. This would be zero to start from the left side.
172 : *
173 : * @param nYOff The line offset to the top left corner of the region
174 : * of the band to be accessed. This would be zero to start from the top.
175 : *
176 : * @param nXSize The width of the region of the band to be accessed in pixels.
177 : *
178 : * @param nYSize The height of the region of the band to be accessed in lines.
179 : *
180 : * @param pData The buffer into which the data should be read, or from which
181 : * it should be written. This buffer must contain at least nBufXSize *
182 : * nBufYSize words of type eBufType. It is organized in left to right,
183 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
184 : * and nLineSpace parameters.
185 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
186 : * temporarily modified during the execution of this method (and eventually
187 : * restored back to its original content), so it is not safe to use a buffer
188 : * stored in a read-only section of the calling program.
189 : *
190 : * @param nBufXSize the width of the buffer image into which the desired region
191 : * is to be read, or from which it is to be written.
192 : *
193 : * @param nBufYSize the height of the buffer image into which the desired region
194 : * is to be read, or from which it is to be written.
195 : *
196 : * @param eBufType the type of the pixel values in the pData data buffer. The
197 : * pixel values will automatically be translated to/from the GDALRasterBand
198 : * data type as needed. Most driver implementations will use GDALCopyWords64()
199 : * to perform data type translation.
200 : *
201 : * @param nPixelSpace The byte offset from the start of one pixel value in
202 : * pData to the start of the next pixel value within a scanline. If defaulted
203 : * (0) the size of the datatype eBufType is used.
204 : *
205 : * @param nLineSpace The byte offset from the start of one scanline in
206 : * pData to the start of the next. If defaulted (0) the size of the datatype
207 : * eBufType * nBufXSize is used.
208 : *
209 : * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
210 : * structure with additional arguments to specify resampling and progress
211 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
212 : * configuration option can also be defined to override the default resampling
213 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
214 : *
215 : * @return CE_Failure if the access fails, otherwise CE_None.
216 : */
217 :
218 : /**
219 : * \brief Read/write a region of image data for this band.
220 : *
221 : * This method allows reading a region of a GDALRasterBand into a buffer,
222 : * or writing data from a buffer into a region of a GDALRasterBand. It
223 : * automatically takes care of data type translation if the data type
224 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
225 : * The method also takes care of image decimation / replication if the
226 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
227 : * region being accessed (nXSize x nYSize).
228 : *
229 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
230 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
231 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
232 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
233 : * Or use nLineSpace and a possibly shifted pData value.
234 : *
235 : * The nPixelSpace and nLineSpace parameters allow reading into or
236 : * writing from unusually organized buffers. This is primarily used
237 : * for buffers containing more than one bands raster data in interleaved
238 : * format.
239 : *
240 : * Some formats may efficiently implement decimation into a buffer by
241 : * reading from lower resolution overview images. The logic of the default
242 : * implementation in the base class GDALRasterBand is the following one. It
243 : * computes a target_downscaling_factor from the window of interest and buffer
244 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
245 : * It then walks through overviews and will select the first one whose
246 : * downscaling factor is greater than target_downscaling_factor / 1.2.
247 : *
248 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
249 : * The relationship between target_downscaling_factor and the select overview
250 : * level is the following one:
251 : *
252 : * target_downscaling_factor | selected_overview
253 : * ------------------------- | -----------------
254 : * ]0, 2 / 1.2] | full resolution band
255 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
256 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
257 : * ]8 / 1.2, infinity[ | 8x downsampled band
258 : *
259 : * For highest performance full resolution data access, read and write
260 : * on "block boundaries" as returned by GetBlockSize(), or use the
261 : * ReadBlock() and WriteBlock() methods.
262 : *
263 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
264 : * functions.
265 : *
266 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
267 : * more convenient to use for most common use cases.
268 : *
269 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
270 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
271 : * instance of this dataset) concurrently from several threads.
272 : *
273 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
274 : * write a region of data.
275 : *
276 : * @param nXOff The pixel offset to the top left corner of the region
277 : * of the band to be accessed. This would be zero to start from the left side.
278 : *
279 : * @param nYOff The line offset to the top left corner of the region
280 : * of the band to be accessed. This would be zero to start from the top.
281 : *
282 : * @param nXSize The width of the region of the band to be accessed in pixels.
283 : *
284 : * @param nYSize The height of the region of the band to be accessed in lines.
285 : *
286 : * @param[in,out] pData The buffer into which the data should be read, or from
287 : * which it should be written. This buffer must contain at least nBufXSize *
288 : * nBufYSize words of type eBufType. It is organized in left to right,
289 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
290 : * and nLineSpace parameters.
291 : *
292 : * @param nBufXSize the width of the buffer image into which the desired region
293 : * is to be read, or from which it is to be written.
294 : *
295 : * @param nBufYSize the height of the buffer image into which the desired region
296 : * is to be read, or from which it is to be written.
297 : *
298 : * @param eBufType the type of the pixel values in the pData data buffer. The
299 : * pixel values will automatically be translated to/from the GDALRasterBand
300 : * data type as needed.
301 : *
302 : * @param nPixelSpace The byte offset from the start of one pixel value in
303 : * pData to the start of the next pixel value within a scanline. If defaulted
304 : * (0) the size of the datatype eBufType is used.
305 : *
306 : * @param nLineSpace The byte offset from the start of one scanline in
307 : * pData to the start of the next. If defaulted (0) the size of the datatype
308 : * eBufType * nBufXSize is used.
309 : *
310 : * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
311 : * structure with additional arguments to specify resampling and progress
312 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
313 : * configuration option can also be defined to override the default resampling
314 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
315 : *
316 : * @return CE_Failure if the access fails, otherwise CE_None.
317 : *
318 : * @see GDALRasterBand::ReadRaster()
319 : */
320 :
321 3729640 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
322 : int nXSize, int nYSize, void *pData,
323 : int nBufXSize, int nBufYSize,
324 : GDALDataType eBufType, GSpacing nPixelSpace,
325 : GSpacing nLineSpace,
326 : GDALRasterIOExtraArg *psExtraArg)
327 :
328 : {
329 : GDALRasterIOExtraArg sExtraArg;
330 3729640 : if (psExtraArg == nullptr)
331 : {
332 3648150 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
333 3648150 : psExtraArg = &sExtraArg;
334 : }
335 81488 : else if (CPL_UNLIKELY(psExtraArg->nVersion !=
336 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
337 : {
338 0 : ReportError(CE_Failure, CPLE_AppDefined,
339 : "Unhandled version of GDALRasterIOExtraArg");
340 0 : return CE_Failure;
341 : }
342 :
343 3729640 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
344 : nBufYSize);
345 :
346 3746040 : if (CPL_UNLIKELY(nullptr == pData))
347 : {
348 0 : ReportError(CE_Failure, CPLE_AppDefined,
349 : "The buffer into which the data should be read is null");
350 0 : return CE_Failure;
351 : }
352 :
353 : /* -------------------------------------------------------------------- */
354 : /* Some size values are "noop". Lets just return to avoid */
355 : /* stressing lower level functions. */
356 : /* -------------------------------------------------------------------- */
357 3746040 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
358 : nBufYSize < 1))
359 : {
360 2 : CPLDebug("GDAL",
361 : "RasterIO() skipped for odd window or buffer size.\n"
362 : " Window = (%d,%d)x%dx%d\n"
363 : " Buffer = %dx%d\n",
364 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
365 :
366 2 : return CE_None;
367 : }
368 :
369 3746040 : if (eRWFlag == GF_Write)
370 : {
371 208975 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
372 : {
373 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
374 : "An error occurred while writing a dirty block "
375 : "from GDALRasterBand::RasterIO");
376 0 : CPLErr eErr = eFlushBlockErr;
377 0 : eFlushBlockErr = CE_None;
378 0 : return eErr;
379 : }
380 208975 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
381 : {
382 7 : return CE_Failure;
383 : }
384 : }
385 :
386 : /* -------------------------------------------------------------------- */
387 : /* If pixel and line spacing are defaulted assign reasonable */
388 : /* value assuming a packed buffer. */
389 : /* -------------------------------------------------------------------- */
390 3747310 : if (nPixelSpace == 0)
391 : {
392 3643770 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
393 : }
394 :
395 3749240 : if (nLineSpace == 0)
396 : {
397 3633190 : nLineSpace = nPixelSpace * nBufXSize;
398 : }
399 :
400 : /* -------------------------------------------------------------------- */
401 : /* Do some validation of parameters. */
402 : /* -------------------------------------------------------------------- */
403 3749240 : if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
404 : nXOff + nXSize > nRasterXSize || nYOff < 0 ||
405 : nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
406 : {
407 14 : ReportError(CE_Failure, CPLE_IllegalArg,
408 : "Access window out of range in RasterIO(). Requested\n"
409 : "(%d,%d) of size %dx%d on raster of %dx%d.",
410 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
411 14 : return CE_Failure;
412 : }
413 :
414 3749230 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
415 : {
416 0 : ReportError(
417 : CE_Failure, CPLE_IllegalArg,
418 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
419 : eRWFlag);
420 0 : return CE_Failure;
421 : }
422 3749230 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
423 : {
424 2 : ReportError(CE_Failure, CPLE_IllegalArg,
425 : "Illegal GDT_Unknown/GDT_TypeCount argument");
426 2 : return CE_Failure;
427 : }
428 :
429 : /* -------------------------------------------------------------------- */
430 : /* Call the format specific function. */
431 : /* -------------------------------------------------------------------- */
432 :
433 3749230 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
434 :
435 : CPLErr eErr;
436 3718100 : if (bForceCachedIO)
437 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
438 : pData, nBufXSize, nBufYSize, eBufType,
439 : nPixelSpace, nLineSpace, psExtraArg);
440 : else
441 : eErr =
442 3730120 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
443 3718080 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
444 :
445 3730150 : if (bCallLeaveReadWrite)
446 219227 : LeaveReadWrite();
447 :
448 3706720 : return eErr;
449 : }
450 :
451 : /************************************************************************/
452 : /* GDALRasterIO() */
453 : /************************************************************************/
454 :
455 : /**
456 : * \brief Read/write a region of image data for this band.
457 : *
458 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
459 : * resolution, progress callback, etc. are needed)
460 : *
461 : * @see GDALRasterBand::RasterIO()
462 : */
463 :
464 3442040 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
465 : int nXOff, int nYOff, int nXSize, int nYSize,
466 : void *pData, int nBufXSize, int nBufYSize,
467 : GDALDataType eBufType, int nPixelSpace,
468 : int nLineSpace)
469 :
470 : {
471 3442040 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
472 :
473 3442040 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
474 :
475 3440220 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
476 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
477 3402070 : nLineSpace, nullptr));
478 : }
479 :
480 : /************************************************************************/
481 : /* GDALRasterIOEx() */
482 : /************************************************************************/
483 :
484 : /**
485 : * \brief Read/write a region of image data for this band.
486 : *
487 : * @see GDALRasterBand::RasterIO()
488 : * @since GDAL 2.0
489 : */
490 :
491 35180 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
492 : int nXOff, int nYOff, int nXSize, int nYSize,
493 : void *pData, int nBufXSize, int nBufYSize,
494 : GDALDataType eBufType, GSpacing nPixelSpace,
495 : GSpacing nLineSpace,
496 : GDALRasterIOExtraArg *psExtraArg)
497 :
498 : {
499 35180 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
500 :
501 35180 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
502 :
503 35180 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
504 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
505 35179 : nLineSpace, psExtraArg));
506 : }
507 :
508 : /************************************************************************/
509 : /* GetGDTFromCppType() */
510 : /************************************************************************/
511 :
512 : namespace
513 : {
514 : template <class T> struct GetGDTFromCppType;
515 :
516 : #define DEFINE_GetGDTFromCppType(T, eDT) \
517 : template <> struct GetGDTFromCppType<T> \
518 : { \
519 : static constexpr GDALDataType GDT = eDT; \
520 : }
521 :
522 : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
523 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
524 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
525 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
526 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
527 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
528 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
529 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
530 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
531 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
532 : // Not allowed by C++ standard
533 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
534 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
535 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
536 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
537 : } // namespace
538 :
539 : /************************************************************************/
540 : /* ReadRaster() */
541 : /************************************************************************/
542 :
543 : // clang-format off
544 : /** Read a region of image data for this band.
545 : *
546 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
547 : * for common use cases, like reading a whole band.
548 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
549 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
550 : * float, double, std::complex<float|double>.
551 : *
552 : * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
553 : * and can allocate memory automatically.
554 : *
555 : * To read a whole band (assuming it fits into memory), as an array of double:
556 : *
557 : \code{.cpp}
558 : double* myArray = static_cast<double*>(
559 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
560 : // TODO: check here that myArray != nullptr
561 : const size_t nArrayEltCount =
562 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
563 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
564 : {
565 : // do something
566 : }
567 : VSIFree(myArray)
568 : \endcode
569 : *
570 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
571 : *
572 : \code{.cpp}
573 : double* myArray = static_cast<double*>(
574 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
575 : // TODO: check here that myArray != nullptr
576 : const size_t nArrayEltCount = 128 * 128;
577 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
578 : {
579 : // do something
580 : }
581 : VSIFree(myArray)
582 : \endcode
583 : *
584 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
585 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
586 : * instance of this dataset) concurrently from several threads.
587 : *
588 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
589 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
590 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
591 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
592 : * Or use nLineSpace and a possibly shifted pData value.
593 : *
594 : * @param[out] pData The buffer into which the data should be written.
595 : * This buffer must contain at least nBufXSize *
596 : * nBufYSize words of type T. It is organized in left to right,
597 : * top to bottom pixel order, and fully packed.
598 : * The type of the buffer does not need to be the one of GetDataType(). The
599 : * method will perform data type translation (with potential rounding, clamping)
600 : * if needed.
601 : *
602 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
603 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
604 : * return in error if it is not. If set to zero, then pData is trusted to be
605 : * large enough.
606 : *
607 : * @param dfXOff The pixel offset to the top left corner of the region
608 : * of the band to be accessed. This would be zero to start from the left side.
609 : * Defaults to 0.
610 : *
611 : * @param dfYOff The line offset to the top left corner of the region
612 : * of the band to be accessed. This would be zero to start from the top.
613 : * Defaults to 0.
614 : *
615 : * @param dfXSize The width of the region of the band to be accessed in pixels.
616 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
617 : * dfXSize is set to the band width.
618 : *
619 : * @param dfYSize The height of the region of the band to be accessed in lines.
620 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
621 : * dfYSize is set to the band height.
622 : *
623 : * @param nBufXSize the width of the buffer image into which the desired region
624 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
625 : * then nBufXSize is initialized with dfXSize.
626 : *
627 : * @param nBufYSize the height of the buffer image into which the desired region
628 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
629 : * then nBufYSize is initialized with dfYSize.
630 : *
631 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
632 : *
633 : * @param pfnProgress Progress function. May be nullptr.
634 : *
635 : * @param pProgressData User data of pfnProgress. May be nullptr.
636 : *
637 : * @return CE_Failure if the access fails, otherwise CE_None.
638 : *
639 : * @see GDALRasterBand::RasterIO()
640 : * @since GDAL 3.10
641 : */
642 : // clang-format on
643 :
644 : template <class T>
645 19 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
646 : double dfXOff, double dfYOff, double dfXSize,
647 : double dfYSize, size_t nBufXSize,
648 : size_t nBufYSize,
649 : GDALRIOResampleAlg eResampleAlg,
650 : GDALProgressFunc pfnProgress,
651 : void *pProgressData) const
652 : {
653 19 : if (((nBufXSize | nBufYSize) >> 31) != 0)
654 : {
655 2 : return CE_Failure;
656 : }
657 :
658 17 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
659 : {
660 15 : dfXSize = nRasterXSize;
661 15 : dfYSize = nRasterYSize;
662 : }
663 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
664 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
665 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
666 2 : dfYOff + dfYSize > INT_MAX)
667 : {
668 0 : return CE_Failure;
669 : }
670 :
671 : GDALRasterIOExtraArg sExtraArg;
672 17 : sExtraArg.nVersion = 1;
673 17 : sExtraArg.eResampleAlg = eResampleAlg;
674 17 : sExtraArg.pfnProgress = pfnProgress;
675 17 : sExtraArg.pProgressData = pProgressData;
676 17 : sExtraArg.bFloatingPointWindowValidity = true;
677 17 : sExtraArg.dfXOff = dfXOff;
678 17 : sExtraArg.dfYOff = dfYOff;
679 17 : sExtraArg.dfXSize = dfXSize;
680 17 : sExtraArg.dfYSize = dfYSize;
681 17 : const int nXOff = static_cast<int>(dfXOff);
682 17 : const int nYOff = static_cast<int>(dfYOff);
683 17 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
684 17 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
685 17 : if (nBufXSize == 0 && nBufYSize == 0)
686 : {
687 16 : if (static_cast<int>(dfXSize) == dfXSize &&
688 16 : static_cast<int>(dfYSize) == dfYSize)
689 : {
690 16 : nBufXSize = static_cast<int>(dfXSize);
691 16 : nBufYSize = static_cast<int>(dfYSize);
692 : }
693 : else
694 : {
695 0 : CPLError(CE_Failure, CPLE_AppDefined,
696 : "nBufXSize and nBufYSize must be provided if dfXSize or "
697 : "dfYSize is not an integer value");
698 0 : return CE_Failure;
699 : }
700 : }
701 17 : if (nBufXSize == 0 || nBufYSize == 0)
702 : {
703 0 : CPLDebug("GDAL",
704 : "RasterIO() skipped for odd window or buffer size.\n"
705 : " Window = (%d,%d)x%dx%d\n"
706 : " Buffer = %dx%d\n",
707 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
708 : static_cast<int>(nBufYSize));
709 :
710 0 : return CE_None;
711 : }
712 :
713 17 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
714 : {
715 1 : CPLError(CE_Failure, CPLE_AppDefined,
716 : "Provided array is not large enough");
717 1 : return CE_Failure;
718 : }
719 :
720 16 : constexpr GSpacing nPixelSpace = sizeof(T);
721 16 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
722 16 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
723 :
724 16 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
725 :
726 : const bool bCallLeaveReadWrite =
727 16 : CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
728 : CPLErr eErr;
729 : // coverity[identical_branches]
730 16 : if (bForceCachedIO)
731 0 : eErr = pThis->GDALRasterBand::IRasterIO(
732 : GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
733 : static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
734 : nPixelSpace, nLineSpace, &sExtraArg);
735 : else
736 16 : eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
737 : static_cast<int>(nBufXSize),
738 : static_cast<int>(nBufYSize), eBufType,
739 : nPixelSpace, nLineSpace, &sExtraArg);
740 :
741 16 : if (bCallLeaveReadWrite)
742 0 : pThis->LeaveReadWrite();
743 :
744 16 : return eErr;
745 : }
746 :
747 : //! @cond Doxygen_Suppress
748 :
749 : #define INSTANTIATE_READ_RASTER(T) \
750 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
751 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
752 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
753 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
754 : void *pProgressData) const;
755 :
756 : INSTANTIATE_READ_RASTER(uint8_t)
757 : INSTANTIATE_READ_RASTER(int8_t)
758 : INSTANTIATE_READ_RASTER(uint16_t)
759 : INSTANTIATE_READ_RASTER(int16_t)
760 : INSTANTIATE_READ_RASTER(uint32_t)
761 : INSTANTIATE_READ_RASTER(int32_t)
762 : INSTANTIATE_READ_RASTER(uint64_t)
763 : INSTANTIATE_READ_RASTER(int64_t)
764 : INSTANTIATE_READ_RASTER(float)
765 : INSTANTIATE_READ_RASTER(double)
766 : // Not allowed by C++ standard
767 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
768 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
769 : INSTANTIATE_READ_RASTER(std::complex<float>)
770 : INSTANTIATE_READ_RASTER(std::complex<double>)
771 :
772 : //! @endcond
773 :
774 : /************************************************************************/
775 : /* ReadRaster() */
776 : /************************************************************************/
777 :
778 : /** Read a region of image data for this band.
779 : *
780 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
781 : * for common use cases, like reading a whole band.
782 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
783 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
784 : * float, double, std::complex<float|double>.
785 : *
786 : * To read a whole band (assuming it fits into memory), as a vector of double:
787 : *
788 : \code
789 : std::vector<double> myArray;
790 : if (poBand->ReadRaster(myArray) == CE_None)
791 : {
792 : // do something
793 : }
794 : \endcode
795 : *
796 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
797 : *
798 : \code{.cpp}
799 : std::vector<double> myArray;
800 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
801 : {
802 : // do something
803 : }
804 : \endcode
805 : *
806 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
807 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
808 : * instance of this dataset) concurrently from several threads.
809 : *
810 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
811 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
812 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
813 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
814 : * Or use nLineSpace and a possibly shifted pData value.
815 : *
816 : * @param[out] vData The vector into which the data should be written.
817 : * The vector will be resized, if needed, to contain at least nBufXSize *
818 : * nBufYSize values. The values in the vector are organized in left to right,
819 : * top to bottom pixel order, and fully packed.
820 : * The type of the vector does not need to be the one of GetDataType(). The
821 : * method will perform data type translation (with potential rounding, clamping)
822 : * if needed.
823 : *
824 : * @param dfXOff The pixel offset to the top left corner of the region
825 : * of the band to be accessed. This would be zero to start from the left side.
826 : * Defaults to 0.
827 : *
828 : * @param dfYOff The line offset to the top left corner of the region
829 : * of the band to be accessed. This would be zero to start from the top.
830 : * Defaults to 0.
831 : *
832 : * @param dfXSize The width of the region of the band to be accessed in pixels.
833 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
834 : * dfXSize is set to the band width.
835 : *
836 : * @param dfYSize The height of the region of the band to be accessed in lines.
837 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
838 : * dfYSize is set to the band height.
839 : *
840 : * @param nBufXSize the width of the buffer image into which the desired region
841 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
842 : * then nBufXSize is initialized with dfXSize.
843 : *
844 : * @param nBufYSize the height of the buffer image into which the desired region
845 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
846 : * then nBufYSize is initialized with dfYSize.
847 : *
848 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
849 : *
850 : * @param pfnProgress Progress function. May be nullptr.
851 : *
852 : * @param pProgressData User data of pfnProgress. May be nullptr.
853 : *
854 : * @return CE_Failure if the access fails, otherwise CE_None.
855 : *
856 : * @see GDALRasterBand::RasterIO()
857 : * @since GDAL 3.10
858 : */
859 : template <class T>
860 21 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
861 : double dfYOff, double dfXSize, double dfYSize,
862 : size_t nBufXSize, size_t nBufYSize,
863 : GDALRIOResampleAlg eResampleAlg,
864 : GDALProgressFunc pfnProgress,
865 : void *pProgressData) const
866 : {
867 21 : if (((nBufXSize | nBufYSize) >> 31) != 0)
868 : {
869 2 : return CE_Failure;
870 : }
871 :
872 19 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
873 : {
874 12 : dfXSize = nRasterXSize;
875 12 : dfYSize = nRasterYSize;
876 : }
877 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
878 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
879 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
880 7 : dfYOff + dfYSize > INT_MAX)
881 : {
882 0 : return CE_Failure;
883 : }
884 :
885 : GDALRasterIOExtraArg sExtraArg;
886 19 : sExtraArg.nVersion = 1;
887 19 : sExtraArg.eResampleAlg = eResampleAlg;
888 19 : sExtraArg.pfnProgress = pfnProgress;
889 19 : sExtraArg.pProgressData = pProgressData;
890 19 : sExtraArg.bFloatingPointWindowValidity = true;
891 19 : sExtraArg.dfXOff = dfXOff;
892 19 : sExtraArg.dfYOff = dfYOff;
893 19 : sExtraArg.dfXSize = dfXSize;
894 19 : sExtraArg.dfYSize = dfYSize;
895 19 : const int nXOff = static_cast<int>(dfXOff);
896 19 : const int nYOff = static_cast<int>(dfYOff);
897 19 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
898 19 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
899 19 : if (nBufXSize == 0 && nBufYSize == 0)
900 : {
901 15 : if (static_cast<int>(dfXSize) == dfXSize &&
902 14 : static_cast<int>(dfYSize) == dfYSize)
903 : {
904 14 : nBufXSize = static_cast<int>(dfXSize);
905 14 : nBufYSize = static_cast<int>(dfYSize);
906 : }
907 : else
908 : {
909 1 : CPLError(CE_Failure, CPLE_AppDefined,
910 : "nBufXSize and nBufYSize must be provided if "
911 : "dfXSize or dfYSize is not an integer value");
912 1 : return CE_Failure;
913 : }
914 : }
915 18 : if (nBufXSize == 0 || nBufYSize == 0)
916 : {
917 0 : CPLDebug("GDAL",
918 : "RasterIO() skipped for odd window or buffer size.\n"
919 : " Window = (%d,%d)x%dx%d\n"
920 : " Buffer = %dx%d\n",
921 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
922 : static_cast<int>(nBufYSize));
923 :
924 0 : return CE_None;
925 : }
926 :
927 : if constexpr (SIZEOF_VOIDP < 8)
928 : {
929 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
930 : {
931 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
932 : return CE_Failure;
933 : }
934 : }
935 :
936 18 : if (vData.size() < nBufXSize * nBufYSize)
937 : {
938 : try
939 : {
940 16 : vData.resize(nBufXSize * nBufYSize);
941 : }
942 1 : catch (const std::exception &)
943 : {
944 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
945 1 : return CE_Failure;
946 : }
947 : }
948 :
949 17 : constexpr GSpacing nPixelSpace = sizeof(T);
950 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
951 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
952 :
953 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
954 :
955 : const bool bCallLeaveReadWrite =
956 17 : CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
957 :
958 : CPLErr eErr;
959 : // coverity[identical_branches]
960 17 : if (bForceCachedIO)
961 0 : eErr = pThis->GDALRasterBand::IRasterIO(
962 : GF_Read, nXOff, nYOff, nXSize, nYSize, vData.data(),
963 : static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
964 : nPixelSpace, nLineSpace, &sExtraArg);
965 : else
966 17 : eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
967 : vData.data(), static_cast<int>(nBufXSize),
968 : static_cast<int>(nBufYSize), eBufType,
969 : nPixelSpace, nLineSpace, &sExtraArg);
970 :
971 17 : if (bCallLeaveReadWrite)
972 0 : pThis->LeaveReadWrite();
973 :
974 17 : return eErr;
975 : }
976 :
977 : //! @cond Doxygen_Suppress
978 :
979 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
980 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
981 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
982 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
983 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
984 : void *pProgressData) const;
985 :
986 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
987 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
988 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
989 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
990 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
991 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
992 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
993 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
994 : INSTANTIATE_READ_RASTER_VECTOR(float)
995 : INSTANTIATE_READ_RASTER_VECTOR(double)
996 : // Not allowed by C++ standard
997 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
998 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
999 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
1000 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
1001 :
1002 : //! @endcond
1003 :
1004 : /************************************************************************/
1005 : /* ReadBlock() */
1006 : /************************************************************************/
1007 :
1008 : /**
1009 : * \brief Read a block of image data efficiently.
1010 : *
1011 : * This method accesses a "natural" block from the raster band without
1012 : * resampling, or data type conversion. For a more generalized, but
1013 : * potentially less efficient access use RasterIO().
1014 : *
1015 : * This method is the same as the C GDALReadBlock() function.
1016 : *
1017 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1018 : * block oriented data without an extra copy into an application buffer.
1019 : *
1020 : * The following code would efficiently compute a histogram of eight bit
1021 : * raster data. Note that the final block may be partial ... data beyond
1022 : * the edge of the underlying raster band in these edge blocks is of an
1023 : * undetermined value.
1024 : *
1025 : \code{.cpp}
1026 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1027 :
1028 : {
1029 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1030 :
1031 : CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1032 :
1033 : int nXBlockSize, nYBlockSize;
1034 :
1035 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1036 : int nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
1037 : int nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
1038 :
1039 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1040 :
1041 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1042 : {
1043 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1044 : {
1045 : int nXValid, nYValid;
1046 :
1047 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1048 :
1049 : // Compute the portion of the block that is valid
1050 : // for partial edge blocks.
1051 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1052 :
1053 : // Collect the histogram counts.
1054 : for( int iY = 0; iY < nYValid; iY++ )
1055 : {
1056 : for( int iX = 0; iX < nXValid; iX++ )
1057 : {
1058 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1059 : }
1060 : }
1061 : }
1062 : }
1063 : }
1064 : \endcode
1065 : *
1066 : * @param nXBlockOff the horizontal block offset, with zero indicating
1067 : * the left most block, 1 the next block and so forth.
1068 : *
1069 : * @param nYBlockOff the vertical block offset, with zero indicating
1070 : * the top most block, 1 the next block and so forth.
1071 : *
1072 : * @param pImage the buffer into which the data will be read. The buffer
1073 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1074 : * of type GetRasterDataType().
1075 : *
1076 : * @return CE_None on success or CE_Failure on an error.
1077 : */
1078 :
1079 644 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1080 :
1081 : {
1082 : /* -------------------------------------------------------------------- */
1083 : /* Validate arguments. */
1084 : /* -------------------------------------------------------------------- */
1085 644 : CPLAssert(pImage != nullptr);
1086 :
1087 644 : if (!InitBlockInfo())
1088 0 : return CE_Failure;
1089 :
1090 644 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1091 : {
1092 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1093 : "Illegal nXBlockOff value (%d) in "
1094 : "GDALRasterBand::ReadBlock()\n",
1095 : nXBlockOff);
1096 :
1097 0 : return (CE_Failure);
1098 : }
1099 :
1100 644 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1101 : {
1102 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1103 : "Illegal nYBlockOff value (%d) in "
1104 : "GDALRasterBand::ReadBlock()\n",
1105 : nYBlockOff);
1106 :
1107 0 : return (CE_Failure);
1108 : }
1109 :
1110 : /* -------------------------------------------------------------------- */
1111 : /* Invoke underlying implementation method. */
1112 : /* -------------------------------------------------------------------- */
1113 :
1114 644 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1115 644 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1116 644 : if (bCallLeaveReadWrite)
1117 4 : LeaveReadWrite();
1118 644 : return eErr;
1119 : }
1120 :
1121 : /************************************************************************/
1122 : /* GDALReadBlock() */
1123 : /************************************************************************/
1124 :
1125 : /**
1126 : * \brief Read a block of image data efficiently.
1127 : *
1128 : * @see GDALRasterBand::ReadBlock()
1129 : */
1130 :
1131 67 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1132 : void *pData)
1133 :
1134 : {
1135 67 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1136 :
1137 67 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1138 67 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1139 : }
1140 :
1141 : /************************************************************************/
1142 : /* IReadBlock() */
1143 : /************************************************************************/
1144 :
1145 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1146 : * ) \brief Read a block of data.
1147 : *
1148 : * Default internal implementation ... to be overridden by
1149 : * subclasses that support reading.
1150 : * @param nBlockXOff Block X Offset
1151 : * @param nBlockYOff Block Y Offset
1152 : * @param pData Pixel buffer into which to place read data.
1153 : * @return CE_None on success or CE_Failure on an error.
1154 : */
1155 :
1156 : /************************************************************************/
1157 : /* IWriteBlock() */
1158 : /************************************************************************/
1159 :
1160 : /**
1161 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1162 : * Write a block of data.
1163 : *
1164 : * Default internal implementation ... to be overridden by
1165 : * subclasses that support writing.
1166 : * @param nBlockXOff Block X Offset
1167 : * @param nBlockYOff Block Y Offset
1168 : * @param pData Pixel buffer to write
1169 : * @return CE_None on success or CE_Failure on an error.
1170 : */
1171 :
1172 : /**/
1173 : /**/
1174 :
1175 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1176 : void * /*pData*/)
1177 :
1178 : {
1179 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1180 0 : ReportError(CE_Failure, CPLE_NotSupported,
1181 : "WriteBlock() not supported for this dataset.");
1182 :
1183 0 : return (CE_Failure);
1184 : }
1185 :
1186 : /************************************************************************/
1187 : /* WriteBlock() */
1188 : /************************************************************************/
1189 :
1190 : /**
1191 : * \brief Write a block of image data efficiently.
1192 : *
1193 : * This method accesses a "natural" block from the raster band without
1194 : * resampling, or data type conversion. For a more generalized, but
1195 : * potentially less efficient access use RasterIO().
1196 : *
1197 : * This method is the same as the C GDALWriteBlock() function.
1198 : *
1199 : * See ReadBlock() for an example of block oriented data access.
1200 : *
1201 : * @param nXBlockOff the horizontal block offset, with zero indicating
1202 : * the left most block, 1 the next block and so forth.
1203 : *
1204 : * @param nYBlockOff the vertical block offset, with zero indicating
1205 : * the left most block, 1 the next block and so forth.
1206 : *
1207 : * @param pImage the buffer from which the data will be written. The buffer
1208 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1209 : * of type GetRasterDataType(). Note that the content of the buffer might be
1210 : * temporarily modified during the execution of this method (and eventually
1211 : * restored back to its original content), so it is not safe to use a buffer
1212 : * stored in a read-only section of the calling program.
1213 : *
1214 : * @return CE_None on success or CE_Failure on an error.
1215 : */
1216 :
1217 4888 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1218 :
1219 : {
1220 : /* -------------------------------------------------------------------- */
1221 : /* Validate arguments. */
1222 : /* -------------------------------------------------------------------- */
1223 4888 : CPLAssert(pImage != nullptr);
1224 :
1225 4888 : if (!InitBlockInfo())
1226 0 : return CE_Failure;
1227 :
1228 4888 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1229 : {
1230 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1231 : "Illegal nXBlockOff value (%d) in "
1232 : "GDALRasterBand::WriteBlock()\n",
1233 : nXBlockOff);
1234 :
1235 0 : return (CE_Failure);
1236 : }
1237 :
1238 4888 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1239 : {
1240 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1241 : "Illegal nYBlockOff value (%d) in "
1242 : "GDALRasterBand::WriteBlock()\n",
1243 : nYBlockOff);
1244 :
1245 0 : return (CE_Failure);
1246 : }
1247 :
1248 4888 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1249 : {
1250 0 : return CE_Failure;
1251 : }
1252 :
1253 4888 : if (eFlushBlockErr != CE_None)
1254 : {
1255 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1256 : "An error occurred while writing a dirty block "
1257 : "from GDALRasterBand::WriteBlock");
1258 0 : CPLErr eErr = eFlushBlockErr;
1259 0 : eFlushBlockErr = CE_None;
1260 0 : return eErr;
1261 : }
1262 :
1263 : /* -------------------------------------------------------------------- */
1264 : /* Invoke underlying implementation method. */
1265 : /* -------------------------------------------------------------------- */
1266 :
1267 4888 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1268 4888 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1269 4888 : if (bCallLeaveReadWrite)
1270 4888 : LeaveReadWrite();
1271 :
1272 4888 : return eErr;
1273 : }
1274 :
1275 : /************************************************************************/
1276 : /* GDALWriteBlock() */
1277 : /************************************************************************/
1278 :
1279 : /**
1280 : * \brief Write a block of image data efficiently.
1281 : *
1282 : * @see GDALRasterBand::WriteBlock()
1283 : */
1284 :
1285 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1286 : void *pData)
1287 :
1288 : {
1289 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1290 :
1291 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1292 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1293 : }
1294 :
1295 : /************************************************************************/
1296 : /* EmitErrorMessageIfWriteNotSupported() */
1297 : /************************************************************************/
1298 :
1299 : /**
1300 : * Emit an error message if a write operation to this band is not supported.
1301 : *
1302 : * The base implementation will emit an error message if the access mode is
1303 : * read-only. Derived classes may implement it to provide a custom message.
1304 : *
1305 : * @param pszCaller Calling function.
1306 : * @return true if an error message has been emitted.
1307 : */
1308 384390 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1309 : const char *pszCaller) const
1310 : {
1311 384390 : if (eAccess == GA_ReadOnly)
1312 : {
1313 4 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1314 : "%s: attempt to write to dataset opened in read-only mode.",
1315 : pszCaller);
1316 :
1317 4 : return true;
1318 : }
1319 384386 : return false;
1320 : }
1321 :
1322 : /************************************************************************/
1323 : /* GetActualBlockSize() */
1324 : /************************************************************************/
1325 : /**
1326 : * \brief Fetch the actual block size for a given block offset.
1327 : *
1328 : * Handles partial blocks at the edges of the raster and returns the true
1329 : * number of pixels
1330 : *
1331 : * @param nXBlockOff the horizontal block offset for which to calculate the
1332 : * number of valid pixels, with zero indicating the left most block, 1 the next
1333 : * block and so forth.
1334 : *
1335 : * @param nYBlockOff the vertical block offset, with zero indicating
1336 : * the top most block, 1 the next block and so forth.
1337 : *
1338 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1339 : * the x direction will be stored
1340 : *
1341 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1342 : * the y direction will be stored
1343 : *
1344 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1345 : *
1346 : * @since GDAL 2.2
1347 : */
1348 47144 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1349 : int *pnXValid, int *pnYValid) const
1350 : {
1351 94281 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1352 94274 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1353 94271 : nYBlockOff < 0 || nBlockYSize == 0 ||
1354 47135 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1355 : {
1356 11 : return CE_Failure;
1357 : }
1358 :
1359 47133 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1360 47133 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1361 :
1362 47133 : *pnXValid = nBlockXSize;
1363 47133 : *pnYValid = nBlockYSize;
1364 :
1365 47133 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1366 : {
1367 45747 : *pnXValid = nRasterXSize - nXPixelOff;
1368 : }
1369 :
1370 47133 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1371 : {
1372 3258 : *pnYValid = nRasterYSize - nYPixelOff;
1373 : }
1374 :
1375 47133 : return CE_None;
1376 : }
1377 :
1378 : /************************************************************************/
1379 : /* GDALGetActualBlockSize() */
1380 : /************************************************************************/
1381 :
1382 : /**
1383 : * \brief Retrieve the actual block size for a given block offset.
1384 : *
1385 : * @see GDALRasterBand::GetActualBlockSize()
1386 : */
1387 :
1388 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1389 : int nYBlockOff, int *pnXValid,
1390 : int *pnYValid)
1391 :
1392 : {
1393 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1394 :
1395 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1396 : return (
1397 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1398 : }
1399 :
1400 : /************************************************************************/
1401 : /* GetSuggestedBlockAccessPattern() */
1402 : /************************************************************************/
1403 :
1404 : /**
1405 : * \brief Return the suggested/most efficient access pattern to blocks
1406 : * (for read operations).
1407 : *
1408 : * While all GDAL drivers have to expose a block size, not all can guarantee
1409 : * efficient random access (GSBAP_RANDOM) to any block.
1410 : * Some drivers for example decompress sequentially a compressed stream from
1411 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1412 : * case best performance will be achieved while reading blocks in that order.
1413 : * (accessing blocks in random access in such rasters typically causes the
1414 : * decoding to be re-initialized from the start if accessing blocks in
1415 : * a non-sequential order)
1416 : *
1417 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1418 : * returned by drivers that expose a somewhat artificial block size, because
1419 : * they can extract any part of a raster, but in a rather inefficient way.
1420 : *
1421 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1422 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1423 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1424 : * most efficient strategy is to read as many pixels as possible in the less
1425 : * RasterIO() operations.
1426 : *
1427 : * The return of this method is for example used to determine the swath size
1428 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1429 : *
1430 : * @since GDAL 3.6
1431 : */
1432 :
1433 : GDALSuggestedBlockAccessPattern
1434 2159 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1435 : {
1436 2159 : return GSBAP_UNKNOWN;
1437 : }
1438 :
1439 : /************************************************************************/
1440 : /* GetRasterDataType() */
1441 : /************************************************************************/
1442 :
1443 : /**
1444 : * \brief Fetch the pixel data type for this band.
1445 : *
1446 : * This method is the same as the C function GDALGetRasterDataType().
1447 : *
1448 : * @return the data type of pixels for this band.
1449 : */
1450 :
1451 7549330 : GDALDataType GDALRasterBand::GetRasterDataType() const
1452 :
1453 : {
1454 7549330 : return eDataType;
1455 : }
1456 :
1457 : /************************************************************************/
1458 : /* GDALGetRasterDataType() */
1459 : /************************************************************************/
1460 :
1461 : /**
1462 : * \brief Fetch the pixel data type for this band.
1463 : *
1464 : * @see GDALRasterBand::GetRasterDataType()
1465 : */
1466 :
1467 899571 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1468 :
1469 : {
1470 899571 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1471 :
1472 899571 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1473 899571 : return poBand->GetRasterDataType();
1474 : }
1475 :
1476 : /************************************************************************/
1477 : /* GetBlockSize() */
1478 : /************************************************************************/
1479 :
1480 : /**
1481 : * \brief Fetch the "natural" block size of this band.
1482 : *
1483 : * GDAL contains a concept of the natural block size of rasters so that
1484 : * applications can organized data access efficiently for some file formats.
1485 : * The natural block size is the block size that is most efficient for
1486 : * accessing the format. For many formats this is simple a whole scanline
1487 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1488 : *
1489 : * However, for tiled images this will typically be the tile size.
1490 : *
1491 : * Note that the X and Y block sizes don't have to divide the image size
1492 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1493 : * See ReadBlock() for an example of code dealing with these issues.
1494 : *
1495 : * This method is the same as the C function GDALGetBlockSize().
1496 : *
1497 : * @param pnXSize integer to put the X block size into or NULL.
1498 : *
1499 : * @param pnYSize integer to put the Y block size into or NULL.
1500 : */
1501 :
1502 4972260 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1503 :
1504 : {
1505 4972260 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1506 : {
1507 53815 : ReportError(CE_Failure, CPLE_AppDefined,
1508 53815 : "Invalid block dimension : %d * %d", nBlockXSize,
1509 53815 : nBlockYSize);
1510 0 : if (pnXSize != nullptr)
1511 0 : *pnXSize = 0;
1512 0 : if (pnYSize != nullptr)
1513 0 : *pnYSize = 0;
1514 : }
1515 : else
1516 : {
1517 4918450 : if (pnXSize != nullptr)
1518 4920510 : *pnXSize = nBlockXSize;
1519 4918450 : if (pnYSize != nullptr)
1520 4914830 : *pnYSize = nBlockYSize;
1521 : }
1522 4918450 : }
1523 :
1524 : /************************************************************************/
1525 : /* GDALGetBlockSize() */
1526 : /************************************************************************/
1527 :
1528 : /**
1529 : * \brief Fetch the "natural" block size of this band.
1530 : *
1531 : * @see GDALRasterBand::GetBlockSize()
1532 : */
1533 :
1534 40539 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1535 : int *pnYSize)
1536 :
1537 : {
1538 40539 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1539 :
1540 40539 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1541 40539 : poBand->GetBlockSize(pnXSize, pnYSize);
1542 : }
1543 :
1544 : /************************************************************************/
1545 : /* InitBlockInfo() */
1546 : /************************************************************************/
1547 :
1548 : //! @cond Doxygen_Suppress
1549 3315890 : int GDALRasterBand::InitBlockInfo()
1550 :
1551 : {
1552 3315890 : if (poBandBlockCache != nullptr)
1553 3282060 : return poBandBlockCache->IsInitOK();
1554 :
1555 : /* Do some validation of raster and block dimensions in case the driver */
1556 : /* would have neglected to do it itself */
1557 33833 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1558 : {
1559 14 : ReportError(CE_Failure, CPLE_AppDefined,
1560 : "Invalid block dimension : %d * %d", nBlockXSize,
1561 : nBlockYSize);
1562 0 : return FALSE;
1563 : }
1564 :
1565 33819 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1566 : {
1567 16 : ReportError(CE_Failure, CPLE_AppDefined,
1568 : "Invalid raster dimension : %d * %d", nRasterXSize,
1569 : nRasterYSize);
1570 0 : return FALSE;
1571 : }
1572 :
1573 33803 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1574 33810 : if (nDataTypeSize == 0)
1575 : {
1576 1 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1577 0 : return FALSE;
1578 : }
1579 :
1580 : #if SIZEOF_VOIDP == 4
1581 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1582 : {
1583 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1584 : * multiplication in other cases */
1585 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1586 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1587 : {
1588 : ReportError(CE_Failure, CPLE_NotSupported,
1589 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1590 : nBlockYSize);
1591 : return FALSE;
1592 : }
1593 : }
1594 : #endif
1595 :
1596 33809 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1597 33809 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1598 :
1599 : const char *pszBlockStrategy =
1600 33809 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1601 33827 : bool bUseArray = true;
1602 33827 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1603 : {
1604 33787 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1605 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1606 : {
1607 33768 : GUIntBig nBlockCount =
1608 33768 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1609 33768 : if (poDS != nullptr)
1610 33580 : nBlockCount *= poDS->GetRasterCount();
1611 33768 : bUseArray = (nBlockCount < 1024 * 1024);
1612 : }
1613 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1614 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1615 : {
1616 0 : bUseArray = false;
1617 33787 : }
1618 : }
1619 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1620 40 : bUseArray = false;
1621 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1622 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1623 : pszBlockStrategy);
1624 :
1625 33826 : if (bUseArray)
1626 33756 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1627 : else
1628 : {
1629 70 : if (nBand == 1)
1630 25 : CPLDebug("GDAL", "Use hashset band block cache");
1631 70 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1632 : }
1633 33820 : if (poBandBlockCache == nullptr)
1634 0 : return FALSE;
1635 33820 : return poBandBlockCache->Init();
1636 : }
1637 :
1638 : //! @endcond
1639 :
1640 : /************************************************************************/
1641 : /* FlushCache() */
1642 : /************************************************************************/
1643 :
1644 : /**
1645 : * \brief Flush raster data cache.
1646 : *
1647 : * This call will recover memory used to cache data blocks for this raster
1648 : * band, and ensure that new requests are referred to the underlying driver.
1649 : *
1650 : * This method is the same as the C function GDALFlushRasterCache().
1651 : *
1652 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1653 : * @return CE_None on success.
1654 : */
1655 :
1656 3856210 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1657 :
1658 : {
1659 3900960 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1660 44749 : poBandBlockCache)
1661 2165 : poBandBlockCache->DisableDirtyBlockWriting();
1662 :
1663 3838220 : CPLErr eGlobalErr = eFlushBlockErr;
1664 :
1665 3838220 : if (eFlushBlockErr != CE_None)
1666 : {
1667 0 : ReportError(
1668 : eFlushBlockErr, CPLE_AppDefined,
1669 : "An error occurred while writing a dirty block from FlushCache");
1670 0 : eFlushBlockErr = CE_None;
1671 : }
1672 :
1673 3838220 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1674 3633290 : return eGlobalErr;
1675 :
1676 204934 : return poBandBlockCache->FlushCache();
1677 : }
1678 :
1679 : /************************************************************************/
1680 : /* GDALFlushRasterCache() */
1681 : /************************************************************************/
1682 :
1683 : /**
1684 : * \brief Flush raster data cache.
1685 : *
1686 : * @see GDALRasterBand::FlushCache()
1687 : */
1688 :
1689 130 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1690 :
1691 : {
1692 130 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1693 :
1694 130 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1695 : }
1696 :
1697 : /************************************************************************/
1698 : /* DropCache() */
1699 : /************************************************************************/
1700 :
1701 : /**
1702 : * \brief Drop raster data cache : data in cache will be lost.
1703 : *
1704 : * This call will recover memory used to cache data blocks for this raster
1705 : * band, and ensure that new requests are referred to the underlying driver.
1706 : *
1707 : * This method is the same as the C function GDALDropRasterCache().
1708 : *
1709 : * @return CE_None on success.
1710 : * @since 3.9
1711 : */
1712 :
1713 1 : CPLErr GDALRasterBand::DropCache()
1714 :
1715 : {
1716 1 : CPLErr result = CE_None;
1717 :
1718 1 : if (poBandBlockCache)
1719 1 : poBandBlockCache->DisableDirtyBlockWriting();
1720 :
1721 1 : CPLErr eGlobalErr = eFlushBlockErr;
1722 :
1723 1 : if (eFlushBlockErr != CE_None)
1724 : {
1725 0 : ReportError(
1726 : eFlushBlockErr, CPLE_AppDefined,
1727 : "An error occurred while writing a dirty block from DropCache");
1728 0 : eFlushBlockErr = CE_None;
1729 : }
1730 :
1731 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1732 0 : result = eGlobalErr;
1733 : else
1734 1 : result = poBandBlockCache->FlushCache();
1735 :
1736 1 : if (poBandBlockCache)
1737 1 : poBandBlockCache->EnableDirtyBlockWriting();
1738 :
1739 1 : return result;
1740 : }
1741 :
1742 : /************************************************************************/
1743 : /* GDALDropRasterCache() */
1744 : /************************************************************************/
1745 :
1746 : /**
1747 : * \brief Drop raster data cache.
1748 : *
1749 : * @see GDALRasterBand::DropCache()
1750 : * @since 3.9
1751 : */
1752 :
1753 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1754 :
1755 : {
1756 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1757 :
1758 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1759 : }
1760 :
1761 : /************************************************************************/
1762 : /* UnreferenceBlock() */
1763 : /* */
1764 : /* Unreference the block from our array of blocks */
1765 : /* This method should only be called by */
1766 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1767 : /* the block cache mutex) */
1768 : /************************************************************************/
1769 :
1770 29622 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1771 : {
1772 : #ifdef notdef
1773 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1774 : {
1775 : if (poBandBlockCache == nullptr)
1776 : printf("poBandBlockCache == NULL\n"); /*ok*/
1777 : else
1778 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1779 : printf("caller = %s\n", pszCaller); /*ok*/
1780 : printf("GDALRasterBand: %p\n", this); /*ok*/
1781 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1782 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1783 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1784 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1785 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1786 : poBlock->DumpBlock();
1787 : if (GetDataset() != nullptr)
1788 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1789 : GDALRasterBlock::Verify();
1790 : abort();
1791 : }
1792 : #endif
1793 29622 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1794 29622 : return poBandBlockCache->UnreferenceBlock(poBlock);
1795 : }
1796 :
1797 : /************************************************************************/
1798 : /* AddBlockToFreeList() */
1799 : /* */
1800 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1801 : /* finished with a block about to be free'd, they pass it to that */
1802 : /* method. */
1803 : /************************************************************************/
1804 :
1805 : //! @cond Doxygen_Suppress
1806 29619 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1807 : {
1808 29619 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1809 29618 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1810 : }
1811 :
1812 : //! @endcond
1813 :
1814 : /************************************************************************/
1815 : /* FlushBlock() */
1816 : /************************************************************************/
1817 :
1818 : /** Flush a block out of the block cache.
1819 : * @param nXBlockOff block x offset
1820 : * @param nYBlockOff blocky offset
1821 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1822 : * @return CE_None in case of success, an error code otherwise.
1823 : */
1824 2294 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1825 : int bWriteDirtyBlock)
1826 :
1827 : {
1828 2294 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1829 0 : return (CE_Failure);
1830 :
1831 : /* -------------------------------------------------------------------- */
1832 : /* Validate the request */
1833 : /* -------------------------------------------------------------------- */
1834 2294 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1835 : {
1836 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1837 : "Illegal nBlockXOff value (%d) in "
1838 : "GDALRasterBand::FlushBlock()\n",
1839 : nXBlockOff);
1840 :
1841 0 : return (CE_Failure);
1842 : }
1843 :
1844 2294 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1845 : {
1846 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1847 : "Illegal nBlockYOff value (%d) in "
1848 : "GDALRasterBand::FlushBlock()\n",
1849 : nYBlockOff);
1850 :
1851 0 : return (CE_Failure);
1852 : }
1853 :
1854 2294 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1855 2294 : bWriteDirtyBlock);
1856 : }
1857 :
1858 : /************************************************************************/
1859 : /* TryGetLockedBlockRef() */
1860 : /************************************************************************/
1861 :
1862 : /**
1863 : * \brief Try fetching block ref.
1864 : *
1865 : * This method will returned the requested block (locked) if it is already
1866 : * in the block cache for the layer. If not, nullptr is returned.
1867 : *
1868 : * If a non-NULL value is returned, then a lock for the block will have been
1869 : * acquired on behalf of the caller. It is absolutely imperative that the
1870 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1871 : * severe problems may result.
1872 : *
1873 : * @param nXBlockOff the horizontal block offset, with zero indicating
1874 : * the left most block, 1 the next block and so forth.
1875 : *
1876 : * @param nYBlockOff the vertical block offset, with zero indicating
1877 : * the top most block, 1 the next block and so forth.
1878 : *
1879 : * @return NULL if block not available, or locked block pointer.
1880 : */
1881 :
1882 9932740 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1883 : int nYBlockOff)
1884 :
1885 : {
1886 9932740 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1887 66189 : return nullptr;
1888 :
1889 : /* -------------------------------------------------------------------- */
1890 : /* Validate the request */
1891 : /* -------------------------------------------------------------------- */
1892 9866570 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1893 : {
1894 3482 : ReportError(CE_Failure, CPLE_IllegalArg,
1895 : "Illegal nBlockXOff value (%d) in "
1896 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1897 : nXBlockOff);
1898 :
1899 0 : return (nullptr);
1900 : }
1901 :
1902 9863090 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1903 : {
1904 896 : ReportError(CE_Failure, CPLE_IllegalArg,
1905 : "Illegal nBlockYOff value (%d) in "
1906 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1907 : nYBlockOff);
1908 :
1909 0 : return (nullptr);
1910 : }
1911 :
1912 9862190 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1913 : }
1914 :
1915 : /************************************************************************/
1916 : /* GetLockedBlockRef() */
1917 : /************************************************************************/
1918 :
1919 : /**
1920 : * \brief Fetch a pointer to an internally cached raster block.
1921 : *
1922 : * This method will returned the requested block (locked) if it is already
1923 : * in the block cache for the layer. If not, the block will be read from
1924 : * the driver, and placed in the layer block cached, then returned. If an
1925 : * error occurs reading the block from the driver, a NULL value will be
1926 : * returned.
1927 : *
1928 : * If a non-NULL value is returned, then a lock for the block will have been
1929 : * acquired on behalf of the caller. It is absolutely imperative that the
1930 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1931 : * severe problems may result.
1932 : *
1933 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1934 : * enable caching.
1935 : *
1936 : * @param nXBlockOff the horizontal block offset, with zero indicating
1937 : * the left most block, 1 the next block and so forth.
1938 : *
1939 : * @param nYBlockOff the vertical block offset, with zero indicating
1940 : * the top most block, 1 the next block and so forth.
1941 : *
1942 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1943 : * but not actually read from the source. This is useful when it will just
1944 : * be completely set and written back.
1945 : *
1946 : * @return pointer to the block object, or NULL on failure.
1947 : */
1948 :
1949 9732560 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1950 : int nYBlockOff,
1951 : int bJustInitialize)
1952 :
1953 : {
1954 : /* -------------------------------------------------------------------- */
1955 : /* Try and fetch from cache. */
1956 : /* -------------------------------------------------------------------- */
1957 9732560 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1958 :
1959 : /* -------------------------------------------------------------------- */
1960 : /* If we didn't find it in our memory cache, instantiate a */
1961 : /* block (potentially load from disk) and "adopt" it into the */
1962 : /* cache. */
1963 : /* -------------------------------------------------------------------- */
1964 9733680 : if (poBlock == nullptr)
1965 : {
1966 3139040 : if (!InitBlockInfo())
1967 0 : return (nullptr);
1968 :
1969 : /* --------------------------------------------------------------------
1970 : */
1971 : /* Validate the request */
1972 : /* --------------------------------------------------------------------
1973 : */
1974 3139040 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1975 : {
1976 34 : ReportError(CE_Failure, CPLE_IllegalArg,
1977 : "Illegal nBlockXOff value (%d) in "
1978 : "GDALRasterBand::GetLockedBlockRef()\n",
1979 : nXBlockOff);
1980 :
1981 0 : return (nullptr);
1982 : }
1983 :
1984 3139010 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1985 : {
1986 7 : ReportError(CE_Failure, CPLE_IllegalArg,
1987 : "Illegal nBlockYOff value (%d) in "
1988 : "GDALRasterBand::GetLockedBlockRef()\n",
1989 : nYBlockOff);
1990 :
1991 0 : return (nullptr);
1992 : }
1993 :
1994 3139000 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1995 3139000 : if (poBlock == nullptr)
1996 0 : return nullptr;
1997 :
1998 3139000 : poBlock->AddLock();
1999 :
2000 : /* We need to temporarily drop the read-write lock in the following */
2001 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
2002 : */
2003 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
2004 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
2005 : */
2006 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
2007 : */
2008 : /* called and attempt at taking the lock on T2 (already taken).
2009 : * Similarly */
2010 : /* for T2 with D1, hence a deadlock situation (#6163) */
2011 : /* But this may open the door to other problems... */
2012 3139030 : if (poDS)
2013 3138300 : poDS->TemporarilyDropReadWriteLock();
2014 : /* allocate data space */
2015 3139060 : CPLErr eErr = poBlock->Internalize();
2016 3139090 : if (poDS)
2017 3138360 : poDS->ReacquireReadWriteLock();
2018 3139080 : if (eErr != CE_None)
2019 : {
2020 0 : poBlock->DropLock();
2021 0 : delete poBlock;
2022 0 : return nullptr;
2023 : }
2024 :
2025 3139080 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2026 : {
2027 0 : poBlock->DropLock();
2028 0 : delete poBlock;
2029 0 : return nullptr;
2030 : }
2031 :
2032 3139060 : if (!bJustInitialize)
2033 : {
2034 2792180 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2035 2792150 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2036 2792180 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2037 2792200 : if (bCallLeaveReadWrite)
2038 129137 : LeaveReadWrite();
2039 2792190 : if (eErr != CE_None)
2040 : {
2041 1144 : poBlock->DropLock();
2042 1144 : FlushBlock(nXBlockOff, nYBlockOff);
2043 1144 : ReportError(CE_Failure, CPLE_AppDefined,
2044 : "IReadBlock failed at X offset %d, Y offset %d%s",
2045 : nXBlockOff, nYBlockOff,
2046 1144 : (nErrorCounter != CPLGetErrorCounter())
2047 1142 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2048 : : "");
2049 1144 : return nullptr;
2050 : }
2051 :
2052 2791050 : nBlockReads++;
2053 2791050 : if (static_cast<GIntBig>(nBlockReads) ==
2054 2791050 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2055 214 : 1 &&
2056 214 : nBand == 1 && poDS != nullptr)
2057 : {
2058 151 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2059 151 : poDS->GetDescription());
2060 : }
2061 : }
2062 : }
2063 :
2064 9732550 : return poBlock;
2065 : }
2066 :
2067 : /************************************************************************/
2068 : /* Fill() */
2069 : /************************************************************************/
2070 :
2071 : /**
2072 : * \brief Fill this band with a constant value.
2073 : *
2074 : * GDAL makes no guarantees
2075 : * about what values pixels in newly created files are set to, so this
2076 : * method can be used to clear a band to a specified "default" value.
2077 : * The fill value is passed in as a double but this will be converted
2078 : * to the underlying type before writing to the file. An optional
2079 : * second argument allows the imaginary component of a complex
2080 : * constant value to be specified.
2081 : *
2082 : * This method is the same as the C function GDALFillRaster().
2083 : *
2084 : * @param dfRealValue Real component of fill value
2085 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2086 : *
2087 : * @return CE_Failure if the write fails, otherwise CE_None
2088 : */
2089 169277 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2090 : {
2091 :
2092 : // General approach is to construct a source block of the file's
2093 : // native type containing the appropriate value and then copy this
2094 : // to each block in the image via the RasterBlock cache. Using
2095 : // the cache means we avoid file I/O if it is not necessary, at the
2096 : // expense of some extra memcpy's (since we write to the
2097 : // RasterBlock cache, which is then at some point written to the
2098 : // underlying file, rather than simply directly to the underlying
2099 : // file.)
2100 :
2101 : // Check we can write to the file.
2102 169277 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2103 : {
2104 6 : return CE_Failure;
2105 : }
2106 :
2107 : // Make sure block parameters are set.
2108 169271 : if (!InitBlockInfo())
2109 0 : return CE_Failure;
2110 :
2111 : // Allocate the source block.
2112 169271 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2113 169271 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2114 169271 : auto blockByteSize = blockSize * elementSize;
2115 : unsigned char *srcBlock =
2116 169271 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2117 169271 : if (srcBlock == nullptr)
2118 : {
2119 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2120 : "GDALRasterBand::Fill(): Out of memory "
2121 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2122 : static_cast<GUIntBig>(blockByteSize));
2123 0 : return CE_Failure;
2124 : }
2125 :
2126 : // Initialize the source block.
2127 169271 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2128 169271 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2129 : elementSize, blockSize);
2130 :
2131 169271 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2132 :
2133 : // Write block to block cache
2134 646268 : for (int j = 0; j < nBlocksPerColumn; ++j)
2135 : {
2136 1248330 : for (int i = 0; i < nBlocksPerRow; ++i)
2137 : {
2138 771330 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2139 771330 : if (destBlock == nullptr)
2140 : {
2141 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2142 : "GDALRasterBand::Fill(): Error "
2143 : "while retrieving cache block.");
2144 0 : VSIFree(srcBlock);
2145 0 : return CE_Failure;
2146 : }
2147 771330 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2148 771330 : destBlock->MarkDirty();
2149 771330 : destBlock->DropLock();
2150 : }
2151 : }
2152 :
2153 169271 : if (bCallLeaveReadWrite)
2154 168763 : LeaveReadWrite();
2155 :
2156 : // Free up the source block
2157 169271 : VSIFree(srcBlock);
2158 :
2159 169271 : return CE_None;
2160 : }
2161 :
2162 : /************************************************************************/
2163 : /* GDALFillRaster() */
2164 : /************************************************************************/
2165 :
2166 : /**
2167 : * \brief Fill this band with a constant value.
2168 : *
2169 : * @see GDALRasterBand::Fill()
2170 : */
2171 169243 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2172 : double dfImaginaryValue)
2173 : {
2174 169243 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2175 :
2176 169243 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2177 169243 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2178 : }
2179 :
2180 : /************************************************************************/
2181 : /* GetAccess() */
2182 : /************************************************************************/
2183 :
2184 : /**
2185 : * \brief Find out if we have update permission for this band.
2186 : *
2187 : * This method is the same as the C function GDALGetRasterAccess().
2188 : *
2189 : * @return Either GA_Update or GA_ReadOnly.
2190 : */
2191 :
2192 2517 : GDALAccess GDALRasterBand::GetAccess()
2193 :
2194 : {
2195 2517 : return eAccess;
2196 : }
2197 :
2198 : /************************************************************************/
2199 : /* GDALGetRasterAccess() */
2200 : /************************************************************************/
2201 :
2202 : /**
2203 : * \brief Find out if we have update permission for this band.
2204 : *
2205 : * @see GDALRasterBand::GetAccess()
2206 : */
2207 :
2208 1871 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2209 :
2210 : {
2211 1871 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2212 :
2213 1871 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2214 1871 : return poBand->GetAccess();
2215 : }
2216 :
2217 : /************************************************************************/
2218 : /* GetCategoryNames() */
2219 : /************************************************************************/
2220 :
2221 : /**
2222 : * \brief Fetch the list of category names for this raster.
2223 : *
2224 : * The return list is a "StringList" in the sense of the CPL functions.
2225 : * That is a NULL terminated array of strings. Raster values without
2226 : * associated names will have an empty string in the returned list. The
2227 : * first entry in the list is for raster values of zero, and so on.
2228 : *
2229 : * The returned stringlist should not be altered or freed by the application.
2230 : * It may change on the next GDAL call, so please copy it if it is needed
2231 : * for any period of time.
2232 : *
2233 : * This method is the same as the C function GDALGetRasterCategoryNames().
2234 : *
2235 : * @return list of names, or NULL if none.
2236 : */
2237 :
2238 225 : char **GDALRasterBand::GetCategoryNames()
2239 :
2240 : {
2241 225 : return nullptr;
2242 : }
2243 :
2244 : /************************************************************************/
2245 : /* GDALGetRasterCategoryNames() */
2246 : /************************************************************************/
2247 :
2248 : /**
2249 : * \brief Fetch the list of category names for this raster.
2250 : *
2251 : * @see GDALRasterBand::GetCategoryNames()
2252 : */
2253 :
2254 175 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2255 :
2256 : {
2257 175 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2258 :
2259 175 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2260 175 : return poBand->GetCategoryNames();
2261 : }
2262 :
2263 : /************************************************************************/
2264 : /* SetCategoryNames() */
2265 : /************************************************************************/
2266 :
2267 : /**
2268 : * \fn GDALRasterBand::SetCategoryNames(char**)
2269 : * \brief Set the category names for this band.
2270 : *
2271 : * See the GetCategoryNames() method for more on the interpretation of
2272 : * category names.
2273 : *
2274 : * This method is the same as the C function GDALSetRasterCategoryNames().
2275 : *
2276 : * @param papszNames the NULL terminated StringList of category names. May
2277 : * be NULL to just clear the existing list.
2278 : *
2279 : * @return CE_None on success of CE_Failure on failure. If unsupported
2280 : * by the driver CE_Failure is returned, but no error message is reported.
2281 : */
2282 :
2283 : /**/
2284 : /**/
2285 :
2286 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2287 : {
2288 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2289 0 : ReportError(CE_Failure, CPLE_NotSupported,
2290 : "SetCategoryNames() not supported for this dataset.");
2291 :
2292 0 : return CE_Failure;
2293 : }
2294 :
2295 : /************************************************************************/
2296 : /* GDALSetCategoryNames() */
2297 : /************************************************************************/
2298 :
2299 : /**
2300 : * \brief Set the category names for this band.
2301 : *
2302 : * @see GDALRasterBand::SetCategoryNames()
2303 : */
2304 :
2305 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2306 : CSLConstList papszNames)
2307 :
2308 : {
2309 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2310 :
2311 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2312 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2313 : }
2314 :
2315 : /************************************************************************/
2316 : /* GetNoDataValue() */
2317 : /************************************************************************/
2318 :
2319 : /**
2320 : * \brief Fetch the no data value for this band.
2321 : *
2322 : * If there is no out of data value, an out of range value will generally
2323 : * be returned. The no data value for a band is generally a special marker
2324 : * value used to mark pixels that are not valid data. Such pixels should
2325 : * generally not be displayed, nor contribute to analysis operations.
2326 : *
2327 : * The no data value returned is 'raw', meaning that it has no offset and
2328 : * scale applied.
2329 : *
2330 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2331 : * lossy if the nodata value cannot exactly been represented by a double.
2332 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2333 : *
2334 : * This method is the same as the C function GDALGetRasterNoDataValue().
2335 : *
2336 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2337 : * is actually associated with this layer. May be NULL (default).
2338 : *
2339 : * @return the nodata value for this band.
2340 : */
2341 :
2342 31413 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2343 :
2344 : {
2345 31413 : if (pbSuccess != nullptr)
2346 31413 : *pbSuccess = FALSE;
2347 :
2348 31413 : return -1e10;
2349 : }
2350 :
2351 : /************************************************************************/
2352 : /* GDALGetRasterNoDataValue() */
2353 : /************************************************************************/
2354 :
2355 : /**
2356 : * \brief Fetch the no data value for this band.
2357 : *
2358 : * @see GDALRasterBand::GetNoDataValue()
2359 : */
2360 :
2361 413842 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2362 : int *pbSuccess)
2363 :
2364 : {
2365 413842 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2366 :
2367 413842 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2368 413842 : return poBand->GetNoDataValue(pbSuccess);
2369 : }
2370 :
2371 : /************************************************************************/
2372 : /* GetNoDataValueAsInt64() */
2373 : /************************************************************************/
2374 :
2375 : /**
2376 : * \brief Fetch the no data value for this band.
2377 : *
2378 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2379 : *
2380 : * If there is no out of data value, an out of range value will generally
2381 : * be returned. The no data value for a band is generally a special marker
2382 : * value used to mark pixels that are not valid data. Such pixels should
2383 : * generally not be displayed, nor contribute to analysis operations.
2384 : *
2385 : * The no data value returned is 'raw', meaning that it has no offset and
2386 : * scale applied.
2387 : *
2388 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2389 : *
2390 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2391 : * is actually associated with this layer. May be NULL (default).
2392 : *
2393 : * @return the nodata value for this band.
2394 : *
2395 : * @since GDAL 3.5
2396 : */
2397 :
2398 4 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2399 :
2400 : {
2401 4 : if (pbSuccess != nullptr)
2402 4 : *pbSuccess = FALSE;
2403 :
2404 4 : return std::numeric_limits<int64_t>::min();
2405 : }
2406 :
2407 : /************************************************************************/
2408 : /* GDALGetRasterNoDataValueAsInt64() */
2409 : /************************************************************************/
2410 :
2411 : /**
2412 : * \brief Fetch the no data value for this band.
2413 : *
2414 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2415 : *
2416 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2417 : *
2418 : * @since GDAL 3.5
2419 : */
2420 :
2421 23 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2422 : int *pbSuccess)
2423 :
2424 : {
2425 23 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2426 : std::numeric_limits<int64_t>::min());
2427 :
2428 23 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2429 23 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2430 : }
2431 :
2432 : /************************************************************************/
2433 : /* GetNoDataValueAsUInt64() */
2434 : /************************************************************************/
2435 :
2436 : /**
2437 : * \brief Fetch the no data value for this band.
2438 : *
2439 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2440 : *
2441 : * If there is no out of data value, an out of range value will generally
2442 : * be returned. The no data value for a band is generally a special marker
2443 : * value used to mark pixels that are not valid data. Such pixels should
2444 : * generally not be displayed, nor contribute to analysis operations.
2445 : *
2446 : * The no data value returned is 'raw', meaning that it has no offset and
2447 : * scale applied.
2448 : *
2449 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2450 : *
2451 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2452 : * is actually associated with this layer. May be NULL (default).
2453 : *
2454 : * @return the nodata value for this band.
2455 : *
2456 : * @since GDAL 3.5
2457 : */
2458 :
2459 3 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2460 :
2461 : {
2462 3 : if (pbSuccess != nullptr)
2463 3 : *pbSuccess = FALSE;
2464 :
2465 3 : return std::numeric_limits<uint64_t>::max();
2466 : }
2467 :
2468 : /************************************************************************/
2469 : /* GDALGetRasterNoDataValueAsUInt64() */
2470 : /************************************************************************/
2471 :
2472 : /**
2473 : * \brief Fetch the no data value for this band.
2474 : *
2475 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2476 : *
2477 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2478 : *
2479 : * @since GDAL 3.5
2480 : */
2481 :
2482 18 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2483 : int *pbSuccess)
2484 :
2485 : {
2486 18 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2487 : std::numeric_limits<uint64_t>::max());
2488 :
2489 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2490 18 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2491 : }
2492 :
2493 : /************************************************************************/
2494 : /* SetNoDataValue() */
2495 : /************************************************************************/
2496 :
2497 : /**
2498 : * \fn GDALRasterBand::SetNoDataValue(double)
2499 : * \brief Set the no data value for this band.
2500 : *
2501 : * Depending on drivers, changing the no data value may or may not have an
2502 : * effect on the pixel values of a raster that has just been created. It is
2503 : * thus advised to explicitly called Fill() if the intent is to initialize
2504 : * the raster to the nodata value.
2505 : * In any case, changing an existing no data value, when one already exists and
2506 : * the dataset exists or has been initialized, has no effect on the pixel whose
2507 : * value matched the previous nodata value.
2508 : *
2509 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2510 : * be represented by a double, use SetNoDataValueAsInt64() or
2511 : * SetNoDataValueAsUInt64() instead.
2512 : *
2513 : * To clear the nodata value, use DeleteNoDataValue().
2514 : *
2515 : * This method is the same as the C function GDALSetRasterNoDataValue().
2516 : *
2517 : * @param dfNoData the value to set.
2518 : *
2519 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2520 : * by the driver, CE_Failure is returned by no error message will have
2521 : * been emitted.
2522 : */
2523 :
2524 : /**/
2525 : /**/
2526 :
2527 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2528 :
2529 : {
2530 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2531 0 : ReportError(CE_Failure, CPLE_NotSupported,
2532 : "SetNoDataValue() not supported for this dataset.");
2533 :
2534 0 : return CE_Failure;
2535 : }
2536 :
2537 : /************************************************************************/
2538 : /* GDALSetRasterNoDataValue() */
2539 : /************************************************************************/
2540 :
2541 : /**
2542 : * \brief Set the no data value for this band.
2543 : *
2544 : * Depending on drivers, changing the no data value may or may not have an
2545 : * effect on the pixel values of a raster that has just been created. It is
2546 : * thus advised to explicitly called Fill() if the intent is to initialize
2547 : * the raster to the nodata value.
2548 : * In any case, changing an existing no data value, when one already exists and
2549 : * the dataset exists or has been initialized, has no effect on the pixel whose
2550 : * value matched the previous nodata value.
2551 : *
2552 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2553 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2554 : * GDALSetRasterNoDataValueAsUInt64() instead.
2555 : *
2556 : * @see GDALRasterBand::SetNoDataValue()
2557 : */
2558 :
2559 749 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2560 : double dfValue)
2561 :
2562 : {
2563 749 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2564 :
2565 749 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2566 749 : return poBand->SetNoDataValue(dfValue);
2567 : }
2568 :
2569 : /************************************************************************/
2570 : /* SetNoDataValueAsInt64() */
2571 : /************************************************************************/
2572 :
2573 : /**
2574 : * \brief Set the no data value for this band.
2575 : *
2576 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2577 : *
2578 : * Depending on drivers, changing the no data value may or may not have an
2579 : * effect on the pixel values of a raster that has just been created. It is
2580 : * thus advised to explicitly called Fill() if the intent is to initialize
2581 : * the raster to the nodata value.
2582 : * In ay case, changing an existing no data value, when one already exists and
2583 : * the dataset exists or has been initialized, has no effect on the pixel whose
2584 : * value matched the previous nodata value.
2585 : *
2586 : * To clear the nodata value, use DeleteNoDataValue().
2587 : *
2588 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2589 : *
2590 : * @param nNoDataValue the value to set.
2591 : *
2592 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2593 : * by the driver, CE_Failure is returned by no error message will have
2594 : * been emitted.
2595 : *
2596 : * @since GDAL 3.5
2597 : */
2598 :
2599 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2600 :
2601 : {
2602 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2603 0 : ReportError(CE_Failure, CPLE_NotSupported,
2604 : "SetNoDataValueAsInt64() not supported for this dataset.");
2605 :
2606 0 : return CE_Failure;
2607 : }
2608 :
2609 : /************************************************************************/
2610 : /* GDALSetRasterNoDataValueAsInt64() */
2611 : /************************************************************************/
2612 :
2613 : /**
2614 : * \brief Set the no data value for this band.
2615 : *
2616 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2617 : *
2618 : * Depending on drivers, changing the no data value may or may not have an
2619 : * effect on the pixel values of a raster that has just been created. It is
2620 : * thus advised to explicitly called Fill() if the intent is to initialize
2621 : * the raster to the nodata value.
2622 : * In ay case, changing an existing no data value, when one already exists and
2623 : * the dataset exists or has been initialized, has no effect on the pixel whose
2624 : * value matched the previous nodata value.
2625 : *
2626 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2627 : *
2628 : * @since GDAL 3.5
2629 : */
2630 :
2631 18 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2632 : int64_t nValue)
2633 :
2634 : {
2635 18 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2636 :
2637 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2638 18 : return poBand->SetNoDataValueAsInt64(nValue);
2639 : }
2640 :
2641 : /************************************************************************/
2642 : /* SetNoDataValueAsUInt64() */
2643 : /************************************************************************/
2644 :
2645 : /**
2646 : * \brief Set the no data value for this band.
2647 : *
2648 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2649 : *
2650 : * Depending on drivers, changing the no data value may or may not have an
2651 : * effect on the pixel values of a raster that has just been created. It is
2652 : * thus advised to explicitly called Fill() if the intent is to initialize
2653 : * the raster to the nodata value.
2654 : * In ay case, changing an existing no data value, when one already exists and
2655 : * the dataset exists or has been initialized, has no effect on the pixel whose
2656 : * value matched the previous nodata value.
2657 : *
2658 : * To clear the nodata value, use DeleteNoDataValue().
2659 : *
2660 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2661 : *
2662 : * @param nNoDataValue the value to set.
2663 : *
2664 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2665 : * by the driver, CE_Failure is returned by no error message will have
2666 : * been emitted.
2667 : *
2668 : * @since GDAL 3.5
2669 : */
2670 :
2671 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2672 :
2673 : {
2674 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2675 0 : ReportError(CE_Failure, CPLE_NotSupported,
2676 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2677 :
2678 0 : return CE_Failure;
2679 : }
2680 :
2681 : /************************************************************************/
2682 : /* GDALSetRasterNoDataValueAsUInt64() */
2683 : /************************************************************************/
2684 :
2685 : /**
2686 : * \brief Set the no data value for this band.
2687 : *
2688 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2689 : *
2690 : * Depending on drivers, changing the no data value may or may not have an
2691 : * effect on the pixel values of a raster that has just been created. It is
2692 : * thus advised to explicitly called Fill() if the intent is to initialize
2693 : * the raster to the nodata value.
2694 : * In ay case, changing an existing no data value, when one already exists and
2695 : * the dataset exists or has been initialized, has no effect on the pixel whose
2696 : * value matched the previous nodata value.
2697 : *
2698 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2699 : *
2700 : * @since GDAL 3.5
2701 : */
2702 :
2703 16 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2704 : uint64_t nValue)
2705 :
2706 : {
2707 16 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2708 :
2709 16 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2710 16 : return poBand->SetNoDataValueAsUInt64(nValue);
2711 : }
2712 :
2713 : /************************************************************************/
2714 : /* DeleteNoDataValue() */
2715 : /************************************************************************/
2716 :
2717 : /**
2718 : * \brief Remove the no data value for this band.
2719 : *
2720 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2721 : *
2722 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2723 : * by the driver, CE_Failure is returned by no error message will have
2724 : * been emitted.
2725 : *
2726 : * @since GDAL 2.1
2727 : */
2728 :
2729 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2730 :
2731 : {
2732 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2733 0 : ReportError(CE_Failure, CPLE_NotSupported,
2734 : "DeleteNoDataValue() not supported for this dataset.");
2735 :
2736 0 : return CE_Failure;
2737 : }
2738 :
2739 : /************************************************************************/
2740 : /* GDALDeleteRasterNoDataValue() */
2741 : /************************************************************************/
2742 :
2743 : /**
2744 : * \brief Remove the no data value for this band.
2745 : *
2746 : * @see GDALRasterBand::DeleteNoDataValue()
2747 : *
2748 : * @since GDAL 2.1
2749 : */
2750 :
2751 41 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2752 :
2753 : {
2754 41 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2755 :
2756 41 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2757 41 : return poBand->DeleteNoDataValue();
2758 : }
2759 :
2760 : /************************************************************************/
2761 : /* GetMaximum() */
2762 : /************************************************************************/
2763 :
2764 : /**
2765 : * \brief Fetch the maximum value for this band.
2766 : *
2767 : * For file formats that don't know this intrinsically, the maximum supported
2768 : * value for the data type will generally be returned.
2769 : *
2770 : * This method is the same as the C function GDALGetRasterMaximum().
2771 : *
2772 : * @param pbSuccess pointer to a boolean to use to indicate if the
2773 : * returned value is a tight maximum or not. May be NULL (default).
2774 : *
2775 : * @return the maximum raster value (excluding no data pixels)
2776 : */
2777 :
2778 501 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2779 :
2780 : {
2781 501 : const char *pszValue = nullptr;
2782 :
2783 501 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2784 : {
2785 46 : if (pbSuccess != nullptr)
2786 41 : *pbSuccess = TRUE;
2787 :
2788 46 : return CPLAtofM(pszValue);
2789 : }
2790 :
2791 455 : if (pbSuccess != nullptr)
2792 451 : *pbSuccess = FALSE;
2793 :
2794 455 : switch (eDataType)
2795 : {
2796 308 : case GDT_Byte:
2797 : {
2798 308 : EnablePixelTypeSignedByteWarning(false);
2799 : const char *pszPixelType =
2800 308 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2801 308 : EnablePixelTypeSignedByteWarning(true);
2802 308 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2803 0 : return 127;
2804 :
2805 308 : return 255;
2806 : }
2807 :
2808 1 : case GDT_Int8:
2809 1 : return 127;
2810 :
2811 18 : case GDT_UInt16:
2812 18 : return 65535;
2813 :
2814 23 : case GDT_Int16:
2815 : case GDT_CInt16:
2816 23 : return 32767;
2817 :
2818 39 : case GDT_Int32:
2819 : case GDT_CInt32:
2820 39 : return 2147483647.0;
2821 :
2822 12 : case GDT_UInt32:
2823 12 : return 4294967295.0;
2824 :
2825 1 : case GDT_Int64:
2826 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2827 :
2828 1 : case GDT_UInt64:
2829 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2830 :
2831 0 : case GDT_Float16:
2832 : case GDT_CFloat16:
2833 0 : return 65504.0;
2834 :
2835 30 : case GDT_Float32:
2836 : case GDT_CFloat32:
2837 30 : return 4294967295.0; // Not actually accurate.
2838 :
2839 22 : case GDT_Float64:
2840 : case GDT_CFloat64:
2841 22 : return 4294967295.0; // Not actually accurate.
2842 :
2843 0 : case GDT_Unknown:
2844 : case GDT_TypeCount:
2845 0 : break;
2846 : }
2847 0 : return 4294967295.0; // Not actually accurate.
2848 : }
2849 :
2850 : /************************************************************************/
2851 : /* GDALGetRasterMaximum() */
2852 : /************************************************************************/
2853 :
2854 : /**
2855 : * \brief Fetch the maximum value for this band.
2856 : *
2857 : * @see GDALRasterBand::GetMaximum()
2858 : */
2859 :
2860 271 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2861 :
2862 : {
2863 271 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2864 :
2865 271 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2866 271 : return poBand->GetMaximum(pbSuccess);
2867 : }
2868 :
2869 : /************************************************************************/
2870 : /* GetMinimum() */
2871 : /************************************************************************/
2872 :
2873 : /**
2874 : * \brief Fetch the minimum value for this band.
2875 : *
2876 : * For file formats that don't know this intrinsically, the minimum supported
2877 : * value for the data type will generally be returned.
2878 : *
2879 : * This method is the same as the C function GDALGetRasterMinimum().
2880 : *
2881 : * @param pbSuccess pointer to a boolean to use to indicate if the
2882 : * returned value is a tight minimum or not. May be NULL (default).
2883 : *
2884 : * @return the minimum raster value (excluding no data pixels)
2885 : */
2886 :
2887 509 : double GDALRasterBand::GetMinimum(int *pbSuccess)
2888 :
2889 : {
2890 509 : const char *pszValue = nullptr;
2891 :
2892 509 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
2893 : {
2894 51 : if (pbSuccess != nullptr)
2895 46 : *pbSuccess = TRUE;
2896 :
2897 51 : return CPLAtofM(pszValue);
2898 : }
2899 :
2900 458 : if (pbSuccess != nullptr)
2901 454 : *pbSuccess = FALSE;
2902 :
2903 458 : switch (eDataType)
2904 : {
2905 311 : case GDT_Byte:
2906 : {
2907 311 : EnablePixelTypeSignedByteWarning(false);
2908 : const char *pszPixelType =
2909 311 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2910 311 : EnablePixelTypeSignedByteWarning(true);
2911 311 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2912 0 : return -128;
2913 :
2914 311 : return 0;
2915 : }
2916 :
2917 1 : case GDT_Int8:
2918 1 : return -128;
2919 : break;
2920 :
2921 18 : case GDT_UInt16:
2922 18 : return 0;
2923 :
2924 23 : case GDT_Int16:
2925 : case GDT_CInt16:
2926 23 : return -32768;
2927 :
2928 39 : case GDT_Int32:
2929 : case GDT_CInt32:
2930 39 : return -2147483648.0;
2931 :
2932 12 : case GDT_UInt32:
2933 12 : return 0;
2934 :
2935 1 : case GDT_Int64:
2936 1 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
2937 :
2938 1 : case GDT_UInt64:
2939 1 : return 0;
2940 :
2941 0 : case GDT_Float16:
2942 : case GDT_CFloat16:
2943 0 : return -65504.0;
2944 :
2945 30 : case GDT_Float32:
2946 : case GDT_CFloat32:
2947 30 : return -4294967295.0; // Not actually accurate.
2948 :
2949 22 : case GDT_Float64:
2950 : case GDT_CFloat64:
2951 22 : return -4294967295.0; // Not actually accurate.
2952 :
2953 0 : case GDT_Unknown:
2954 : case GDT_TypeCount:
2955 0 : break;
2956 : }
2957 0 : return -4294967295.0; // Not actually accurate.
2958 : }
2959 :
2960 : /************************************************************************/
2961 : /* GDALGetRasterMinimum() */
2962 : /************************************************************************/
2963 :
2964 : /**
2965 : * \brief Fetch the minimum value for this band.
2966 : *
2967 : * @see GDALRasterBand::GetMinimum()
2968 : */
2969 :
2970 281 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
2971 :
2972 : {
2973 281 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
2974 :
2975 281 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2976 281 : return poBand->GetMinimum(pbSuccess);
2977 : }
2978 :
2979 : /************************************************************************/
2980 : /* GetColorInterpretation() */
2981 : /************************************************************************/
2982 :
2983 : /**
2984 : * \brief How should this band be interpreted as color?
2985 : *
2986 : * GCI_Undefined is returned when the format doesn't know anything
2987 : * about the color interpretation.
2988 : *
2989 : * This method is the same as the C function
2990 : * GDALGetRasterColorInterpretation().
2991 : *
2992 : * @return color interpretation value for band.
2993 : */
2994 :
2995 115 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
2996 :
2997 : {
2998 115 : return GCI_Undefined;
2999 : }
3000 :
3001 : /************************************************************************/
3002 : /* GDALGetRasterColorInterpretation() */
3003 : /************************************************************************/
3004 :
3005 : /**
3006 : * \brief How should this band be interpreted as color?
3007 : *
3008 : * @see GDALRasterBand::GetColorInterpretation()
3009 : */
3010 :
3011 : GDALColorInterp CPL_STDCALL
3012 5141 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3013 :
3014 : {
3015 5141 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3016 :
3017 5141 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3018 5141 : return poBand->GetColorInterpretation();
3019 : }
3020 :
3021 : /************************************************************************/
3022 : /* SetColorInterpretation() */
3023 : /************************************************************************/
3024 :
3025 : /**
3026 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3027 : * \brief Set color interpretation of a band.
3028 : *
3029 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3030 : *
3031 : * @param eColorInterp the new color interpretation to apply to this band.
3032 : *
3033 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3034 : */
3035 :
3036 : /**/
3037 : /**/
3038 :
3039 3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3040 :
3041 : {
3042 3 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3043 3 : ReportError(CE_Failure, CPLE_NotSupported,
3044 : "SetColorInterpretation() not supported for this dataset.");
3045 3 : return CE_Failure;
3046 : }
3047 :
3048 : /************************************************************************/
3049 : /* GDALSetRasterColorInterpretation() */
3050 : /************************************************************************/
3051 :
3052 : /**
3053 : * \brief Set color interpretation of a band.
3054 : *
3055 : * @see GDALRasterBand::SetColorInterpretation()
3056 : */
3057 :
3058 1779 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3059 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3060 :
3061 : {
3062 1779 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3063 :
3064 1779 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3065 1779 : return poBand->SetColorInterpretation(eColorInterp);
3066 : }
3067 :
3068 : /************************************************************************/
3069 : /* GetColorTable() */
3070 : /************************************************************************/
3071 :
3072 : /**
3073 : * \brief Fetch the color table associated with band.
3074 : *
3075 : * If there is no associated color table, the return result is NULL. The
3076 : * returned color table remains owned by the GDALRasterBand, and can't
3077 : * be depended on for long, nor should it ever be modified by the caller.
3078 : *
3079 : * This method is the same as the C function GDALGetRasterColorTable().
3080 : *
3081 : * @return internal color table, or NULL.
3082 : */
3083 :
3084 200 : GDALColorTable *GDALRasterBand::GetColorTable()
3085 :
3086 : {
3087 200 : return nullptr;
3088 : }
3089 :
3090 : /************************************************************************/
3091 : /* GDALGetRasterColorTable() */
3092 : /************************************************************************/
3093 :
3094 : /**
3095 : * \brief Fetch the color table associated with band.
3096 : *
3097 : * @see GDALRasterBand::GetColorTable()
3098 : */
3099 :
3100 1810 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3101 :
3102 : {
3103 1810 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3104 :
3105 1810 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3106 1810 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3107 : }
3108 :
3109 : /************************************************************************/
3110 : /* SetColorTable() */
3111 : /************************************************************************/
3112 :
3113 : /**
3114 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3115 : * \brief Set the raster color table.
3116 : *
3117 : * The driver will make a copy of all desired data in the colortable. It
3118 : * remains owned by the caller after the call.
3119 : *
3120 : * This method is the same as the C function GDALSetRasterColorTable().
3121 : *
3122 : * @param poCT the color table to apply. This may be NULL to clear the color
3123 : * table (where supported).
3124 : *
3125 : * @return CE_None on success, or CE_Failure on failure. If the action is
3126 : * unsupported by the driver, a value of CE_Failure is returned, but no
3127 : * error is issued.
3128 : */
3129 :
3130 : /**/
3131 : /**/
3132 :
3133 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3134 :
3135 : {
3136 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3137 0 : ReportError(CE_Failure, CPLE_NotSupported,
3138 : "SetColorTable() not supported for this dataset.");
3139 0 : return CE_Failure;
3140 : }
3141 :
3142 : /************************************************************************/
3143 : /* GDALSetRasterColorTable() */
3144 : /************************************************************************/
3145 :
3146 : /**
3147 : * \brief Set the raster color table.
3148 : *
3149 : * @see GDALRasterBand::SetColorTable()
3150 : */
3151 :
3152 76 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3153 : GDALColorTableH hCT)
3154 :
3155 : {
3156 76 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3157 :
3158 76 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3159 76 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3160 : }
3161 :
3162 : /************************************************************************/
3163 : /* HasArbitraryOverviews() */
3164 : /************************************************************************/
3165 :
3166 : /**
3167 : * \brief Check for arbitrary overviews.
3168 : *
3169 : * This returns TRUE if the underlying datastore can compute arbitrary
3170 : * overviews efficiently, such as is the case with OGDI over a network.
3171 : * Datastores with arbitrary overviews don't generally have any fixed
3172 : * overviews, but the RasterIO() method can be used in downsampling mode
3173 : * to get overview data efficiently.
3174 : *
3175 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3176 : *
3177 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3178 : * FALSE.
3179 : */
3180 :
3181 241 : int GDALRasterBand::HasArbitraryOverviews()
3182 :
3183 : {
3184 241 : return FALSE;
3185 : }
3186 :
3187 : /************************************************************************/
3188 : /* GDALHasArbitraryOverviews() */
3189 : /************************************************************************/
3190 :
3191 : /**
3192 : * \brief Check for arbitrary overviews.
3193 : *
3194 : * @see GDALRasterBand::HasArbitraryOverviews()
3195 : */
3196 :
3197 165 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3198 :
3199 : {
3200 165 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3201 :
3202 165 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3203 165 : return poBand->HasArbitraryOverviews();
3204 : }
3205 :
3206 : /************************************************************************/
3207 : /* GetOverviewCount() */
3208 : /************************************************************************/
3209 :
3210 : /**
3211 : * \brief Return the number of overview layers available.
3212 : *
3213 : * This method is the same as the C function GDALGetOverviewCount().
3214 : *
3215 : * @return overview count, zero if none.
3216 : */
3217 :
3218 660633 : int GDALRasterBand::GetOverviewCount()
3219 :
3220 : {
3221 1316340 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3222 655709 : poDS->AreOverviewsEnabled())
3223 655709 : return poDS->oOvManager.GetOverviewCount(nBand);
3224 :
3225 4924 : return 0;
3226 : }
3227 :
3228 : /************************************************************************/
3229 : /* GDALGetOverviewCount() */
3230 : /************************************************************************/
3231 :
3232 : /**
3233 : * \brief Return the number of overview layers available.
3234 : *
3235 : * @see GDALRasterBand::GetOverviewCount()
3236 : */
3237 :
3238 3185 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3239 :
3240 : {
3241 3185 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3242 :
3243 3185 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3244 3185 : return poBand->GetOverviewCount();
3245 : }
3246 :
3247 : /************************************************************************/
3248 : /* GetOverview() */
3249 : /************************************************************************/
3250 :
3251 : /**
3252 : * \brief Fetch overview raster band object.
3253 : *
3254 : * This method is the same as the C function GDALGetOverview().
3255 : *
3256 : * @param i overview index between 0 and GetOverviewCount()-1.
3257 : *
3258 : * @return overview GDALRasterBand.
3259 : */
3260 :
3261 791 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3262 :
3263 : {
3264 1527 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3265 736 : poDS->AreOverviewsEnabled())
3266 736 : return poDS->oOvManager.GetOverview(nBand, i);
3267 :
3268 55 : return nullptr;
3269 : }
3270 :
3271 : /************************************************************************/
3272 : /* GDALGetOverview() */
3273 : /************************************************************************/
3274 :
3275 : /**
3276 : * \brief Fetch overview raster band object.
3277 : *
3278 : * @see GDALRasterBand::GetOverview()
3279 : */
3280 :
3281 5574 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3282 :
3283 : {
3284 5574 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3285 :
3286 5574 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3287 5574 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3288 : }
3289 :
3290 : /************************************************************************/
3291 : /* GetRasterSampleOverview() */
3292 : /************************************************************************/
3293 :
3294 : /**
3295 : * \brief Fetch best sampling overview.
3296 : *
3297 : * Returns the most reduced overview of the given band that still satisfies
3298 : * the desired number of samples. This function can be used with zero
3299 : * as the number of desired samples to fetch the most reduced overview.
3300 : * The same band as was passed in will be returned if it has not overviews,
3301 : * or if none of the overviews have enough samples.
3302 : *
3303 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3304 : * and GDALGetRasterSampleOverviewEx().
3305 : *
3306 : * @param nDesiredSamples the returned band will have at least this many
3307 : * pixels.
3308 : *
3309 : * @return optimal overview or the band itself.
3310 : */
3311 :
3312 : GDALRasterBand *
3313 2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3314 :
3315 : {
3316 2006 : GDALRasterBand *poBestBand = this;
3317 :
3318 2006 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3319 :
3320 4023 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3321 : {
3322 2017 : GDALRasterBand *poOBand = GetOverview(iOverview);
3323 :
3324 2017 : if (poOBand == nullptr)
3325 0 : continue;
3326 :
3327 : const double dfOSamples =
3328 2017 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3329 :
3330 2017 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3331 : {
3332 2014 : dfBestSamples = dfOSamples;
3333 2014 : poBestBand = poOBand;
3334 : }
3335 : }
3336 :
3337 2006 : return poBestBand;
3338 : }
3339 :
3340 : /************************************************************************/
3341 : /* GDALGetRasterSampleOverview() */
3342 : /************************************************************************/
3343 :
3344 : /**
3345 : * \brief Fetch best sampling overview.
3346 : *
3347 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3348 : * billion samples.
3349 : *
3350 : * @see GDALRasterBand::GetRasterSampleOverview()
3351 : * @see GDALGetRasterSampleOverviewEx()
3352 : */
3353 :
3354 2000 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3355 : int nDesiredSamples)
3356 :
3357 : {
3358 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3359 :
3360 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3361 2000 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3362 4000 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3363 : }
3364 :
3365 : /************************************************************************/
3366 : /* GDALGetRasterSampleOverviewEx() */
3367 : /************************************************************************/
3368 :
3369 : /**
3370 : * \brief Fetch best sampling overview.
3371 : *
3372 : * @see GDALRasterBand::GetRasterSampleOverview()
3373 : * @since GDAL 2.0
3374 : */
3375 :
3376 : GDALRasterBandH CPL_STDCALL
3377 0 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3378 :
3379 : {
3380 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3381 :
3382 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3383 0 : return GDALRasterBand::ToHandle(
3384 0 : poBand->GetRasterSampleOverview(nDesiredSamples));
3385 : }
3386 :
3387 : /************************************************************************/
3388 : /* BuildOverviews() */
3389 : /************************************************************************/
3390 :
3391 : /**
3392 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3393 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3394 : *
3395 : * If the operation is unsupported for the indicated dataset, then
3396 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3397 : * CPLE_NotSupported.
3398 : *
3399 : * WARNING: Most formats don't support per-band overview computation, but
3400 : * require that overviews are computed for all bands of a dataset, using
3401 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3402 : * is the HFA driver which supports this method.
3403 : *
3404 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3405 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3406 : * applied.
3407 : * @param nOverviews number of overviews to build.
3408 : * @param panOverviewList the list of overview decimation factors to build.
3409 : * @param pfnProgress a function to call to report progress, or NULL.
3410 : * @param pProgressData application data to pass to the progress function.
3411 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3412 : * key=value pairs, or NULL
3413 : *
3414 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3415 : */
3416 :
3417 : /**/
3418 : /**/
3419 :
3420 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3421 : int /*nOverviews*/,
3422 : const int * /*panOverviewList*/,
3423 : GDALProgressFunc /*pfnProgress*/,
3424 : void * /*pProgressData*/,
3425 : CSLConstList /* papszOptions */)
3426 :
3427 : {
3428 0 : ReportError(CE_Failure, CPLE_NotSupported,
3429 : "BuildOverviews() not supported for this dataset.");
3430 :
3431 0 : return (CE_Failure);
3432 : }
3433 :
3434 : /************************************************************************/
3435 : /* GetOffset() */
3436 : /************************************************************************/
3437 :
3438 : /**
3439 : * \brief Fetch the raster value offset.
3440 : *
3441 : * This value (in combination with the GetScale() value) can be used to
3442 : * transform raw pixel values into the units returned by GetUnitType().
3443 : * For example this might be used to store elevations in GUInt16 bands
3444 : * with a precision of 0.1, and starting from -100.
3445 : *
3446 : * Units value = (raw value * scale) + offset
3447 : *
3448 : * Note that applying scale and offset is of the responsibility of the user,
3449 : * and is not done by methods such as RasterIO() or ReadBlock().
3450 : *
3451 : * For file formats that don't know this intrinsically a value of zero
3452 : * is returned.
3453 : *
3454 : * This method is the same as the C function GDALGetRasterOffset().
3455 : *
3456 : * @param pbSuccess pointer to a boolean to use to indicate if the
3457 : * returned value is meaningful or not. May be NULL (default).
3458 : *
3459 : * @return the raster offset.
3460 : */
3461 :
3462 381 : double GDALRasterBand::GetOffset(int *pbSuccess)
3463 :
3464 : {
3465 381 : if (pbSuccess != nullptr)
3466 313 : *pbSuccess = FALSE;
3467 :
3468 381 : return 0.0;
3469 : }
3470 :
3471 : /************************************************************************/
3472 : /* GDALGetRasterOffset() */
3473 : /************************************************************************/
3474 :
3475 : /**
3476 : * \brief Fetch the raster value offset.
3477 : *
3478 : * @see GDALRasterBand::GetOffset()
3479 : */
3480 :
3481 343 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3482 :
3483 : {
3484 343 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3485 :
3486 343 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3487 343 : return poBand->GetOffset(pbSuccess);
3488 : }
3489 :
3490 : /************************************************************************/
3491 : /* SetOffset() */
3492 : /************************************************************************/
3493 :
3494 : /**
3495 : * \fn GDALRasterBand::SetOffset(double)
3496 : * \brief Set scaling offset.
3497 : *
3498 : * Very few formats implement this method. When not implemented it will
3499 : * issue a CPLE_NotSupported error and return CE_Failure.
3500 : *
3501 : * This method is the same as the C function GDALSetRasterOffset().
3502 : *
3503 : * @param dfNewOffset the new offset.
3504 : *
3505 : * @return CE_None or success or CE_Failure on failure.
3506 : */
3507 :
3508 : /**/
3509 : /**/
3510 :
3511 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3512 : {
3513 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3514 0 : ReportError(CE_Failure, CPLE_NotSupported,
3515 : "SetOffset() not supported on this raster band.");
3516 :
3517 0 : return CE_Failure;
3518 : }
3519 :
3520 : /************************************************************************/
3521 : /* GDALSetRasterOffset() */
3522 : /************************************************************************/
3523 :
3524 : /**
3525 : * \brief Set scaling offset.
3526 : *
3527 : * @see GDALRasterBand::SetOffset()
3528 : */
3529 :
3530 73 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3531 : double dfNewOffset)
3532 :
3533 : {
3534 73 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3535 :
3536 73 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3537 73 : return poBand->SetOffset(dfNewOffset);
3538 : }
3539 :
3540 : /************************************************************************/
3541 : /* GetScale() */
3542 : /************************************************************************/
3543 :
3544 : /**
3545 : * \brief Fetch the raster value scale.
3546 : *
3547 : * This value (in combination with the GetOffset() value) can be used to
3548 : * transform raw pixel values into the units returned by GetUnitType().
3549 : * For example this might be used to store elevations in GUInt16 bands
3550 : * with a precision of 0.1, and starting from -100.
3551 : *
3552 : * Units value = (raw value * scale) + offset
3553 : *
3554 : * Note that applying scale and offset is of the responsibility of the user,
3555 : * and is not done by methods such as RasterIO() or ReadBlock().
3556 : *
3557 : * For file formats that don't know this intrinsically a value of one
3558 : * is returned.
3559 : *
3560 : * This method is the same as the C function GDALGetRasterScale().
3561 : *
3562 : * @param pbSuccess pointer to a boolean to use to indicate if the
3563 : * returned value is meaningful or not. May be NULL (default).
3564 : *
3565 : * @return the raster scale.
3566 : */
3567 :
3568 381 : double GDALRasterBand::GetScale(int *pbSuccess)
3569 :
3570 : {
3571 381 : if (pbSuccess != nullptr)
3572 313 : *pbSuccess = FALSE;
3573 :
3574 381 : return 1.0;
3575 : }
3576 :
3577 : /************************************************************************/
3578 : /* GDALGetRasterScale() */
3579 : /************************************************************************/
3580 :
3581 : /**
3582 : * \brief Fetch the raster value scale.
3583 : *
3584 : * @see GDALRasterBand::GetScale()
3585 : */
3586 :
3587 341 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3588 :
3589 : {
3590 341 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3591 :
3592 341 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3593 341 : return poBand->GetScale(pbSuccess);
3594 : }
3595 :
3596 : /************************************************************************/
3597 : /* SetScale() */
3598 : /************************************************************************/
3599 :
3600 : /**
3601 : * \fn GDALRasterBand::SetScale(double)
3602 : * \brief Set scaling ratio.
3603 : *
3604 : * Very few formats implement this method. When not implemented it will
3605 : * issue a CPLE_NotSupported error and return CE_Failure.
3606 : *
3607 : * This method is the same as the C function GDALSetRasterScale().
3608 : *
3609 : * @param dfNewScale the new scale.
3610 : *
3611 : * @return CE_None or success or CE_Failure on failure.
3612 : */
3613 :
3614 : /**/
3615 : /**/
3616 :
3617 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3618 :
3619 : {
3620 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3621 0 : ReportError(CE_Failure, CPLE_NotSupported,
3622 : "SetScale() not supported on this raster band.");
3623 :
3624 0 : return CE_Failure;
3625 : }
3626 :
3627 : /************************************************************************/
3628 : /* GDALSetRasterScale() */
3629 : /************************************************************************/
3630 :
3631 : /**
3632 : * \brief Set scaling ratio.
3633 : *
3634 : * @see GDALRasterBand::SetScale()
3635 : */
3636 :
3637 74 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3638 :
3639 : {
3640 74 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3641 :
3642 74 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3643 74 : return poBand->SetScale(dfNewOffset);
3644 : }
3645 :
3646 : /************************************************************************/
3647 : /* GetUnitType() */
3648 : /************************************************************************/
3649 :
3650 : /**
3651 : * \brief Return raster unit type.
3652 : *
3653 : * Return a name for the units of this raster's values. For instance, it
3654 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3655 : * units are available, a value of "" will be returned. The returned string
3656 : * should not be modified, nor freed by the calling application.
3657 : *
3658 : * This method is the same as the C function GDALGetRasterUnitType().
3659 : *
3660 : * @return unit name string.
3661 : */
3662 :
3663 155 : const char *GDALRasterBand::GetUnitType()
3664 :
3665 : {
3666 155 : return "";
3667 : }
3668 :
3669 : /************************************************************************/
3670 : /* GDALGetRasterUnitType() */
3671 : /************************************************************************/
3672 :
3673 : /**
3674 : * \brief Return raster unit type.
3675 : *
3676 : * @see GDALRasterBand::GetUnitType()
3677 : */
3678 :
3679 1363 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3680 :
3681 : {
3682 1363 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3683 :
3684 1363 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3685 1363 : return poBand->GetUnitType();
3686 : }
3687 :
3688 : /************************************************************************/
3689 : /* SetUnitType() */
3690 : /************************************************************************/
3691 :
3692 : /**
3693 : * \fn GDALRasterBand::SetUnitType(const char*)
3694 : * \brief Set unit type.
3695 : *
3696 : * Set the unit type for a raster band. Values should be one of
3697 : * "" (the default indicating it is unknown), "m" indicating meters,
3698 : * or "ft" indicating feet, though other nonstandard values are allowed.
3699 : *
3700 : * This method is the same as the C function GDALSetRasterUnitType().
3701 : *
3702 : * @param pszNewValue the new unit type value.
3703 : *
3704 : * @return CE_None on success or CE_Failure if not successful, or
3705 : * unsupported.
3706 : */
3707 :
3708 : /**/
3709 : /**/
3710 :
3711 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3712 :
3713 : {
3714 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3715 0 : ReportError(CE_Failure, CPLE_NotSupported,
3716 : "SetUnitType() not supported on this raster band.");
3717 0 : return CE_Failure;
3718 : }
3719 :
3720 : /************************************************************************/
3721 : /* GDALSetRasterUnitType() */
3722 : /************************************************************************/
3723 :
3724 : /**
3725 : * \brief Set unit type.
3726 : *
3727 : * @see GDALRasterBand::SetUnitType()
3728 : *
3729 : * @since GDAL 1.8.0
3730 : */
3731 :
3732 60 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3733 : const char *pszNewValue)
3734 :
3735 : {
3736 60 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3737 :
3738 60 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3739 60 : return poBand->SetUnitType(pszNewValue);
3740 : }
3741 :
3742 : /************************************************************************/
3743 : /* GetXSize() */
3744 : /************************************************************************/
3745 :
3746 : /**
3747 : * \brief Fetch XSize of raster.
3748 : *
3749 : * This method is the same as the C function GDALGetRasterBandXSize().
3750 : *
3751 : * @return the width in pixels of this band.
3752 : */
3753 :
3754 6706750 : int GDALRasterBand::GetXSize() const
3755 :
3756 : {
3757 6706750 : return nRasterXSize;
3758 : }
3759 :
3760 : /************************************************************************/
3761 : /* GDALGetRasterBandXSize() */
3762 : /************************************************************************/
3763 :
3764 : /**
3765 : * \brief Fetch XSize of raster.
3766 : *
3767 : * @see GDALRasterBand::GetXSize()
3768 : */
3769 :
3770 54247 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3771 :
3772 : {
3773 54247 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3774 :
3775 54247 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3776 54247 : return poBand->GetXSize();
3777 : }
3778 :
3779 : /************************************************************************/
3780 : /* GetYSize() */
3781 : /************************************************************************/
3782 :
3783 : /**
3784 : * \brief Fetch YSize of raster.
3785 : *
3786 : * This method is the same as the C function GDALGetRasterBandYSize().
3787 : *
3788 : * @return the height in pixels of this band.
3789 : */
3790 :
3791 3157690 : int GDALRasterBand::GetYSize() const
3792 :
3793 : {
3794 3157690 : return nRasterYSize;
3795 : }
3796 :
3797 : /************************************************************************/
3798 : /* GDALGetRasterBandYSize() */
3799 : /************************************************************************/
3800 :
3801 : /**
3802 : * \brief Fetch YSize of raster.
3803 : *
3804 : * @see GDALRasterBand::GetYSize()
3805 : */
3806 :
3807 53613 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3808 :
3809 : {
3810 53613 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3811 :
3812 53613 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3813 53613 : return poBand->GetYSize();
3814 : }
3815 :
3816 : /************************************************************************/
3817 : /* GetBand() */
3818 : /************************************************************************/
3819 :
3820 : /**
3821 : * \brief Fetch the band number.
3822 : *
3823 : * This method returns the band that this GDALRasterBand objects represents
3824 : * within its dataset. This method may return a value of 0 to indicate
3825 : * GDALRasterBand objects without an apparently relationship to a dataset,
3826 : * such as GDALRasterBands serving as overviews.
3827 : *
3828 : * This method is the same as the C function GDALGetBandNumber().
3829 : *
3830 : * @return band number (1+) or 0 if the band number isn't known.
3831 : */
3832 :
3833 18671 : int GDALRasterBand::GetBand() const
3834 :
3835 : {
3836 18671 : return nBand;
3837 : }
3838 :
3839 : /************************************************************************/
3840 : /* GDALGetBandNumber() */
3841 : /************************************************************************/
3842 :
3843 : /**
3844 : * \brief Fetch the band number.
3845 : *
3846 : * @see GDALRasterBand::GetBand()
3847 : */
3848 :
3849 149 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3850 :
3851 : {
3852 149 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3853 :
3854 149 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3855 149 : return poBand->GetBand();
3856 : }
3857 :
3858 : /************************************************************************/
3859 : /* GetDataset() */
3860 : /************************************************************************/
3861 :
3862 : /**
3863 : * \brief Fetch the owning dataset handle.
3864 : *
3865 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3866 : * such as overviews or other "freestanding" bands.
3867 : *
3868 : * This method is the same as the C function GDALGetBandDataset().
3869 : *
3870 : * @return the pointer to the GDALDataset to which this band belongs, or
3871 : * NULL if this cannot be determined.
3872 : */
3873 :
3874 3850930 : GDALDataset *GDALRasterBand::GetDataset() const
3875 :
3876 : {
3877 3850930 : return poDS;
3878 : }
3879 :
3880 : /************************************************************************/
3881 : /* GDALGetBandDataset() */
3882 : /************************************************************************/
3883 :
3884 : /**
3885 : * \brief Fetch the owning dataset handle.
3886 : *
3887 : * @see GDALRasterBand::GetDataset()
3888 : */
3889 :
3890 341 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
3891 :
3892 : {
3893 341 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
3894 :
3895 341 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3896 341 : return GDALDataset::ToHandle(poBand->GetDataset());
3897 : }
3898 :
3899 : /************************************************************************/
3900 : /* ComputeFloat16NoDataValue() */
3901 : /************************************************************************/
3902 :
3903 2026 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
3904 : double dfNoDataValue,
3905 : int &bGotNoDataValue,
3906 : GFloat16 &fNoDataValue,
3907 : bool &bGotFloat16NoDataValue)
3908 : {
3909 2026 : if (eDataType == GDT_Float16 && bGotNoDataValue)
3910 : {
3911 0 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
3912 0 : if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
3913 : {
3914 0 : fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
3915 0 : bGotFloat16NoDataValue = true;
3916 0 : bGotNoDataValue = false;
3917 : }
3918 : }
3919 2026 : }
3920 :
3921 : /************************************************************************/
3922 : /* ComputeFloatNoDataValue() */
3923 : /************************************************************************/
3924 :
3925 2026 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
3926 : double dfNoDataValue,
3927 : int &bGotNoDataValue,
3928 : float &fNoDataValue,
3929 : bool &bGotFloatNoDataValue)
3930 : {
3931 2026 : if (eDataType == GDT_Float32 && bGotNoDataValue)
3932 : {
3933 69 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
3934 69 : if (GDALIsValueInRange<float>(dfNoDataValue))
3935 : {
3936 69 : fNoDataValue = static_cast<float>(dfNoDataValue);
3937 69 : bGotFloatNoDataValue = true;
3938 69 : bGotNoDataValue = false;
3939 : }
3940 : }
3941 2026 : }
3942 :
3943 : /************************************************************************/
3944 : /* struct GDALNoDataValues */
3945 : /************************************************************************/
3946 :
3947 : /**
3948 : * \brief No-data-values for all types
3949 : *
3950 : * The functions below pass various no-data-values around. To avoid
3951 : * long argument lists, this struct collects the no-data-values for
3952 : * all types into a single, convenient place.
3953 : **/
3954 :
3955 : struct GDALNoDataValues
3956 : {
3957 : int bGotNoDataValue;
3958 : double dfNoDataValue;
3959 :
3960 : bool bGotFloatNoDataValue;
3961 : float fNoDataValue;
3962 :
3963 : bool bGotFloat16NoDataValue;
3964 : GFloat16 hfNoDataValue;
3965 :
3966 2026 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
3967 2026 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
3968 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
3969 2026 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
3970 : {
3971 2024 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
3972 2026 : bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
3973 :
3974 2026 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
3975 2026 : fNoDataValue, bGotFloatNoDataValue);
3976 :
3977 2026 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
3978 2026 : hfNoDataValue, bGotFloat16NoDataValue);
3979 2026 : }
3980 : };
3981 :
3982 : /************************************************************************/
3983 : /* GetHistogram() */
3984 : /************************************************************************/
3985 :
3986 : /**
3987 : * \brief Compute raster histogram.
3988 : *
3989 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
3990 : *
3991 : * For example to compute a simple 256 entry histogram of eight bit data,
3992 : * the following would be suitable. The unusual bounds are to ensure that
3993 : * bucket boundaries don't fall right on integer values causing possible errors
3994 : * due to rounding after scaling.
3995 : \code{.cpp}
3996 : GUIntBig anHistogram[256];
3997 :
3998 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
3999 : GDALDummyProgress, nullptr );
4000 : \endcode
4001 : *
4002 : * Note that setting bApproxOK will generally result in a subsampling of the
4003 : * file, and will utilize overviews if available. It should generally
4004 : * produce a representative histogram for the data that is suitable for use
4005 : * in generating histogram based luts for instance. Generally bApproxOK is
4006 : * much faster than an exactly computed histogram.
4007 : *
4008 : * This method is the same as the C functions GDALGetRasterHistogram() and
4009 : * GDALGetRasterHistogramEx().
4010 : *
4011 : * @param dfMin the lower bound of the histogram.
4012 : * @param dfMax the upper bound of the histogram.
4013 : * @param nBuckets the number of buckets in panHistogram.
4014 : * @param panHistogram array into which the histogram totals are placed.
4015 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4016 : * mapped into panHistogram[0], and values above will be mapped into
4017 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4018 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4019 : * @param pfnProgress function to report progress to completion.
4020 : * @param pProgressData application data to pass to pfnProgress.
4021 : *
4022 : * @return CE_None on success, or CE_Failure if something goes wrong.
4023 : */
4024 :
4025 40 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4026 : GUIntBig *panHistogram,
4027 : int bIncludeOutOfRange, int bApproxOK,
4028 : GDALProgressFunc pfnProgress,
4029 : void *pProgressData)
4030 :
4031 : {
4032 40 : CPLAssert(nullptr != panHistogram);
4033 :
4034 40 : if (pfnProgress == nullptr)
4035 26 : pfnProgress = GDALDummyProgress;
4036 :
4037 : /* -------------------------------------------------------------------- */
4038 : /* If we have overviews, use them for the histogram. */
4039 : /* -------------------------------------------------------------------- */
4040 40 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4041 : {
4042 : // FIXME: should we use the most reduced overview here or use some
4043 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4044 : // does?
4045 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4046 :
4047 0 : if (poBestOverview != this)
4048 : {
4049 0 : return poBestOverview->GetHistogram(
4050 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4051 0 : bApproxOK, pfnProgress, pProgressData);
4052 : }
4053 : }
4054 :
4055 : /* -------------------------------------------------------------------- */
4056 : /* Read actual data and build histogram. */
4057 : /* -------------------------------------------------------------------- */
4058 40 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4059 : {
4060 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4061 0 : return CE_Failure;
4062 : }
4063 :
4064 : // Written this way to deal with NaN
4065 40 : if (!(dfMax > dfMin))
4066 : {
4067 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4068 : "dfMax should be strictly greater than dfMin");
4069 5 : return CE_Failure;
4070 : }
4071 :
4072 : GDALRasterIOExtraArg sExtraArg;
4073 35 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4074 :
4075 35 : const double dfScale = nBuckets / (dfMax - dfMin);
4076 35 : if (dfScale == 0 || !std::isfinite(dfScale))
4077 : {
4078 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4079 : "dfMin and dfMax should be finite values such that "
4080 : "nBuckets / (dfMax - dfMin) is non-zero");
4081 5 : return CE_Failure;
4082 : }
4083 30 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4084 :
4085 30 : GDALNoDataValues sNoDataValues(this, eDataType);
4086 30 : GDALRasterBand *poMaskBand = nullptr;
4087 30 : if (!sNoDataValues.bGotNoDataValue)
4088 : {
4089 29 : const int l_nMaskFlags = GetMaskFlags();
4090 30 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
4091 1 : GetColorInterpretation() != GCI_AlphaBand)
4092 : {
4093 1 : poMaskBand = GetMaskBand();
4094 : }
4095 : }
4096 :
4097 30 : bool bSignedByte = false;
4098 30 : if (eDataType == GDT_Byte)
4099 : {
4100 23 : EnablePixelTypeSignedByteWarning(false);
4101 : const char *pszPixelType =
4102 23 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4103 23 : EnablePixelTypeSignedByteWarning(true);
4104 23 : bSignedByte =
4105 23 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4106 : }
4107 :
4108 30 : if (bApproxOK && HasArbitraryOverviews())
4109 : {
4110 : /* --------------------------------------------------------------------
4111 : */
4112 : /* Figure out how much the image should be reduced to get an */
4113 : /* approximate value. */
4114 : /* --------------------------------------------------------------------
4115 : */
4116 : const double dfReduction =
4117 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4118 : GDALSTAT_APPROX_NUMSAMPLES);
4119 :
4120 0 : int nXReduced = nRasterXSize;
4121 0 : int nYReduced = nRasterYSize;
4122 0 : if (dfReduction > 1.0)
4123 : {
4124 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4125 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4126 :
4127 : // Catch the case of huge resizing ratios here
4128 0 : if (nXReduced == 0)
4129 0 : nXReduced = 1;
4130 0 : if (nYReduced == 0)
4131 0 : nYReduced = 1;
4132 : }
4133 :
4134 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4135 : nXReduced, nYReduced);
4136 0 : if (!pData)
4137 0 : return CE_Failure;
4138 :
4139 : const CPLErr eErr =
4140 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4141 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4142 0 : if (eErr != CE_None)
4143 : {
4144 0 : CPLFree(pData);
4145 0 : return eErr;
4146 : }
4147 :
4148 0 : GByte *pabyMaskData = nullptr;
4149 0 : if (poMaskBand)
4150 : {
4151 : pabyMaskData =
4152 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4153 0 : if (!pabyMaskData)
4154 : {
4155 0 : CPLFree(pData);
4156 0 : return CE_Failure;
4157 : }
4158 :
4159 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4160 : pabyMaskData, nXReduced, nYReduced,
4161 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
4162 : {
4163 0 : CPLFree(pData);
4164 0 : CPLFree(pabyMaskData);
4165 0 : return CE_Failure;
4166 : }
4167 : }
4168 :
4169 : // This isn't the fastest way to do this, but is easier for now.
4170 0 : for (int iY = 0; iY < nYReduced; iY++)
4171 : {
4172 0 : for (int iX = 0; iX < nXReduced; iX++)
4173 : {
4174 0 : const int iOffset = iX + iY * nXReduced;
4175 0 : double dfValue = 0.0;
4176 :
4177 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4178 0 : continue;
4179 :
4180 0 : switch (eDataType)
4181 : {
4182 0 : case GDT_Byte:
4183 : {
4184 0 : if (bSignedByte)
4185 0 : dfValue =
4186 0 : static_cast<signed char *>(pData)[iOffset];
4187 : else
4188 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4189 0 : break;
4190 : }
4191 0 : case GDT_Int8:
4192 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4193 0 : break;
4194 0 : case GDT_UInt16:
4195 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4196 0 : break;
4197 0 : case GDT_Int16:
4198 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4199 0 : break;
4200 0 : case GDT_UInt32:
4201 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4202 0 : break;
4203 0 : case GDT_Int32:
4204 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4205 0 : break;
4206 0 : case GDT_UInt64:
4207 0 : dfValue = static_cast<double>(
4208 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4209 0 : break;
4210 0 : case GDT_Int64:
4211 0 : dfValue = static_cast<double>(
4212 0 : static_cast<GInt64 *>(pData)[iOffset]);
4213 0 : break;
4214 0 : case GDT_Float16:
4215 : {
4216 0 : const GFloat16 hfValue =
4217 0 : static_cast<GFloat16 *>(pData)[iOffset];
4218 0 : if (CPLIsNan(hfValue) ||
4219 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4220 0 : ARE_REAL_EQUAL(hfValue,
4221 : sNoDataValues.hfNoDataValue)))
4222 0 : continue;
4223 0 : dfValue = hfValue;
4224 0 : break;
4225 : }
4226 0 : case GDT_Float32:
4227 : {
4228 0 : const float fValue =
4229 0 : static_cast<float *>(pData)[iOffset];
4230 0 : if (CPLIsNan(fValue) ||
4231 0 : (sNoDataValues.bGotFloatNoDataValue &&
4232 0 : ARE_REAL_EQUAL(fValue,
4233 : sNoDataValues.fNoDataValue)))
4234 0 : continue;
4235 0 : dfValue = fValue;
4236 0 : break;
4237 : }
4238 0 : case GDT_Float64:
4239 0 : dfValue = static_cast<double *>(pData)[iOffset];
4240 0 : if (std::isnan(dfValue))
4241 0 : continue;
4242 0 : break;
4243 0 : case GDT_CInt16:
4244 : {
4245 0 : const double dfReal =
4246 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4247 0 : const double dfImag =
4248 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4249 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4250 0 : continue;
4251 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4252 : }
4253 0 : break;
4254 0 : case GDT_CInt32:
4255 : {
4256 0 : const double dfReal =
4257 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4258 0 : const double dfImag =
4259 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4260 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4261 0 : continue;
4262 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4263 : }
4264 0 : break;
4265 0 : case GDT_CFloat16:
4266 : {
4267 : const double dfReal =
4268 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4269 : const double dfImag =
4270 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4271 0 : if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
4272 0 : continue;
4273 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4274 0 : break;
4275 : }
4276 0 : case GDT_CFloat32:
4277 : {
4278 0 : const double dfReal =
4279 0 : static_cast<float *>(pData)[iOffset * 2];
4280 0 : const double dfImag =
4281 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
4282 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4283 0 : continue;
4284 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4285 0 : break;
4286 : }
4287 0 : case GDT_CFloat64:
4288 : {
4289 0 : const double dfReal =
4290 0 : static_cast<double *>(pData)[iOffset * 2];
4291 0 : const double dfImag =
4292 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4293 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4294 0 : continue;
4295 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4296 0 : break;
4297 : }
4298 0 : case GDT_Unknown:
4299 : case GDT_TypeCount:
4300 0 : CPLAssert(false);
4301 : }
4302 :
4303 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4304 0 : sNoDataValues.bGotNoDataValue &&
4305 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4306 0 : continue;
4307 :
4308 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4309 : // finite, the result of the multiplication cannot be NaN
4310 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4311 :
4312 0 : if (dfIndex < 0)
4313 : {
4314 0 : if (bIncludeOutOfRange)
4315 0 : panHistogram[0]++;
4316 : }
4317 0 : else if (dfIndex >= nBuckets)
4318 : {
4319 0 : if (bIncludeOutOfRange)
4320 0 : ++panHistogram[nBuckets - 1];
4321 : }
4322 : else
4323 : {
4324 0 : ++panHistogram[static_cast<int>(dfIndex)];
4325 : }
4326 : }
4327 : }
4328 :
4329 0 : CPLFree(pData);
4330 0 : CPLFree(pabyMaskData);
4331 : }
4332 : else // No arbitrary overviews.
4333 : {
4334 30 : if (!InitBlockInfo())
4335 0 : return CE_Failure;
4336 :
4337 : /* --------------------------------------------------------------------
4338 : */
4339 : /* Figure out the ratio of blocks we will read to get an */
4340 : /* approximate value. */
4341 : /* --------------------------------------------------------------------
4342 : */
4343 :
4344 30 : int nSampleRate = 1;
4345 30 : if (bApproxOK)
4346 : {
4347 8 : nSampleRate = static_cast<int>(std::max(
4348 16 : 1.0,
4349 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4350 : // We want to avoid probing only the first column of blocks for
4351 : // a square shaped raster, because it is not unlikely that it may
4352 : // be padding only (#6378).
4353 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4354 2 : nSampleRate += 1;
4355 : }
4356 :
4357 30 : GByte *pabyMaskData = nullptr;
4358 30 : if (poMaskBand)
4359 : {
4360 : pabyMaskData = static_cast<GByte *>(
4361 1 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4362 1 : if (!pabyMaskData)
4363 : {
4364 0 : return CE_Failure;
4365 : }
4366 : }
4367 :
4368 : /* --------------------------------------------------------------------
4369 : */
4370 : /* Read the blocks, and add to histogram. */
4371 : /* --------------------------------------------------------------------
4372 : */
4373 30 : for (GIntBig iSampleBlock = 0;
4374 138 : iSampleBlock <
4375 138 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4376 108 : iSampleBlock += nSampleRate)
4377 : {
4378 108 : if (!pfnProgress(
4379 108 : static_cast<double>(iSampleBlock) /
4380 108 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4381 : "Compute Histogram", pProgressData))
4382 : {
4383 0 : CPLFree(pabyMaskData);
4384 0 : return CE_Failure;
4385 : }
4386 :
4387 108 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4388 108 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4389 :
4390 108 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4391 108 : if (poBlock == nullptr)
4392 : {
4393 0 : CPLFree(pabyMaskData);
4394 0 : return CE_Failure;
4395 : }
4396 :
4397 108 : void *pData = poBlock->GetDataRef();
4398 :
4399 108 : int nXCheck = 0, nYCheck = 0;
4400 108 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4401 :
4402 109 : if (poMaskBand &&
4403 1 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4404 1 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4405 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4406 1 : 0, nBlockXSize, nullptr) != CE_None)
4407 : {
4408 0 : CPLFree(pabyMaskData);
4409 0 : poBlock->DropLock();
4410 0 : return CE_Failure;
4411 : }
4412 :
4413 : // this is a special case for a common situation.
4414 108 : if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4415 86 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4416 83 : nXCheck == nBlockXSize && nBuckets == 256)
4417 : {
4418 83 : const GPtrDiff_t nPixels =
4419 83 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4420 83 : GByte *pabyData = static_cast<GByte *>(pData);
4421 :
4422 72137 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4423 : {
4424 72054 : if (pabyMaskData && pabyMaskData[i] == 0)
4425 0 : continue;
4426 72054 : if (!(sNoDataValues.bGotNoDataValue &&
4427 512 : (pabyData[i] ==
4428 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4429 : {
4430 71798 : panHistogram[pabyData[i]]++;
4431 : }
4432 : }
4433 :
4434 83 : poBlock->DropLock();
4435 83 : continue; // To next sample block.
4436 : }
4437 :
4438 : // This isn't the fastest way to do this, but is easier for now.
4439 721 : for (int iY = 0; iY < nYCheck; iY++)
4440 : {
4441 86017 : for (int iX = 0; iX < nXCheck; iX++)
4442 : {
4443 85321 : const GPtrDiff_t iOffset =
4444 85321 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4445 :
4446 85321 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4447 1 : continue;
4448 :
4449 85320 : double dfValue = 0.0;
4450 :
4451 85320 : switch (eDataType)
4452 : {
4453 19716 : case GDT_Byte:
4454 : {
4455 19716 : if (bSignedByte)
4456 0 : dfValue =
4457 0 : static_cast<signed char *>(pData)[iOffset];
4458 : else
4459 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4460 19716 : break;
4461 : }
4462 0 : case GDT_Int8:
4463 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4464 0 : break;
4465 65536 : case GDT_UInt16:
4466 65536 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4467 65536 : break;
4468 2 : case GDT_Int16:
4469 2 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4470 2 : break;
4471 0 : case GDT_UInt32:
4472 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4473 0 : break;
4474 60 : case GDT_Int32:
4475 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4476 60 : break;
4477 0 : case GDT_UInt64:
4478 0 : dfValue = static_cast<double>(
4479 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4480 0 : break;
4481 0 : case GDT_Int64:
4482 0 : dfValue = static_cast<double>(
4483 0 : static_cast<GInt64 *>(pData)[iOffset]);
4484 0 : break;
4485 0 : case GDT_Float16:
4486 : {
4487 0 : const GFloat16 hfValue =
4488 0 : static_cast<GFloat16 *>(pData)[iOffset];
4489 0 : if (CPLIsNan(hfValue) ||
4490 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4491 0 : ARE_REAL_EQUAL(hfValue,
4492 : sNoDataValues.hfNoDataValue)))
4493 0 : continue;
4494 0 : dfValue = hfValue;
4495 0 : break;
4496 : }
4497 4 : case GDT_Float32:
4498 : {
4499 4 : const float fValue =
4500 4 : static_cast<float *>(pData)[iOffset];
4501 8 : if (CPLIsNan(fValue) ||
4502 8 : (sNoDataValues.bGotFloatNoDataValue &&
4503 4 : ARE_REAL_EQUAL(fValue,
4504 : sNoDataValues.fNoDataValue)))
4505 1 : continue;
4506 3 : dfValue = fValue;
4507 3 : break;
4508 : }
4509 2 : case GDT_Float64:
4510 2 : dfValue = static_cast<double *>(pData)[iOffset];
4511 2 : if (std::isnan(dfValue))
4512 0 : continue;
4513 2 : break;
4514 0 : case GDT_CInt16:
4515 : {
4516 0 : double dfReal =
4517 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4518 0 : double dfImag =
4519 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4520 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4521 0 : break;
4522 : }
4523 0 : case GDT_CInt32:
4524 : {
4525 0 : double dfReal =
4526 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4527 0 : double dfImag =
4528 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4529 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4530 0 : break;
4531 : }
4532 0 : case GDT_CFloat16:
4533 : {
4534 : double dfReal =
4535 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4536 : double dfImag =
4537 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4538 0 : if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
4539 0 : continue;
4540 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4541 0 : break;
4542 : }
4543 0 : case GDT_CFloat32:
4544 : {
4545 0 : double dfReal =
4546 0 : static_cast<float *>(pData)[iOffset * 2];
4547 0 : double dfImag =
4548 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
4549 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4550 0 : continue;
4551 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4552 0 : break;
4553 : }
4554 0 : case GDT_CFloat64:
4555 : {
4556 0 : double dfReal =
4557 0 : static_cast<double *>(pData)[iOffset * 2];
4558 0 : double dfImag =
4559 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4560 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4561 0 : continue;
4562 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4563 0 : break;
4564 : }
4565 0 : case GDT_Unknown:
4566 : case GDT_TypeCount:
4567 0 : CPLAssert(false);
4568 : CPLFree(pabyMaskData);
4569 : return CE_Failure;
4570 : }
4571 :
4572 85319 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4573 170638 : sNoDataValues.bGotNoDataValue &&
4574 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4575 0 : continue;
4576 :
4577 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4578 : // and finite, the result of the multiplication cannot be
4579 : // NaN
4580 85319 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4581 :
4582 85319 : if (dfIndex < 0)
4583 : {
4584 1 : if (bIncludeOutOfRange)
4585 1 : panHistogram[0]++;
4586 : }
4587 85318 : else if (dfIndex >= nBuckets)
4588 : {
4589 7 : if (bIncludeOutOfRange)
4590 4 : ++panHistogram[nBuckets - 1];
4591 : }
4592 : else
4593 : {
4594 85311 : ++panHistogram[static_cast<int>(dfIndex)];
4595 : }
4596 : }
4597 : }
4598 :
4599 25 : poBlock->DropLock();
4600 : }
4601 :
4602 30 : CPLFree(pabyMaskData);
4603 : }
4604 :
4605 30 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4606 :
4607 30 : return CE_None;
4608 : }
4609 :
4610 : /************************************************************************/
4611 : /* GDALGetRasterHistogram() */
4612 : /************************************************************************/
4613 :
4614 : /**
4615 : * \brief Compute raster histogram.
4616 : *
4617 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4618 : * exceeding 2 billion.
4619 : *
4620 : * @see GDALRasterBand::GetHistogram()
4621 : * @see GDALGetRasterHistogramEx()
4622 : */
4623 :
4624 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4625 : double dfMax, int nBuckets,
4626 : int *panHistogram,
4627 : int bIncludeOutOfRange, int bApproxOK,
4628 : GDALProgressFunc pfnProgress,
4629 : void *pProgressData)
4630 :
4631 : {
4632 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4633 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4634 :
4635 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4636 :
4637 : GUIntBig *panHistogramTemp =
4638 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4639 0 : if (panHistogramTemp == nullptr)
4640 : {
4641 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4642 : "Out of memory in GDALGetRasterHistogram().");
4643 0 : return CE_Failure;
4644 : }
4645 :
4646 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4647 : bIncludeOutOfRange, bApproxOK,
4648 0 : pfnProgress, pProgressData);
4649 :
4650 0 : if (eErr == CE_None)
4651 : {
4652 0 : for (int i = 0; i < nBuckets; i++)
4653 : {
4654 0 : if (panHistogramTemp[i] > INT_MAX)
4655 : {
4656 0 : CPLError(CE_Warning, CPLE_AppDefined,
4657 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4658 : " exceeds maximum 32 bit value",
4659 0 : i, panHistogramTemp[i]);
4660 0 : panHistogram[i] = INT_MAX;
4661 : }
4662 : else
4663 : {
4664 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4665 : }
4666 : }
4667 : }
4668 :
4669 0 : CPLFree(panHistogramTemp);
4670 :
4671 0 : return eErr;
4672 : }
4673 :
4674 : /************************************************************************/
4675 : /* GDALGetRasterHistogramEx() */
4676 : /************************************************************************/
4677 :
4678 : /**
4679 : * \brief Compute raster histogram.
4680 : *
4681 : * @see GDALRasterBand::GetHistogram()
4682 : *
4683 : * @since GDAL 2.0
4684 : */
4685 :
4686 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4687 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4688 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4689 : GDALProgressFunc pfnProgress, void *pProgressData)
4690 :
4691 : {
4692 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4693 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4694 :
4695 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4696 :
4697 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4698 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4699 26 : pProgressData);
4700 : }
4701 :
4702 : /************************************************************************/
4703 : /* GetDefaultHistogram() */
4704 : /************************************************************************/
4705 :
4706 : /**
4707 : * \brief Fetch default raster histogram.
4708 : *
4709 : * The default method in GDALRasterBand will compute a default histogram. This
4710 : * method is overridden by derived classes (such as GDALPamRasterBand,
4711 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4712 : * stored histogram.
4713 : *
4714 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4715 : * GDALGetDefaultHistogramEx().
4716 : *
4717 : * @param pdfMin pointer to double value that will contain the lower bound of
4718 : * the histogram.
4719 : * @param pdfMax pointer to double value that will contain the upper bound of
4720 : * the histogram.
4721 : * @param pnBuckets pointer to int value that will contain the number of buckets
4722 : * in *ppanHistogram.
4723 : * @param ppanHistogram pointer to array into which the histogram totals are
4724 : * placed. To be freed with VSIFree
4725 : * @param bForce TRUE to force the computation. If FALSE and no default
4726 : * histogram is available, the method will return CE_Warning
4727 : * @param pfnProgress function to report progress to completion.
4728 : * @param pProgressData application data to pass to pfnProgress.
4729 : *
4730 : * @return CE_None on success, CE_Failure if something goes wrong, or
4731 : * CE_Warning if no default histogram is available.
4732 : */
4733 :
4734 23 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4735 : int *pnBuckets,
4736 : GUIntBig **ppanHistogram, int bForce,
4737 : GDALProgressFunc pfnProgress,
4738 : void *pProgressData)
4739 :
4740 : {
4741 23 : CPLAssert(nullptr != pnBuckets);
4742 23 : CPLAssert(nullptr != ppanHistogram);
4743 23 : CPLAssert(nullptr != pdfMin);
4744 23 : CPLAssert(nullptr != pdfMax);
4745 :
4746 23 : *pnBuckets = 0;
4747 23 : *ppanHistogram = nullptr;
4748 :
4749 23 : if (!bForce)
4750 6 : return CE_Warning;
4751 :
4752 17 : const int nBuckets = 256;
4753 :
4754 17 : bool bSignedByte = false;
4755 17 : if (eDataType == GDT_Byte)
4756 : {
4757 17 : EnablePixelTypeSignedByteWarning(false);
4758 : const char *pszPixelType =
4759 17 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4760 17 : EnablePixelTypeSignedByteWarning(true);
4761 17 : bSignedByte =
4762 17 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4763 : }
4764 :
4765 17 : if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4766 : {
4767 17 : *pdfMin = -0.5;
4768 17 : *pdfMax = 255.5;
4769 : }
4770 : else
4771 : {
4772 :
4773 : const CPLErr eErr =
4774 0 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4775 0 : const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4776 0 : *pdfMin -= dfHalfBucket;
4777 0 : *pdfMax += dfHalfBucket;
4778 :
4779 0 : if (eErr != CE_None)
4780 0 : return eErr;
4781 : }
4782 :
4783 17 : *ppanHistogram =
4784 17 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4785 17 : if (*ppanHistogram == nullptr)
4786 : {
4787 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4788 : "Out of memory in InitBlockInfo().");
4789 0 : return CE_Failure;
4790 : }
4791 :
4792 17 : *pnBuckets = nBuckets;
4793 34 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4794 17 : TRUE, FALSE, pfnProgress, pProgressData);
4795 17 : if (eErr != CE_None)
4796 : {
4797 0 : *pnBuckets = 0;
4798 : }
4799 17 : return eErr;
4800 : }
4801 :
4802 : /************************************************************************/
4803 : /* GDALGetDefaultHistogram() */
4804 : /************************************************************************/
4805 :
4806 : /**
4807 : * \brief Fetch default raster histogram.
4808 : *
4809 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4810 : * exceeding 2 billion.
4811 : *
4812 : * @see GDALRasterBand::GDALGetDefaultHistogram()
4813 : * @see GDALGetRasterHistogramEx()
4814 : */
4815 :
4816 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4817 : double *pdfMin, double *pdfMax,
4818 : int *pnBuckets, int **ppanHistogram,
4819 : int bForce,
4820 : GDALProgressFunc pfnProgress,
4821 : void *pProgressData)
4822 :
4823 : {
4824 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4825 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4826 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4827 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4828 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4829 :
4830 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4831 0 : GUIntBig *panHistogramTemp = nullptr;
4832 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
4833 : &panHistogramTemp, bForce,
4834 0 : pfnProgress, pProgressData);
4835 0 : if (eErr == CE_None)
4836 : {
4837 0 : const int nBuckets = *pnBuckets;
4838 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
4839 0 : if (*ppanHistogram == nullptr)
4840 : {
4841 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4842 : "Out of memory in GDALGetDefaultHistogram().");
4843 0 : VSIFree(panHistogramTemp);
4844 0 : return CE_Failure;
4845 : }
4846 :
4847 0 : for (int i = 0; i < nBuckets; ++i)
4848 : {
4849 0 : if (panHistogramTemp[i] > INT_MAX)
4850 : {
4851 0 : CPLError(CE_Warning, CPLE_AppDefined,
4852 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4853 : " exceeds maximum 32 bit value",
4854 0 : i, panHistogramTemp[i]);
4855 0 : (*ppanHistogram)[i] = INT_MAX;
4856 : }
4857 : else
4858 : {
4859 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
4860 : }
4861 : }
4862 :
4863 0 : CPLFree(panHistogramTemp);
4864 : }
4865 : else
4866 : {
4867 0 : *ppanHistogram = nullptr;
4868 : }
4869 :
4870 0 : return eErr;
4871 : }
4872 :
4873 : /************************************************************************/
4874 : /* GDALGetDefaultHistogramEx() */
4875 : /************************************************************************/
4876 :
4877 : /**
4878 : * \brief Fetch default raster histogram.
4879 : *
4880 : * @see GDALRasterBand::GetDefaultHistogram()
4881 : *
4882 : * @since GDAL 2.0
4883 : */
4884 :
4885 : CPLErr CPL_STDCALL
4886 28 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
4887 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
4888 : GDALProgressFunc pfnProgress, void *pProgressData)
4889 :
4890 : {
4891 28 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4892 28 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4893 28 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4894 28 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4895 28 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4896 :
4897 28 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4898 28 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
4899 28 : bForce, pfnProgress, pProgressData);
4900 : }
4901 :
4902 : /************************************************************************/
4903 : /* AdviseRead() */
4904 : /************************************************************************/
4905 :
4906 : /**
4907 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
4908 : * \brief Advise driver of upcoming read requests.
4909 : *
4910 : * Some GDAL drivers operate more efficiently if they know in advance what
4911 : * set of upcoming read requests will be made. The AdviseRead() method allows
4912 : * an application to notify the driver of the region of interest,
4913 : * and at what resolution the region will be read.
4914 : *
4915 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
4916 : * accelerate access via some drivers.
4917 : *
4918 : * Depending on call paths, drivers might receive several calls to
4919 : * AdviseRead() with the same parameters.
4920 : *
4921 : * @param nXOff The pixel offset to the top left corner of the region
4922 : * of the band to be accessed. This would be zero to start from the left side.
4923 : *
4924 : * @param nYOff The line offset to the top left corner of the region
4925 : * of the band to be accessed. This would be zero to start from the top.
4926 : *
4927 : * @param nXSize The width of the region of the band to be accessed in pixels.
4928 : *
4929 : * @param nYSize The height of the region of the band to be accessed in lines.
4930 : *
4931 : * @param nBufXSize the width of the buffer image into which the desired region
4932 : * is to be read, or from which it is to be written.
4933 : *
4934 : * @param nBufYSize the height of the buffer image into which the desired
4935 : * region is to be read, or from which it is to be written.
4936 : *
4937 : * @param eBufType the type of the pixel values in the pData data buffer. The
4938 : * pixel values will automatically be translated to/from the GDALRasterBand
4939 : * data type as needed.
4940 : *
4941 : * @param papszOptions a list of name=value strings with special control
4942 : * options. Normally this is NULL.
4943 : *
4944 : * @return CE_Failure if the request is invalid and CE_None if it works or
4945 : * is ignored.
4946 : */
4947 :
4948 : /**/
4949 : /**/
4950 :
4951 41367 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
4952 : int /*nYSize*/, int /*nBufXSize*/,
4953 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
4954 : char ** /*papszOptions*/)
4955 : {
4956 41367 : return CE_None;
4957 : }
4958 :
4959 : /************************************************************************/
4960 : /* GDALRasterAdviseRead() */
4961 : /************************************************************************/
4962 :
4963 : /**
4964 : * \brief Advise driver of upcoming read requests.
4965 : *
4966 : * @see GDALRasterBand::AdviseRead()
4967 : */
4968 :
4969 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
4970 : int nYOff, int nXSize, int nYSize,
4971 : int nBufXSize, int nBufYSize,
4972 : GDALDataType eDT,
4973 : CSLConstList papszOptions)
4974 :
4975 : {
4976 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
4977 :
4978 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4979 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
4980 : nBufYSize, eDT,
4981 2 : const_cast<char **>(papszOptions));
4982 : }
4983 :
4984 : /************************************************************************/
4985 : /* GetStatistics() */
4986 : /************************************************************************/
4987 :
4988 : /**
4989 : * \brief Fetch image statistics.
4990 : *
4991 : * Returns the minimum, maximum, mean and standard deviation of all
4992 : * pixel values in this band. If approximate statistics are sufficient,
4993 : * the bApproxOK flag can be set to true in which case overviews, or a
4994 : * subset of image tiles may be used in computing the statistics.
4995 : *
4996 : * If bForce is FALSE results will only be returned if it can be done
4997 : * quickly (i.e. without scanning the image, typically by using pre-existing
4998 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
4999 : * returned efficiently, the method will return CE_Warning but no warning will
5000 : * be issued. This is a non-standard use of the CE_Warning return value
5001 : * to indicate "nothing done".
5002 : *
5003 : * If bForce is TRUE, and results are quickly available without scanning the
5004 : * image, they will be used. If bForce is TRUE and results are not quickly
5005 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5006 : * which will scan the image.
5007 : *
5008 : * To always force recomputation of statistics, use ComputeStatistics() instead
5009 : * of this method.
5010 : *
5011 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5012 : * will generally cache statistics in the .pam file allowing fast fetch
5013 : * after the first request.
5014 : *
5015 : * This method is the same as the C function GDALGetRasterStatistics().
5016 : *
5017 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5018 : * or a subset of all tiles.
5019 : *
5020 : * @param bForce If FALSE statistics will only be returned if it can
5021 : * be done without rescanning the image. If TRUE, statistics computation will
5022 : * be forced if pre-existing values are not quickly available.
5023 : *
5024 : * @param pdfMin Location into which to load image minimum (may be NULL).
5025 : *
5026 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5027 : *
5028 : * @param pdfMean Location into which to load image mean (may be NULL).
5029 : *
5030 : * @param pdfStdDev Location into which to load image standard deviation
5031 : * (may be NULL).
5032 : *
5033 : * @return CE_None on success, CE_Warning if no values returned,
5034 : * CE_Failure if an error occurs.
5035 : */
5036 :
5037 611 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5038 : double *pdfMax, double *pdfMean,
5039 : double *pdfStdDev)
5040 :
5041 : {
5042 : /* -------------------------------------------------------------------- */
5043 : /* Do we already have metadata items for the requested values? */
5044 : /* -------------------------------------------------------------------- */
5045 1222 : if ((pdfMin == nullptr ||
5046 611 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5047 202 : (pdfMax == nullptr ||
5048 202 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5049 1424 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5050 202 : (pdfStdDev == nullptr ||
5051 202 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5052 : {
5053 202 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5054 : {
5055 195 : if (pdfMin != nullptr)
5056 195 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5057 195 : if (pdfMax != nullptr)
5058 195 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5059 195 : if (pdfMean != nullptr)
5060 195 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5061 195 : if (pdfStdDev != nullptr)
5062 195 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5063 :
5064 195 : return CE_None;
5065 : }
5066 : }
5067 :
5068 : /* -------------------------------------------------------------------- */
5069 : /* Does the driver already know the min/max? */
5070 : /* -------------------------------------------------------------------- */
5071 416 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5072 : {
5073 0 : int bSuccessMin = FALSE;
5074 0 : int bSuccessMax = FALSE;
5075 :
5076 0 : const double dfMin = GetMinimum(&bSuccessMin);
5077 0 : const double dfMax = GetMaximum(&bSuccessMax);
5078 :
5079 0 : if (bSuccessMin && bSuccessMax)
5080 : {
5081 0 : if (pdfMin != nullptr)
5082 0 : *pdfMin = dfMin;
5083 0 : if (pdfMax != nullptr)
5084 0 : *pdfMax = dfMax;
5085 0 : return CE_None;
5086 : }
5087 : }
5088 :
5089 : /* -------------------------------------------------------------------- */
5090 : /* Either return without results, or force computation. */
5091 : /* -------------------------------------------------------------------- */
5092 416 : if (!bForce)
5093 161 : return CE_Warning;
5094 : else
5095 255 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5096 255 : GDALDummyProgress, nullptr);
5097 : }
5098 :
5099 : /************************************************************************/
5100 : /* GDALGetRasterStatistics() */
5101 : /************************************************************************/
5102 :
5103 : /**
5104 : * \brief Fetch image statistics.
5105 : *
5106 : * @see GDALRasterBand::GetStatistics()
5107 : */
5108 :
5109 260 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5110 : int bForce, double *pdfMin,
5111 : double *pdfMax, double *pdfMean,
5112 : double *pdfStdDev)
5113 :
5114 : {
5115 260 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5116 :
5117 260 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5118 260 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5119 260 : pdfStdDev);
5120 : }
5121 :
5122 : /************************************************************************/
5123 : /* GDALUInt128 */
5124 : /************************************************************************/
5125 :
5126 : #ifdef HAVE_UINT128_T
5127 : class GDALUInt128
5128 : {
5129 : __uint128_t val;
5130 :
5131 632 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5132 : {
5133 632 : }
5134 :
5135 : public:
5136 423 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5137 : {
5138 : // Evaluates to just a single mul on x86_64
5139 423 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5140 : }
5141 :
5142 211 : GDALUInt128 operator-(const GDALUInt128 &other) const
5143 : {
5144 211 : return GDALUInt128(val - other.val);
5145 : }
5146 :
5147 203 : operator double() const
5148 : {
5149 203 : return static_cast<double>(val);
5150 : }
5151 : };
5152 : #else
5153 :
5154 : #if defined(_MSC_VER) && defined(_M_X64)
5155 : #include <intrin.h>
5156 : #endif
5157 :
5158 : class GDALUInt128
5159 : {
5160 : GUIntBig low, high;
5161 :
5162 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5163 : {
5164 : }
5165 :
5166 : public:
5167 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5168 : {
5169 : #if defined(_MSC_VER) && defined(_M_X64)
5170 : GUIntBig highRes;
5171 : GUIntBig lowRes = _umul128(first, second, &highRes);
5172 : return GDALUInt128(lowRes, highRes);
5173 : #else
5174 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5175 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5176 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5177 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5178 : GUIntBig highRes = 0;
5179 : const GUIntBig firstLowSecondHigh =
5180 : static_cast<GUIntBig>(firstLow) * secondHigh;
5181 : const GUIntBig firstHighSecondLow =
5182 : static_cast<GUIntBig>(firstHigh) * secondLow;
5183 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5184 : if (middleTerm < firstLowSecondHigh) // check for overflow
5185 : highRes += static_cast<GUIntBig>(1) << 32;
5186 : const GUIntBig firstLowSecondLow =
5187 : static_cast<GUIntBig>(firstLow) * secondLow;
5188 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5189 : if (lowRes < firstLowSecondLow) // check for overflow
5190 : highRes++;
5191 : highRes +=
5192 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5193 : return GDALUInt128(lowRes, highRes);
5194 : #endif
5195 : }
5196 :
5197 : GDALUInt128 operator-(const GDALUInt128 &other) const
5198 : {
5199 : GUIntBig highRes = high - other.high;
5200 : GUIntBig lowRes = low - other.low;
5201 : if (lowRes > low) // check for underflow
5202 : --highRes;
5203 : return GDALUInt128(lowRes, highRes);
5204 : }
5205 :
5206 : operator double() const
5207 : {
5208 : const double twoPow64 = 18446744073709551616.0;
5209 : return high * twoPow64 + low;
5210 : }
5211 : };
5212 : #endif
5213 :
5214 : /************************************************************************/
5215 : /* ComputeStatisticsInternal() */
5216 : /************************************************************************/
5217 :
5218 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5219 : // not needed.
5220 : #define static_cast_for_coverity_scan static_cast
5221 :
5222 : // The rationale for below optimizations is detailed in statistics.txt
5223 :
5224 : // Use with T = GByte or GUInt16 only !
5225 : template <class T, bool COMPUTE_OTHER_STATS>
5226 : struct ComputeStatisticsInternalGeneric
5227 : {
5228 188 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5229 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5230 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5231 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5232 : {
5233 : static_assert(std::is_same<T, GByte>::value ||
5234 : std::is_same<T, GUInt16>::value,
5235 : "bad type for T");
5236 188 : if (bHasNoData)
5237 : {
5238 : // General case
5239 386 : for (int iY = 0; iY < nYCheck; iY++)
5240 : {
5241 81751 : for (int iX = 0; iX < nXCheck; iX++)
5242 : {
5243 81468 : const GPtrDiff_t iOffset =
5244 81468 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5245 81468 : const GUInt32 nValue = pData[iOffset];
5246 81468 : if (nValue == nNoDataValue)
5247 175 : continue;
5248 81293 : if (nValue < nMin)
5249 26 : nMin = nValue;
5250 81293 : if (nValue > nMax)
5251 57 : nMax = nValue;
5252 : if constexpr (COMPUTE_OTHER_STATS)
5253 : {
5254 79657 : nValidCount++;
5255 79657 : nSum += nValue;
5256 79657 : nSumSquare +=
5257 79657 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5258 79657 : nValue;
5259 : }
5260 : }
5261 : }
5262 : if constexpr (COMPUTE_OTHER_STATS)
5263 : {
5264 20 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5265 : }
5266 : }
5267 95 : else if (nMin == std::numeric_limits<T>::lowest() &&
5268 10 : nMax == std::numeric_limits<T>::max())
5269 : {
5270 : if constexpr (COMPUTE_OTHER_STATS)
5271 : {
5272 : // Optimization when there is no nodata and we know we have already
5273 : // reached the min and max
5274 208 : for (int iY = 0; iY < nYCheck; iY++)
5275 : {
5276 : int iX;
5277 1002 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5278 : {
5279 800 : const GPtrDiff_t iOffset =
5280 800 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5281 800 : const GUIntBig nValue = pData[iOffset];
5282 800 : const GUIntBig nValue2 = pData[iOffset + 1];
5283 800 : const GUIntBig nValue3 = pData[iOffset + 2];
5284 800 : const GUIntBig nValue4 = pData[iOffset + 3];
5285 800 : nSum += nValue;
5286 800 : nSumSquare += nValue * nValue;
5287 800 : nSum += nValue2;
5288 800 : nSumSquare += nValue2 * nValue2;
5289 800 : nSum += nValue3;
5290 800 : nSumSquare += nValue3 * nValue3;
5291 800 : nSum += nValue4;
5292 800 : nSumSquare += nValue4 * nValue4;
5293 : }
5294 207 : for (; iX < nXCheck; ++iX)
5295 : {
5296 5 : const GPtrDiff_t iOffset =
5297 5 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5298 5 : const GUIntBig nValue = pData[iOffset];
5299 5 : nSum += nValue;
5300 5 : nSumSquare += nValue * nValue;
5301 : }
5302 : }
5303 6 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5304 6 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5305 : }
5306 : }
5307 : else
5308 : {
5309 3378 : for (int iY = 0; iY < nYCheck; iY++)
5310 : {
5311 : int iX;
5312 635068 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5313 : {
5314 631769 : const GPtrDiff_t iOffset =
5315 631769 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5316 631769 : const GUInt32 nValue = pData[iOffset];
5317 631769 : const GUInt32 nValue2 = pData[iOffset + 1];
5318 631769 : if (nValue < nValue2)
5319 : {
5320 2160 : if (nValue < nMin)
5321 48 : nMin = nValue;
5322 2160 : if (nValue2 > nMax)
5323 108 : nMax = nValue2;
5324 : }
5325 : else
5326 : {
5327 629609 : if (nValue2 < nMin)
5328 61 : nMin = nValue2;
5329 629609 : if (nValue > nMax)
5330 212 : nMax = nValue;
5331 : }
5332 : if constexpr (COMPUTE_OTHER_STATS)
5333 : {
5334 624719 : nSum += nValue;
5335 624719 : nSumSquare +=
5336 624719 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5337 624719 : nValue;
5338 624719 : nSum += nValue2;
5339 624719 : nSumSquare +=
5340 624719 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5341 624719 : nValue2;
5342 : }
5343 : }
5344 3299 : if (iX < nXCheck)
5345 : {
5346 15 : const GPtrDiff_t iOffset =
5347 15 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5348 15 : const GUInt32 nValue = pData[iOffset];
5349 15 : if (nValue < nMin)
5350 10 : nMin = nValue;
5351 15 : if (nValue > nMax)
5352 11 : nMax = nValue;
5353 : if (COMPUTE_OTHER_STATS)
5354 : {
5355 9 : nSum += nValue;
5356 9 : nSumSquare +=
5357 9 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5358 9 : nValue;
5359 : }
5360 : }
5361 : }
5362 : if constexpr (COMPUTE_OTHER_STATS)
5363 : {
5364 28 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5365 28 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5366 : }
5367 : }
5368 188 : }
5369 : };
5370 :
5371 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5372 : // using 64bit accumulators in internal loops. This also slightly helps in
5373 : // 64bit mode.
5374 : template <bool COMPUTE_OTHER_STATS>
5375 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5376 : {
5377 11512 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5378 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5379 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5380 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5381 : {
5382 11512 : int nOuterLoops = nXCheck / 65536;
5383 11512 : if (nXCheck % 65536)
5384 11512 : nOuterLoops++;
5385 :
5386 11512 : if (bHasNoData)
5387 : {
5388 : // General case
5389 19454 : for (int iY = 0; iY < nYCheck; iY++)
5390 : {
5391 10890 : int iX = 0;
5392 21784 : for (int k = 0; k < nOuterLoops; k++)
5393 : {
5394 10894 : int iMax = iX + 65536;
5395 10894 : if (iMax > nXCheck)
5396 10893 : iMax = nXCheck;
5397 10894 : GUInt32 nSum32bit = 0;
5398 10894 : GUInt32 nSumSquare32bit = 0;
5399 10894 : GUInt32 nValidCount32bit = 0;
5400 10894 : GUInt32 nSampleCount32bit = 0;
5401 16704967 : for (; iX < iMax; iX++)
5402 : {
5403 16694122 : const GPtrDiff_t iOffset =
5404 16694122 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5405 16694122 : const GUInt32 nValue = pData[iOffset];
5406 :
5407 16694122 : nSampleCount32bit++;
5408 16694122 : if (nValue == nNoDataValue)
5409 16353363 : continue;
5410 340704 : if (nValue < nMin)
5411 335 : nMin = nValue;
5412 340704 : if (nValue > nMax)
5413 809 : nMax = nValue;
5414 : if constexpr (COMPUTE_OTHER_STATS)
5415 : {
5416 16959 : nValidCount32bit++;
5417 16959 : nSum32bit += nValue;
5418 16959 : nSumSquare32bit += nValue * nValue;
5419 : }
5420 : }
5421 : if constexpr (COMPUTE_OTHER_STATS)
5422 : {
5423 645 : nSampleCount += nSampleCount32bit;
5424 645 : nValidCount += nValidCount32bit;
5425 645 : nSum += nSum32bit;
5426 645 : nSumSquare += nSumSquare32bit;
5427 : }
5428 : }
5429 : }
5430 : }
5431 2948 : else if (nMin == 0 && nMax == 255)
5432 : {
5433 : if constexpr (COMPUTE_OTHER_STATS)
5434 : {
5435 : // Optimization when there is no nodata and we know we have already
5436 : // reached the min and max
5437 2644 : for (int iY = 0; iY < nYCheck; iY++)
5438 : {
5439 2617 : int iX = 0;
5440 5234 : for (int k = 0; k < nOuterLoops; k++)
5441 : {
5442 2617 : int iMax = iX + 65536;
5443 2617 : if (iMax > nXCheck)
5444 2617 : iMax = nXCheck;
5445 2617 : GUInt32 nSum32bit = 0;
5446 2617 : GUInt32 nSumSquare32bit = 0;
5447 176297 : for (; iX + 3 < iMax; iX += 4)
5448 : {
5449 173680 : const GPtrDiff_t iOffset =
5450 173680 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5451 173680 : const GUInt32 nValue = pData[iOffset];
5452 173680 : const GUInt32 nValue2 = pData[iOffset + 1];
5453 173680 : const GUInt32 nValue3 = pData[iOffset + 2];
5454 173680 : const GUInt32 nValue4 = pData[iOffset + 3];
5455 173680 : nSum32bit += nValue;
5456 173680 : nSumSquare32bit += nValue * nValue;
5457 173680 : nSum32bit += nValue2;
5458 173680 : nSumSquare32bit += nValue2 * nValue2;
5459 173680 : nSum32bit += nValue3;
5460 173680 : nSumSquare32bit += nValue3 * nValue3;
5461 173680 : nSum32bit += nValue4;
5462 173680 : nSumSquare32bit += nValue4 * nValue4;
5463 : }
5464 2617 : nSum += nSum32bit;
5465 2617 : nSumSquare += nSumSquare32bit;
5466 : }
5467 2620 : for (; iX < nXCheck; ++iX)
5468 : {
5469 3 : const GPtrDiff_t iOffset =
5470 3 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5471 3 : const GUIntBig nValue = pData[iOffset];
5472 3 : nSum += nValue;
5473 3 : nSumSquare += nValue * nValue;
5474 : }
5475 : }
5476 27 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5477 27 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5478 27 : }
5479 : }
5480 : else
5481 : {
5482 7496 : for (int iY = 0; iY < nYCheck; iY++)
5483 : {
5484 4575 : int iX = 0;
5485 9149 : for (int k = 0; k < nOuterLoops; k++)
5486 : {
5487 4574 : int iMax = iX + 65536;
5488 4574 : if (iMax > nXCheck)
5489 4574 : iMax = nXCheck;
5490 4574 : GUInt32 nSum32bit = 0;
5491 4574 : GUInt32 nSumSquare32bit = 0;
5492 159197 : for (; iX + 1 < iMax; iX += 2)
5493 : {
5494 154623 : const GPtrDiff_t iOffset =
5495 154623 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5496 154623 : const GUInt32 nValue = pData[iOffset];
5497 154623 : const GUInt32 nValue2 = pData[iOffset + 1];
5498 154623 : if (nValue < nValue2)
5499 : {
5500 8100 : if (nValue < nMin)
5501 232 : nMin = nValue;
5502 8100 : if (nValue2 > nMax)
5503 219 : nMax = nValue2;
5504 : }
5505 : else
5506 : {
5507 146523 : if (nValue2 < nMin)
5508 277 : nMin = nValue2;
5509 146523 : if (nValue > nMax)
5510 779 : nMax = nValue;
5511 : }
5512 : if constexpr (COMPUTE_OTHER_STATS)
5513 : {
5514 132603 : nSum32bit += nValue;
5515 132603 : nSumSquare32bit += nValue * nValue;
5516 132603 : nSum32bit += nValue2;
5517 132603 : nSumSquare32bit += nValue2 * nValue2;
5518 : }
5519 : }
5520 : if constexpr (COMPUTE_OTHER_STATS)
5521 : {
5522 1628 : nSum += nSum32bit;
5523 1628 : nSumSquare += nSumSquare32bit;
5524 : }
5525 : }
5526 4575 : if (iX < nXCheck)
5527 : {
5528 1400 : const GPtrDiff_t iOffset =
5529 1400 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5530 1400 : const GUInt32 nValue = pData[iOffset];
5531 1400 : if (nValue < nMin)
5532 50 : nMin = nValue;
5533 1400 : if (nValue > nMax)
5534 62 : nMax = nValue;
5535 : if constexpr (COMPUTE_OTHER_STATS)
5536 : {
5537 312 : nSum += nValue;
5538 312 : nSumSquare +=
5539 312 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5540 312 : nValue;
5541 : }
5542 : }
5543 : }
5544 : if constexpr (COMPUTE_OTHER_STATS)
5545 : {
5546 933 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5547 933 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5548 : }
5549 : }
5550 11512 : }
5551 : };
5552 :
5553 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5554 : {
5555 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5556 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5557 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5558 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5559 : {
5560 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5561 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5562 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5563 : }
5564 : };
5565 :
5566 : #if (defined(__x86_64__) || defined(_M_X64)) && \
5567 : (defined(__GNUC__) || defined(_MSC_VER))
5568 :
5569 : #include "gdal_avx2_emulation.hpp"
5570 :
5571 : #define ZERO256 GDALmm256_setzero_si256()
5572 :
5573 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5574 : static void
5575 20929 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5576 : // assumed to be aligned on 256 bits
5577 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5578 : GUIntBig &nSum, GUIntBig &nSumSquare,
5579 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5580 : {
5581 : // 32-byte alignment may not be enforced by linker, so do it at hand
5582 : GByte
5583 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5584 20929 : GByte *paby32ByteAligned =
5585 : aby32ByteUnaligned +
5586 20929 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5587 20929 : GByte *pabyMin = paby32ByteAligned;
5588 20929 : GByte *pabyMax = paby32ByteAligned + 32;
5589 20929 : GUInt32 *panSum =
5590 : COMPUTE_OTHER_STATS
5591 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5592 : : nullptr;
5593 20929 : GUInt32 *panSumSquare =
5594 : COMPUTE_OTHER_STATS
5595 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5596 : : nullptr;
5597 :
5598 20929 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5599 :
5600 20929 : GPtrDiff_t i = 0;
5601 : // Make sure that sumSquare can fit on uint32
5602 : // * 8 since we can hold 8 sums per vector register
5603 20929 : const int nMaxIterationsPerInnerLoop =
5604 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5605 20929 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5606 20929 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5607 20929 : nOuterLoops++;
5608 :
5609 : GDALm256i ymm_min =
5610 20929 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5611 20929 : GDALm256i ymm_max = ymm_min;
5612 20929 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5613 :
5614 41858 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5615 : {
5616 20929 : const auto iMax =
5617 20929 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5618 :
5619 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5620 20929 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5621 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5622 20929 : ZERO256; // holds 8 uint32 sums
5623 705486 : for (; i + 31 < iMax; i += 32)
5624 : {
5625 684557 : const GDALm256i ymm = GDALmm256_load_si256(
5626 684557 : reinterpret_cast<const GDALm256i *>(pData + i));
5627 : if (COMPUTE_MIN)
5628 : {
5629 226720 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5630 : }
5631 : if (COMPUTE_MAX)
5632 : {
5633 593616 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5634 : }
5635 :
5636 : if constexpr (COMPUTE_OTHER_STATS)
5637 : {
5638 : // Extract even-8bit values
5639 : const GDALm256i ymm_even =
5640 493495 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5641 : // Compute square of those 16 values as 32 bit result
5642 : // and add adjacent pairs
5643 : const GDALm256i ymm_even_square =
5644 493495 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5645 : // Add to the sumsquare accumulator
5646 : ymm_sumsquare =
5647 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5648 :
5649 : // Extract odd-8bit values
5650 493495 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5651 : const GDALm256i ymm_odd_square =
5652 493495 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5653 : ymm_sumsquare =
5654 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5655 :
5656 : // Now compute the sums
5657 493495 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5658 : GDALmm256_sad_epu8(ymm, ZERO256));
5659 : }
5660 : }
5661 :
5662 : if constexpr (COMPUTE_OTHER_STATS)
5663 : {
5664 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5665 : ymm_sum);
5666 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5667 : ymm_sumsquare);
5668 :
5669 10649 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5670 10649 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5671 10649 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5672 10649 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5673 : panSumSquare[7];
5674 : }
5675 : }
5676 :
5677 : if constexpr (COMPUTE_MIN)
5678 : {
5679 8055 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5680 : }
5681 : if constexpr (COMPUTE_MAX)
5682 : {
5683 16932 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5684 : }
5685 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5686 : {
5687 576246 : for (int j = 0; j < 32; j++)
5688 : {
5689 : if constexpr (COMPUTE_MIN)
5690 : {
5691 257760 : if (pabyMin[j] < nMin)
5692 1242 : nMin = pabyMin[j];
5693 : }
5694 : if constexpr (COMPUTE_MAX)
5695 : {
5696 541824 : if (pabyMax[j] > nMax)
5697 1790 : nMax = pabyMax[j];
5698 : }
5699 : }
5700 : }
5701 :
5702 227563 : for (; i < nBlockPixels; i++)
5703 : {
5704 206634 : const GUInt32 nValue = pData[i];
5705 : if constexpr (COMPUTE_MIN)
5706 : {
5707 81958 : if (nValue < nMin)
5708 1 : nMin = nValue;
5709 : }
5710 : if constexpr (COMPUTE_MAX)
5711 : {
5712 203859 : if (nValue > nMax)
5713 1149 : nMax = nValue;
5714 : }
5715 : if constexpr (COMPUTE_OTHER_STATS)
5716 : {
5717 77195 : nSum += nValue;
5718 77195 : nSumSquare +=
5719 77195 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5720 : }
5721 : }
5722 :
5723 : if constexpr (COMPUTE_OTHER_STATS)
5724 : {
5725 10649 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5726 10649 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5727 : }
5728 20929 : }
5729 :
5730 : // SSE2/AVX2 optimization for GByte case
5731 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5732 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5733 : // there are strictly equivalent to 2 parallel SSE2 streams.
5734 : template <bool COMPUTE_OTHER_STATS>
5735 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5736 : {
5737 27854 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5738 : // assumed to be aligned on 256 bits
5739 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5740 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5741 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5742 : GUIntBig &nValidCount)
5743 : {
5744 27854 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5745 27854 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5746 9452 : nMin <= nMax)
5747 : {
5748 : // 32-byte alignment may not be enforced by linker, so do it at hand
5749 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5750 1339 : GByte *paby32ByteAligned =
5751 : aby32ByteUnaligned +
5752 1339 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5753 1339 : GByte *pabyMin = paby32ByteAligned;
5754 1339 : GByte *pabyMax = paby32ByteAligned + 32;
5755 1339 : GUInt32 *panSum =
5756 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5757 1339 : GUInt32 *panSumSquare =
5758 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5759 :
5760 1339 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5761 :
5762 1339 : GPtrDiff_t i = 0;
5763 : // Make sure that sumSquare can fit on uint32
5764 : // * 8 since we can hold 8 sums per vector register
5765 1339 : const int nMaxIterationsPerInnerLoop =
5766 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5767 1339 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5768 1339 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5769 1339 : nOuterLoops++;
5770 :
5771 : const GDALm256i ymm_nodata =
5772 1339 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5773 : // any non noData value in [min,max] would do.
5774 : const GDALm256i ymm_neutral =
5775 1339 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5776 1339 : GDALm256i ymm_min = ymm_neutral;
5777 1339 : GDALm256i ymm_max = ymm_neutral;
5778 : [[maybe_unused]] const auto ymm_mask_8bits =
5779 1339 : GDALmm256_set1_epi16(0xFF);
5780 :
5781 1339 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5782 1339 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5783 1339 : const bool bComputeMinMax =
5784 1339 : nMin > nMinThreshold || nMax < nMaxThreshold;
5785 :
5786 2678 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5787 : {
5788 1339 : const auto iMax =
5789 1339 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5790 :
5791 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5792 1339 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5793 : // holds 8 uint32 sums
5794 1339 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5795 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5796 1339 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5797 1339 : const auto iInit = i;
5798 14195 : for (; i + 31 < iMax; i += 32)
5799 : {
5800 12856 : const GDALm256i ymm = GDALmm256_load_si256(
5801 12856 : reinterpret_cast<const GDALm256i *>(pData + i));
5802 :
5803 : // Check which values are nodata
5804 : const GDALm256i ymm_eq_nodata =
5805 12856 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5806 : if constexpr (COMPUTE_OTHER_STATS)
5807 : {
5808 : // Count how many values are nodata (due to cmpeq
5809 : // putting 255 when condition is met, this will actually
5810 : // be 255 times the number of nodata value, spread in 4
5811 : // 64 bits words). We can use add_epi32 as the counter
5812 : // will not overflow uint32
5813 4514 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5814 : ymm_count_nodata_mul_255,
5815 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5816 : }
5817 : // Replace all nodata values by zero for the purpose of sum
5818 : // and sumquare.
5819 : const GDALm256i ymm_nodata_by_zero =
5820 12856 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5821 12856 : if (bComputeMinMax)
5822 : {
5823 : // Replace all nodata values by a neutral value for the
5824 : // purpose of min and max.
5825 : const GDALm256i ymm_nodata_by_neutral =
5826 8471 : GDALmm256_or_si256(
5827 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5828 : ymm_nodata_by_zero);
5829 :
5830 : ymm_min =
5831 8471 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5832 : ymm_max =
5833 8471 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
5834 : }
5835 :
5836 : if constexpr (COMPUTE_OTHER_STATS)
5837 : {
5838 : // Extract even-8bit values
5839 4514 : const GDALm256i ymm_even = GDALmm256_and_si256(
5840 : ymm_nodata_by_zero, ymm_mask_8bits);
5841 : // Compute square of those 16 values as 32 bit result
5842 : // and add adjacent pairs
5843 : const GDALm256i ymm_even_square =
5844 4514 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5845 : // Add to the sumsquare accumulator
5846 : ymm_sumsquare =
5847 4514 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5848 :
5849 : // Extract odd-8bit values
5850 : const GDALm256i ymm_odd =
5851 4514 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
5852 : const GDALm256i ymm_odd_square =
5853 4514 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5854 : ymm_sumsquare =
5855 4514 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5856 :
5857 : // Now compute the sums
5858 4514 : ymm_sum = GDALmm256_add_epi32(
5859 : ymm_sum,
5860 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
5861 : }
5862 : }
5863 :
5864 : if constexpr (COMPUTE_OTHER_STATS)
5865 : {
5866 33 : GUInt32 *panCoutNoDataMul255 = panSum;
5867 33 : GDALmm256_store_si256(
5868 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
5869 : ymm_count_nodata_mul_255);
5870 :
5871 33 : nSampleCount += (i - iInit);
5872 :
5873 33 : nValidCount +=
5874 33 : (i - iInit) -
5875 33 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
5876 33 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
5877 : 255;
5878 :
5879 33 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5880 : ymm_sum);
5881 33 : GDALmm256_store_si256(
5882 : reinterpret_cast<GDALm256i *>(panSumSquare),
5883 : ymm_sumsquare);
5884 33 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5885 33 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5886 33 : panSumSquare[1] + panSumSquare[2] +
5887 33 : panSumSquare[3] + panSumSquare[4] +
5888 33 : panSumSquare[5] + panSumSquare[6] +
5889 : panSumSquare[7];
5890 : }
5891 : }
5892 :
5893 1339 : if (bComputeMinMax)
5894 : {
5895 1308 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
5896 : ymm_min);
5897 1308 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
5898 : ymm_max);
5899 43164 : for (int j = 0; j < 32; j++)
5900 : {
5901 41856 : if (pabyMin[j] < nMin)
5902 32 : nMin = pabyMin[j];
5903 41856 : if (pabyMax[j] > nMax)
5904 157 : nMax = pabyMax[j];
5905 : }
5906 : }
5907 :
5908 : if constexpr (COMPUTE_OTHER_STATS)
5909 : {
5910 33 : nSampleCount += nBlockPixels - i;
5911 : }
5912 30305 : for (; i < nBlockPixels; i++)
5913 : {
5914 28966 : const GUInt32 nValue = pData[i];
5915 28966 : if (nValue == nNoDataValue)
5916 24923 : continue;
5917 4043 : if (nValue < nMin)
5918 1 : nMin = nValue;
5919 4043 : if (nValue > nMax)
5920 13 : nMax = nValue;
5921 : if constexpr (COMPUTE_OTHER_STATS)
5922 : {
5923 110 : nValidCount++;
5924 110 : nSum += nValue;
5925 110 : nSumSquare +=
5926 110 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5927 110 : nValue;
5928 : }
5929 1339 : }
5930 : }
5931 26515 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
5932 : {
5933 14973 : if (nMin > 0)
5934 : {
5935 2099 : if (nMax < 255)
5936 : {
5937 : ComputeStatisticsByteNoNodata<true, true,
5938 1569 : COMPUTE_OTHER_STATS>(
5939 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5940 : nSampleCount, nValidCount);
5941 : }
5942 : else
5943 : {
5944 : ComputeStatisticsByteNoNodata<true, false,
5945 530 : COMPUTE_OTHER_STATS>(
5946 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5947 : nSampleCount, nValidCount);
5948 : }
5949 : }
5950 : else
5951 : {
5952 12874 : if (nMax < 255)
5953 : {
5954 : ComputeStatisticsByteNoNodata<false, true,
5955 9407 : COMPUTE_OTHER_STATS>(
5956 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5957 : nSampleCount, nValidCount);
5958 : }
5959 : else
5960 : {
5961 : ComputeStatisticsByteNoNodata<false, false,
5962 3467 : COMPUTE_OTHER_STATS>(
5963 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5964 : nSampleCount, nValidCount);
5965 : }
5966 : }
5967 : }
5968 10274 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
5969 31 : (nBlockXSize % 32) == 0)
5970 : {
5971 5987 : for (int iY = 0; iY < nYCheck; iY++)
5972 : {
5973 5956 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
5974 5956 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
5975 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5976 31 : }
5977 : }
5978 : else
5979 : {
5980 11511 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
5981 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5982 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5983 : }
5984 27856 : }
5985 : };
5986 :
5987 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
5988 404 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
5989 : GUIntBig i)
5990 : {
5991 404 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
5992 404 : }
5993 :
5994 : // AVX2/SSE2 optimization for GUInt16 case
5995 : template <bool COMPUTE_OTHER_STATS>
5996 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
5997 : {
5998 1354 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5999 : // assumed to be aligned on 128 bits
6000 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6001 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6002 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6003 : GUIntBig &nValidCount)
6004 : {
6005 1354 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6006 1354 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6007 : {
6008 1166 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6009 :
6010 1166 : GPtrDiff_t i = 0;
6011 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6012 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6013 : // Furthermore the shift is also needed to use madd_epi16
6014 1166 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6015 1166 : GDALm256i ymm_min = GDALmm256_load_si256(
6016 1166 : reinterpret_cast<const GDALm256i *>(pData + i));
6017 1166 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6018 1166 : GDALm256i ymm_max = ymm_min;
6019 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6020 1166 : ZERO256; // holds 4 uint64 sums
6021 :
6022 : // Make sure that sum can fit on uint32
6023 : // * 8 since we can hold 8 sums per vector register
6024 1166 : const int nMaxIterationsPerInnerLoop =
6025 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6026 1166 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6027 1166 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6028 1166 : nOuterLoops++;
6029 :
6030 1166 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6031 : [[maybe_unused]] const auto ymm_mask_16bits =
6032 1166 : GDALmm256_set1_epi32(0xFFFF);
6033 : [[maybe_unused]] const auto ymm_mask_32bits =
6034 1166 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6035 :
6036 1166 : GUIntBig nSumThis = 0;
6037 2356 : for (int k = 0; k < nOuterLoops; k++)
6038 : {
6039 1190 : const auto iMax =
6040 1190 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6041 :
6042 : [[maybe_unused]] GDALm256i ymm_sum =
6043 1190 : ZERO256; // holds 8 uint32 sums
6044 959522 : for (; i + 15 < iMax; i += 16)
6045 : {
6046 958332 : const GDALm256i ymm = GDALmm256_load_si256(
6047 958332 : reinterpret_cast<const GDALm256i *>(pData + i));
6048 : const GDALm256i ymm_shifted =
6049 958332 : GDALmm256_add_epi16(ymm, ymm_m32768);
6050 958332 : if (bComputeMinMax)
6051 : {
6052 949313 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6053 949313 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6054 : }
6055 :
6056 : if constexpr (COMPUTE_OTHER_STATS)
6057 : {
6058 : // Note: the int32 range can overflow for (0-32768)^2 +
6059 : // (0-32768)^2 = 0x80000000, but as we know the result
6060 : // is positive, this is OK as we interpret is a uint32.
6061 : const GDALm256i ymm_square =
6062 99506 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6063 99506 : ymm_sumsquare = GDALmm256_add_epi64(
6064 : ymm_sumsquare,
6065 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6066 99506 : ymm_sumsquare = GDALmm256_add_epi64(
6067 : ymm_sumsquare,
6068 : GDALmm256_srli_epi64(ymm_square, 32));
6069 :
6070 : // Now compute the sums
6071 99506 : ymm_sum = GDALmm256_add_epi32(
6072 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6073 99506 : ymm_sum = GDALmm256_add_epi32(
6074 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6075 : }
6076 : }
6077 :
6078 : if constexpr (COMPUTE_OTHER_STATS)
6079 : {
6080 : GUInt32 anSum[8];
6081 404 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6082 : ymm_sum);
6083 404 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6084 404 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6085 404 : anSum[6] + anSum[7];
6086 : }
6087 : }
6088 :
6089 1166 : if (bComputeMinMax)
6090 : {
6091 : GUInt16 anMin[16];
6092 : GUInt16 anMax[16];
6093 :
6094 : // Unshift the result
6095 1125 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6096 1125 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6097 1125 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6098 : ymm_min);
6099 1125 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6100 : ymm_max);
6101 19125 : for (int j = 0; j < 16; j++)
6102 : {
6103 18000 : if (anMin[j] < nMin)
6104 344 : nMin = anMin[j];
6105 18000 : if (anMax[j] > nMax)
6106 482 : nMax = anMax[j];
6107 : }
6108 : }
6109 :
6110 : if constexpr (COMPUTE_OTHER_STATS)
6111 : {
6112 : GUIntBig anSumSquare[4];
6113 404 : GDALmm256_storeu_si256(
6114 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6115 404 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6116 : anSumSquare[3];
6117 :
6118 : // Unshift the sum of squares
6119 404 : UnshiftSumSquare(nSumSquare, nSumThis,
6120 : static_cast<GUIntBig>(i));
6121 :
6122 404 : nSum += nSumThis;
6123 :
6124 726 : for (; i < nBlockPixels; i++)
6125 : {
6126 322 : const GUInt32 nValue = pData[i];
6127 322 : if (nValue < nMin)
6128 1 : nMin = nValue;
6129 322 : if (nValue > nMax)
6130 1 : nMax = nValue;
6131 322 : nSum += nValue;
6132 322 : nSumSquare +=
6133 322 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6134 322 : nValue;
6135 : }
6136 :
6137 404 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6138 404 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6139 1166 : }
6140 : }
6141 : else
6142 : {
6143 188 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6144 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6145 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6146 : }
6147 1354 : }
6148 : };
6149 :
6150 : #endif
6151 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6152 : // defined(_MSC_VER))
6153 :
6154 : /************************************************************************/
6155 : /* GetPixelValue() */
6156 : /************************************************************************/
6157 :
6158 23152800 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6159 : const void *pData, GPtrDiff_t iOffset,
6160 : const GDALNoDataValues &sNoDataValues,
6161 : bool &bValid)
6162 : {
6163 23152800 : bValid = true;
6164 23152800 : double dfValue = 0;
6165 23152800 : switch (eDataType)
6166 : {
6167 1413680 : case GDT_Byte:
6168 : {
6169 1413680 : if (bSignedByte)
6170 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6171 : else
6172 1413490 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6173 1413680 : break;
6174 : }
6175 10409 : case GDT_Int8:
6176 10409 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6177 10409 : break;
6178 4000 : case GDT_UInt16:
6179 4000 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6180 4000 : break;
6181 60192 : case GDT_Int16:
6182 60192 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6183 60192 : break;
6184 27600 : case GDT_UInt32:
6185 27600 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6186 27600 : break;
6187 455610 : case GDT_Int32:
6188 455610 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6189 455610 : break;
6190 2602 : case GDT_UInt64:
6191 2602 : dfValue = static_cast<double>(
6192 2602 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6193 2602 : break;
6194 7402 : case GDT_Int64:
6195 7402 : dfValue = static_cast<double>(
6196 7402 : static_cast<const std::int64_t *>(pData)[iOffset]);
6197 7402 : break;
6198 0 : case GDT_Float16:
6199 : {
6200 0 : const GFloat16 hfValue =
6201 0 : static_cast<const GFloat16 *>(pData)[iOffset];
6202 0 : if (CPLIsNan(hfValue) ||
6203 0 : (sNoDataValues.bGotFloat16NoDataValue &&
6204 0 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6205 : {
6206 0 : bValid = false;
6207 0 : return 0.0;
6208 : }
6209 0 : dfValue = hfValue;
6210 0 : return dfValue;
6211 : }
6212 17477400 : case GDT_Float32:
6213 : {
6214 17477400 : const float fValue = static_cast<const float *>(pData)[iOffset];
6215 34927900 : if (CPLIsNan(fValue) ||
6216 30655700 : (sNoDataValues.bGotFloatNoDataValue &&
6217 13205200 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6218 : {
6219 119863 : bValid = false;
6220 119863 : return 0.0;
6221 : }
6222 17357500 : dfValue = fValue;
6223 17357500 : return dfValue;
6224 : }
6225 3676860 : case GDT_Float64:
6226 3676860 : dfValue = static_cast<const double *>(pData)[iOffset];
6227 3676860 : if (std::isnan(dfValue))
6228 : {
6229 52 : bValid = false;
6230 52 : return 0.0;
6231 : }
6232 3676800 : break;
6233 2692 : case GDT_CInt16:
6234 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6235 2692 : break;
6236 2692 : case GDT_CInt32:
6237 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6238 2692 : break;
6239 0 : case GDT_CFloat16:
6240 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6241 0 : if (isnan(dfValue))
6242 : {
6243 0 : bValid = false;
6244 0 : return 0.0;
6245 : }
6246 0 : break;
6247 5812 : case GDT_CFloat32:
6248 5812 : dfValue = static_cast<const float *>(pData)[iOffset * 2];
6249 5812 : if (std::isnan(dfValue))
6250 : {
6251 0 : bValid = false;
6252 0 : return 0.0;
6253 : }
6254 5812 : break;
6255 5892 : case GDT_CFloat64:
6256 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6257 5892 : if (std::isnan(dfValue))
6258 : {
6259 0 : bValid = false;
6260 0 : return 0.0;
6261 : }
6262 5892 : break;
6263 0 : case GDT_Unknown:
6264 : case GDT_TypeCount:
6265 0 : CPLAssert(false);
6266 : break;
6267 : }
6268 :
6269 9414380 : if (sNoDataValues.bGotNoDataValue &&
6270 3738990 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6271 : {
6272 3346220 : bValid = false;
6273 3346220 : return 0.0;
6274 : }
6275 2329170 : return dfValue;
6276 : }
6277 :
6278 : /************************************************************************/
6279 : /* SetValidPercent() */
6280 : /************************************************************************/
6281 :
6282 : //! @cond Doxygen_Suppress
6283 : /**
6284 : * \brief Set percentage of valid (not nodata) pixels.
6285 : *
6286 : * Stores the percentage of valid pixels in the metadata item
6287 : * STATISTICS_VALID_PERCENT
6288 : *
6289 : * @param nSampleCount Number of sampled pixels.
6290 : *
6291 : * @param nValidCount Number of valid pixels.
6292 : */
6293 :
6294 469 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6295 : GUIntBig nValidCount)
6296 : {
6297 469 : if (nValidCount == 0)
6298 : {
6299 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6300 : }
6301 457 : else if (nValidCount == nSampleCount)
6302 : {
6303 414 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6304 : }
6305 : else /* nValidCount < nSampleCount */
6306 : {
6307 43 : char szValue[128] = {0};
6308 :
6309 : /* percentage is only an indicator: limit precision */
6310 43 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6311 43 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6312 :
6313 43 : if (EQUAL(szValue, "100"))
6314 : {
6315 : /* don't set 100 percent valid
6316 : * because some of the sampled pixels were nodata */
6317 0 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6318 : }
6319 : else
6320 : {
6321 43 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6322 : }
6323 : }
6324 469 : }
6325 :
6326 : //! @endcond
6327 :
6328 : /************************************************************************/
6329 : /* ComputeStatistics() */
6330 : /************************************************************************/
6331 :
6332 : /**
6333 : * \brief Compute image statistics.
6334 : *
6335 : * Returns the minimum, maximum, mean and standard deviation of all
6336 : * pixel values in this band. If approximate statistics are sufficient,
6337 : * the bApproxOK flag can be set to true in which case overviews, or a
6338 : * subset of image tiles may be used in computing the statistics.
6339 : *
6340 : * Once computed, the statistics will generally be "set" back on the
6341 : * raster band using SetStatistics().
6342 : *
6343 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6344 : *
6345 : * This method is the same as the C function GDALComputeRasterStatistics().
6346 : *
6347 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6348 : * or a subset of all tiles.
6349 : *
6350 : * @param pdfMin Location into which to load image minimum (may be NULL).
6351 : *
6352 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6353 : *
6354 : * @param pdfMean Location into which to load image mean (may be NULL).
6355 : *
6356 : * @param pdfStdDev Location into which to load image standard deviation
6357 : * (may be NULL).
6358 : *
6359 : * @param pfnProgress a function to call to report progress, or NULL.
6360 : *
6361 : * @param pProgressData application data to pass to the progress function.
6362 : *
6363 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6364 : * is terminated by the user.
6365 : */
6366 :
6367 453 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6368 : double *pdfMax, double *pdfMean,
6369 : double *pdfStdDev,
6370 : GDALProgressFunc pfnProgress,
6371 : void *pProgressData)
6372 :
6373 : {
6374 453 : if (pfnProgress == nullptr)
6375 155 : pfnProgress = GDALDummyProgress;
6376 :
6377 : /* -------------------------------------------------------------------- */
6378 : /* If we have overview bands, use them for statistics. */
6379 : /* -------------------------------------------------------------------- */
6380 453 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6381 : {
6382 : GDALRasterBand *poBand =
6383 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6384 :
6385 3 : if (poBand != this)
6386 : {
6387 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6388 : pdfMean, pdfStdDev,
6389 3 : pfnProgress, pProgressData);
6390 3 : if (eErr == CE_None)
6391 : {
6392 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6393 : {
6394 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6395 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6396 : }
6397 :
6398 : /* transfer metadata from overview band to this */
6399 : const char *pszPercentValid =
6400 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6401 :
6402 3 : if (pszPercentValid != nullptr)
6403 : {
6404 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6405 3 : pszPercentValid);
6406 : }
6407 : }
6408 3 : return eErr;
6409 : }
6410 : }
6411 :
6412 450 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6413 : {
6414 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6415 0 : return CE_Failure;
6416 : }
6417 :
6418 : /* -------------------------------------------------------------------- */
6419 : /* Read actual data and compute statistics. */
6420 : /* -------------------------------------------------------------------- */
6421 : // Using Welford algorithm:
6422 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6423 : // to compute standard deviation in a more numerically robust way than
6424 : // the difference of the sum of square values with the square of the sum.
6425 : // dfMean and dfM2 are updated at each sample.
6426 : // dfM2 is the sum of square of differences to the current mean.
6427 448 : double dfMin = std::numeric_limits<double>::max();
6428 448 : double dfMax = -std::numeric_limits<double>::max();
6429 448 : double dfMean = 0.0;
6430 448 : double dfM2 = 0.0;
6431 :
6432 : GDALRasterIOExtraArg sExtraArg;
6433 448 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6434 :
6435 448 : GDALNoDataValues sNoDataValues(this, eDataType);
6436 449 : GDALRasterBand *poMaskBand = nullptr;
6437 449 : if (!sNoDataValues.bGotNoDataValue)
6438 : {
6439 425 : const int l_nMaskFlags = GetMaskFlags();
6440 441 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
6441 16 : GetColorInterpretation() != GCI_AlphaBand)
6442 : {
6443 16 : poMaskBand = GetMaskBand();
6444 : }
6445 : }
6446 :
6447 449 : bool bSignedByte = false;
6448 449 : if (eDataType == GDT_Byte)
6449 : {
6450 198 : EnablePixelTypeSignedByteWarning(false);
6451 : const char *pszPixelType =
6452 198 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6453 195 : EnablePixelTypeSignedByteWarning(true);
6454 196 : bSignedByte =
6455 196 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6456 : }
6457 :
6458 447 : GUIntBig nSampleCount = 0;
6459 447 : GUIntBig nValidCount = 0;
6460 :
6461 447 : if (bApproxOK && HasArbitraryOverviews())
6462 : {
6463 : /* --------------------------------------------------------------------
6464 : */
6465 : /* Figure out how much the image should be reduced to get an */
6466 : /* approximate value. */
6467 : /* --------------------------------------------------------------------
6468 : */
6469 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6470 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6471 :
6472 0 : int nXReduced = nRasterXSize;
6473 0 : int nYReduced = nRasterYSize;
6474 0 : if (dfReduction > 1.0)
6475 : {
6476 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6477 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6478 :
6479 : // Catch the case of huge resizing ratios here
6480 0 : if (nXReduced == 0)
6481 0 : nXReduced = 1;
6482 0 : if (nYReduced == 0)
6483 0 : nYReduced = 1;
6484 : }
6485 :
6486 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
6487 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6488 :
6489 : const CPLErr eErr =
6490 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6491 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6492 0 : if (eErr != CE_None)
6493 : {
6494 0 : CPLFree(pData);
6495 0 : return eErr;
6496 : }
6497 :
6498 0 : GByte *pabyMaskData = nullptr;
6499 0 : if (poMaskBand)
6500 : {
6501 : pabyMaskData =
6502 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6503 0 : if (!pabyMaskData)
6504 : {
6505 0 : CPLFree(pData);
6506 0 : return CE_Failure;
6507 : }
6508 :
6509 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6510 : pabyMaskData, nXReduced, nYReduced,
6511 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
6512 : {
6513 0 : CPLFree(pData);
6514 0 : CPLFree(pabyMaskData);
6515 0 : return CE_Failure;
6516 : }
6517 : }
6518 :
6519 : /* this isn't the fastest way to do this, but is easier for now */
6520 0 : for (int iY = 0; iY < nYReduced; iY++)
6521 : {
6522 0 : for (int iX = 0; iX < nXReduced; iX++)
6523 : {
6524 0 : const int iOffset = iX + iY * nXReduced;
6525 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6526 0 : continue;
6527 :
6528 0 : bool bValid = true;
6529 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
6530 0 : iOffset, sNoDataValues, bValid);
6531 0 : if (!bValid)
6532 0 : continue;
6533 :
6534 0 : dfMin = std::min(dfMin, dfValue);
6535 0 : dfMax = std::max(dfMax, dfValue);
6536 :
6537 0 : nValidCount++;
6538 0 : const double dfDelta = dfValue - dfMean;
6539 0 : dfMean += dfDelta / nValidCount;
6540 0 : dfM2 += dfDelta * (dfValue - dfMean);
6541 : }
6542 : }
6543 :
6544 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6545 :
6546 0 : CPLFree(pData);
6547 0 : CPLFree(pabyMaskData);
6548 : }
6549 :
6550 : else // No arbitrary overviews.
6551 : {
6552 447 : if (!InitBlockInfo())
6553 0 : return CE_Failure;
6554 :
6555 : /* --------------------------------------------------------------------
6556 : */
6557 : /* Figure out the ratio of blocks we will read to get an */
6558 : /* approximate value. */
6559 : /* --------------------------------------------------------------------
6560 : */
6561 449 : int nSampleRate = 1;
6562 449 : if (bApproxOK)
6563 : {
6564 42 : nSampleRate = static_cast<int>(std::max(
6565 84 : 1.0,
6566 42 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6567 : // We want to avoid probing only the first column of blocks for
6568 : // a square shaped raster, because it is not unlikely that it may
6569 : // be padding only (#6378)
6570 42 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6571 2 : nSampleRate += 1;
6572 : }
6573 449 : if (nSampleRate == 1)
6574 413 : bApproxOK = false;
6575 :
6576 : // Particular case for GDT_Byte that only use integral types for all
6577 : // intermediate computations. Only possible if the number of pixels
6578 : // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6579 : // can fit on a uint64. Should be 99.99999% of cases.
6580 : // For GUInt16, this limits to raster of 4 giga pixels
6581 449 : if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6582 181 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6583 181 : nSampleRate <
6584 181 : GUINTBIG_MAX / (255U * 255U) /
6585 181 : (static_cast<GUInt64>(nBlockXSize) *
6586 181 : static_cast<GUInt64>(nBlockYSize))) ||
6587 268 : (eDataType == GDT_UInt16 &&
6588 29 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6589 29 : nSampleRate <
6590 29 : GUINTBIG_MAX / (65535U * 65535U) /
6591 29 : (static_cast<GUInt64>(nBlockXSize) *
6592 29 : static_cast<GUInt64>(nBlockYSize))))
6593 : {
6594 209 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6595 209 : GUInt32 nMin = nMaxValueType;
6596 209 : GUInt32 nMax = 0;
6597 209 : GUIntBig nSum = 0;
6598 209 : GUIntBig nSumSquare = 0;
6599 : // If no valid nodata, map to invalid value (256 for Byte)
6600 209 : const GUInt32 nNoDataValue =
6601 230 : (sNoDataValues.bGotNoDataValue &&
6602 21 : sNoDataValues.dfNoDataValue >= 0 &&
6603 21 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
6604 21 : fabs(sNoDataValues.dfNoDataValue -
6605 21 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
6606 : 1e-10)) < 1e-10)
6607 230 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
6608 : : nMaxValueType + 1;
6609 :
6610 209 : for (GIntBig iSampleBlock = 0;
6611 12620 : iSampleBlock <
6612 12620 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6613 12411 : iSampleBlock += nSampleRate)
6614 : {
6615 12408 : const int iYBlock =
6616 12408 : static_cast<int>(iSampleBlock / nBlocksPerRow);
6617 12408 : const int iXBlock =
6618 12408 : static_cast<int>(iSampleBlock % nBlocksPerRow);
6619 :
6620 : GDALRasterBlock *const poBlock =
6621 12408 : GetLockedBlockRef(iXBlock, iYBlock);
6622 12407 : if (poBlock == nullptr)
6623 0 : return CE_Failure;
6624 :
6625 12407 : void *const pData = poBlock->GetDataRef();
6626 :
6627 12403 : int nXCheck = 0, nYCheck = 0;
6628 12403 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6629 :
6630 12403 : if (eDataType == GDT_Byte)
6631 : {
6632 : ComputeStatisticsInternal<
6633 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
6634 11945 : f(nXCheck, nBlockXSize, nYCheck,
6635 : static_cast<const GByte *>(pData),
6636 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6637 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6638 : }
6639 : else
6640 : {
6641 : ComputeStatisticsInternal<
6642 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6643 458 : f(nXCheck, nBlockXSize, nYCheck,
6644 : static_cast<const GUInt16 *>(pData),
6645 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6646 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6647 : }
6648 :
6649 12409 : poBlock->DropLock();
6650 :
6651 12406 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
6652 12408 : (static_cast<double>(nBlocksPerRow) *
6653 12408 : nBlocksPerColumn),
6654 : "Compute Statistics", pProgressData))
6655 : {
6656 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
6657 : "User terminated");
6658 0 : return CE_Failure;
6659 : }
6660 : }
6661 :
6662 212 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6663 : {
6664 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6665 0 : return CE_Failure;
6666 : }
6667 :
6668 : /* --------------------------------------------------------------------
6669 : */
6670 : /* Save computed information. */
6671 : /* --------------------------------------------------------------------
6672 : */
6673 212 : if (nValidCount)
6674 203 : dfMean = static_cast<double>(nSum) / nValidCount;
6675 :
6676 : // To avoid potential precision issues when doing the difference,
6677 : // we need to do that computation on 128 bit rather than casting
6678 : // to double
6679 : const GDALUInt128 nTmpForStdDev(
6680 211 : GDALUInt128::Mul(nSumSquare, nValidCount) -
6681 423 : GDALUInt128::Mul(nSum, nSum));
6682 : const double dfStdDev =
6683 211 : nValidCount > 0
6684 211 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6685 211 : : 0.0;
6686 :
6687 211 : if (nValidCount > 0)
6688 : {
6689 203 : if (bApproxOK)
6690 : {
6691 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6692 : }
6693 179 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6694 : {
6695 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6696 : }
6697 202 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
6698 : }
6699 :
6700 211 : SetValidPercent(nSampleCount, nValidCount);
6701 :
6702 : /* --------------------------------------------------------------------
6703 : */
6704 : /* Record results. */
6705 : /* --------------------------------------------------------------------
6706 : */
6707 210 : if (pdfMin != nullptr)
6708 205 : *pdfMin = nValidCount ? nMin : 0;
6709 210 : if (pdfMax != nullptr)
6710 205 : *pdfMax = nValidCount ? nMax : 0;
6711 :
6712 210 : if (pdfMean != nullptr)
6713 201 : *pdfMean = dfMean;
6714 :
6715 210 : if (pdfStdDev != nullptr)
6716 201 : *pdfStdDev = dfStdDev;
6717 :
6718 210 : if (nValidCount > 0)
6719 200 : return CE_None;
6720 :
6721 10 : ReportError(CE_Failure, CPLE_AppDefined,
6722 : "Failed to compute statistics, no valid pixels found "
6723 : "in sampling.");
6724 9 : return CE_Failure;
6725 : }
6726 :
6727 240 : GByte *pabyMaskData = nullptr;
6728 240 : if (poMaskBand)
6729 : {
6730 : pabyMaskData = static_cast<GByte *>(
6731 16 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6732 16 : if (!pabyMaskData)
6733 : {
6734 0 : return CE_Failure;
6735 : }
6736 : }
6737 :
6738 240 : for (GIntBig iSampleBlock = 0;
6739 5489 : iSampleBlock <
6740 5489 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6741 5249 : iSampleBlock += nSampleRate)
6742 : {
6743 5251 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6744 5251 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6745 :
6746 : GDALRasterBlock *const poBlock =
6747 5251 : GetLockedBlockRef(iXBlock, iYBlock);
6748 5251 : if (poBlock == nullptr)
6749 : {
6750 0 : CPLFree(pabyMaskData);
6751 0 : return CE_Failure;
6752 : }
6753 :
6754 5251 : void *const pData = poBlock->GetDataRef();
6755 :
6756 5251 : int nXCheck = 0, nYCheck = 0;
6757 5251 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6758 :
6759 5352 : if (poMaskBand &&
6760 101 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6761 101 : iYBlock * nBlockYSize, nXCheck, nYCheck,
6762 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6763 101 : 0, nBlockXSize, nullptr) != CE_None)
6764 : {
6765 0 : CPLFree(pabyMaskData);
6766 0 : poBlock->DropLock();
6767 0 : return CE_Failure;
6768 : }
6769 :
6770 : // This isn't the fastest way to do this, but is easier for now.
6771 10686 : for (int iY = 0; iY < nYCheck; iY++)
6772 : {
6773 4342140 : for (int iX = 0; iX < nXCheck; iX++)
6774 : {
6775 4336710 : const GPtrDiff_t iOffset =
6776 4336710 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6777 4336710 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6778 109941 : continue;
6779 :
6780 4326840 : bool bValid = true;
6781 : double dfValue =
6782 4326840 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6783 4326840 : sNoDataValues, bValid);
6784 :
6785 4326840 : if (!bValid)
6786 100070 : continue;
6787 :
6788 4226770 : dfMin = std::min(dfMin, dfValue);
6789 4226770 : dfMax = std::max(dfMax, dfValue);
6790 :
6791 4226770 : nValidCount++;
6792 4226770 : const double dfDelta = dfValue - dfMean;
6793 4226770 : dfMean += dfDelta / nValidCount;
6794 4226770 : dfM2 += dfDelta * (dfValue - dfMean);
6795 : }
6796 : }
6797 :
6798 5251 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6799 :
6800 5251 : poBlock->DropLock();
6801 :
6802 5251 : if (!pfnProgress(
6803 5251 : static_cast<double>(iSampleBlock) /
6804 5251 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6805 : "Compute Statistics", pProgressData))
6806 : {
6807 2 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6808 0 : CPLFree(pabyMaskData);
6809 0 : return CE_Failure;
6810 : }
6811 : }
6812 :
6813 238 : CPLFree(pabyMaskData);
6814 : }
6815 :
6816 238 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6817 : {
6818 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6819 0 : return CE_Failure;
6820 : }
6821 :
6822 : /* -------------------------------------------------------------------- */
6823 : /* Save computed information. */
6824 : /* -------------------------------------------------------------------- */
6825 238 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
6826 :
6827 238 : if (nValidCount > 0)
6828 : {
6829 237 : if (bApproxOK)
6830 : {
6831 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6832 : }
6833 229 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6834 : {
6835 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6836 : }
6837 237 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6838 : }
6839 : else
6840 : {
6841 1 : dfMin = 0.0;
6842 1 : dfMax = 0.0;
6843 : }
6844 :
6845 238 : SetValidPercent(nSampleCount, nValidCount);
6846 :
6847 : /* -------------------------------------------------------------------- */
6848 : /* Record results. */
6849 : /* -------------------------------------------------------------------- */
6850 238 : if (pdfMin != nullptr)
6851 235 : *pdfMin = dfMin;
6852 238 : if (pdfMax != nullptr)
6853 235 : *pdfMax = dfMax;
6854 :
6855 238 : if (pdfMean != nullptr)
6856 233 : *pdfMean = dfMean;
6857 :
6858 238 : if (pdfStdDev != nullptr)
6859 233 : *pdfStdDev = dfStdDev;
6860 :
6861 238 : if (nValidCount > 0)
6862 237 : return CE_None;
6863 :
6864 1 : ReportError(
6865 : CE_Failure, CPLE_AppDefined,
6866 : "Failed to compute statistics, no valid pixels found in sampling.");
6867 1 : return CE_Failure;
6868 : }
6869 :
6870 : /************************************************************************/
6871 : /* GDALComputeRasterStatistics() */
6872 : /************************************************************************/
6873 :
6874 : /**
6875 : * \brief Compute image statistics.
6876 : *
6877 : * @see GDALRasterBand::ComputeStatistics()
6878 : */
6879 :
6880 142 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
6881 : int bApproxOK, double *pdfMin,
6882 : double *pdfMax, double *pdfMean,
6883 : double *pdfStdDev,
6884 : GDALProgressFunc pfnProgress,
6885 : void *pProgressData)
6886 :
6887 : {
6888 142 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
6889 :
6890 142 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6891 :
6892 142 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
6893 142 : pdfStdDev, pfnProgress, pProgressData);
6894 : }
6895 :
6896 : /************************************************************************/
6897 : /* SetStatistics() */
6898 : /************************************************************************/
6899 :
6900 : /**
6901 : * \brief Set statistics on band.
6902 : *
6903 : * This method can be used to store min/max/mean/standard deviation
6904 : * statistics on a raster band.
6905 : *
6906 : * The default implementation stores them as metadata, and will only work
6907 : * on formats that can save arbitrary metadata. This method cannot detect
6908 : * whether metadata will be properly saved and so may return CE_None even
6909 : * if the statistics will never be saved.
6910 : *
6911 : * This method is the same as the C function GDALSetRasterStatistics().
6912 : *
6913 : * @param dfMin minimum pixel value.
6914 : *
6915 : * @param dfMax maximum pixel value.
6916 : *
6917 : * @param dfMean mean (average) of all pixel values.
6918 : *
6919 : * @param dfStdDev Standard deviation of all pixel values.
6920 : *
6921 : * @return CE_None on success or CE_Failure on failure.
6922 : */
6923 :
6924 468 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
6925 : double dfStdDev)
6926 :
6927 : {
6928 468 : char szValue[128] = {0};
6929 :
6930 468 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
6931 467 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
6932 :
6933 468 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
6934 467 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
6935 :
6936 468 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
6937 468 : SetMetadataItem("STATISTICS_MEAN", szValue);
6938 :
6939 468 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
6940 468 : SetMetadataItem("STATISTICS_STDDEV", szValue);
6941 :
6942 468 : return CE_None;
6943 : }
6944 :
6945 : /************************************************************************/
6946 : /* GDALSetRasterStatistics() */
6947 : /************************************************************************/
6948 :
6949 : /**
6950 : * \brief Set statistics on band.
6951 : *
6952 : * @see GDALRasterBand::SetStatistics()
6953 : */
6954 :
6955 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
6956 : double dfMax, double dfMean,
6957 : double dfStdDev)
6958 :
6959 : {
6960 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
6961 :
6962 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6963 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6964 : }
6965 :
6966 : /************************************************************************/
6967 : /* ComputeRasterMinMax() */
6968 : /************************************************************************/
6969 :
6970 : template <class T, bool HAS_NODATA>
6971 120175 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
6972 : T *pMax)
6973 : {
6974 120175 : T min0 = *pMin;
6975 120175 : T max0 = *pMax;
6976 120175 : T min1 = *pMin;
6977 120175 : T max1 = *pMax;
6978 : size_t i;
6979 214453 : for (i = 0; i + 1 < nElts; i += 2)
6980 : {
6981 81892 : if (!HAS_NODATA || buffer[i] != nodataValue)
6982 : {
6983 94278 : min0 = std::min(min0, buffer[i]);
6984 94278 : max0 = std::max(max0, buffer[i]);
6985 : }
6986 81892 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
6987 : {
6988 94278 : min1 = std::min(min1, buffer[i + 1]);
6989 94278 : max1 = std::max(max1, buffer[i + 1]);
6990 : }
6991 : }
6992 120175 : T min = std::min(min0, min1);
6993 120175 : T max = std::max(max0, max1);
6994 120175 : if (i < nElts)
6995 : {
6996 118460 : if (!HAS_NODATA || buffer[i] != nodataValue)
6997 : {
6998 118480 : min = std::min(min, buffer[i]);
6999 118480 : max = std::max(max, buffer[i]);
7000 : }
7001 : }
7002 120175 : *pMin = min;
7003 120175 : *pMax = max;
7004 120175 : }
7005 :
7006 : template <GDALDataType eDataType, bool bSignedByte>
7007 : static void
7008 11072 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7009 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7010 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
7011 : {
7012 11072 : double dfLocalMin = dfMin;
7013 11072 : double dfLocalMax = dfMax;
7014 :
7015 40255 : for (int iY = 0; iY < nYCheck; iY++)
7016 : {
7017 18949417 : for (int iX = 0; iX < nXCheck; iX++)
7018 : {
7019 18920221 : const GPtrDiff_t iOffset =
7020 18920221 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7021 18920221 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7022 3460307 : continue;
7023 18825980 : bool bValid = true;
7024 18825980 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7025 : iOffset, sNoDataValues, bValid);
7026 18825980 : if (!bValid)
7027 3366066 : continue;
7028 :
7029 15459874 : dfLocalMin = std::min(dfLocalMin, dfValue);
7030 15459874 : dfLocalMax = std::max(dfLocalMax, dfValue);
7031 : }
7032 : }
7033 :
7034 11072 : dfMin = dfLocalMin;
7035 11072 : dfMax = dfLocalMax;
7036 11072 : }
7037 :
7038 11072 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
7039 : bool bSignedByte, int nXCheck, int nYCheck,
7040 : int nBlockXSize,
7041 : const GDALNoDataValues &sNoDataValues,
7042 : const GByte *pabyMaskData, double &dfMin,
7043 : double &dfMax)
7044 : {
7045 11072 : switch (eDataType)
7046 : {
7047 0 : case GDT_Unknown:
7048 0 : CPLAssert(false);
7049 : break;
7050 672 : case GDT_Byte:
7051 672 : if (bSignedByte)
7052 : {
7053 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
7054 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7055 : pabyMaskData, dfMin, dfMax);
7056 : }
7057 : else
7058 : {
7059 669 : ComputeMinMaxGeneric<GDT_Byte, false>(
7060 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7061 : pabyMaskData, dfMin, dfMax);
7062 : }
7063 672 : break;
7064 106 : case GDT_Int8:
7065 106 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
7066 : nBlockXSize, sNoDataValues,
7067 : pabyMaskData, dfMin, dfMax);
7068 106 : break;
7069 200 : case GDT_UInt16:
7070 200 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
7071 : nBlockXSize, sNoDataValues,
7072 : pabyMaskData, dfMin, dfMax);
7073 200 : break;
7074 1 : case GDT_Int16:
7075 1 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
7076 : nBlockXSize, sNoDataValues,
7077 : pabyMaskData, dfMin, dfMax);
7078 1 : break;
7079 201 : case GDT_UInt32:
7080 201 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
7081 : nBlockXSize, sNoDataValues,
7082 : pabyMaskData, dfMin, dfMax);
7083 201 : break;
7084 1048 : case GDT_Int32:
7085 1048 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
7086 : nBlockXSize, sNoDataValues,
7087 : pabyMaskData, dfMin, dfMax);
7088 1048 : break;
7089 16 : case GDT_UInt64:
7090 16 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
7091 : nBlockXSize, sNoDataValues,
7092 : pabyMaskData, dfMin, dfMax);
7093 16 : break;
7094 28 : case GDT_Int64:
7095 28 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
7096 : nBlockXSize, sNoDataValues,
7097 : pabyMaskData, dfMin, dfMax);
7098 28 : break;
7099 0 : case GDT_Float16:
7100 0 : ComputeMinMaxGeneric<GDT_Float16, false>(
7101 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7102 : pabyMaskData, dfMin, dfMax);
7103 0 : break;
7104 5421 : case GDT_Float32:
7105 5421 : ComputeMinMaxGeneric<GDT_Float32, false>(
7106 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7107 : pabyMaskData, dfMin, dfMax);
7108 5421 : break;
7109 3269 : case GDT_Float64:
7110 3269 : ComputeMinMaxGeneric<GDT_Float64, false>(
7111 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7112 : pabyMaskData, dfMin, dfMax);
7113 3269 : break;
7114 9 : case GDT_CInt16:
7115 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
7116 : nBlockXSize, sNoDataValues,
7117 : pabyMaskData, dfMin, dfMax);
7118 9 : break;
7119 9 : case GDT_CInt32:
7120 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
7121 : nBlockXSize, sNoDataValues,
7122 : pabyMaskData, dfMin, dfMax);
7123 9 : break;
7124 0 : case GDT_CFloat16:
7125 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
7126 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7127 : pabyMaskData, dfMin, dfMax);
7128 0 : break;
7129 75 : case GDT_CFloat32:
7130 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
7131 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7132 : pabyMaskData, dfMin, dfMax);
7133 75 : break;
7134 17 : case GDT_CFloat64:
7135 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
7136 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7137 : pabyMaskData, dfMin, dfMax);
7138 17 : break;
7139 0 : case GDT_TypeCount:
7140 0 : CPLAssert(false);
7141 : break;
7142 : }
7143 11072 : }
7144 :
7145 705 : static bool ComputeMinMaxGenericIterBlocks(
7146 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
7147 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
7148 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
7149 : double &dfMin, double &dfMax)
7150 :
7151 : {
7152 705 : GByte *pabyMaskData = nullptr;
7153 : int nBlockXSize, nBlockYSize;
7154 705 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7155 :
7156 705 : if (poMaskBand)
7157 : {
7158 : pabyMaskData =
7159 40 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7160 40 : if (!pabyMaskData)
7161 : {
7162 0 : return false;
7163 : }
7164 : }
7165 :
7166 11777 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7167 11072 : iSampleBlock += nSampleRate)
7168 : {
7169 11072 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7170 11072 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7171 :
7172 11072 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7173 11072 : if (poBlock == nullptr)
7174 : {
7175 0 : CPLFree(pabyMaskData);
7176 0 : return false;
7177 : }
7178 :
7179 11072 : void *const pData = poBlock->GetDataRef();
7180 :
7181 11072 : int nXCheck = 0, nYCheck = 0;
7182 11072 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7183 :
7184 11943 : if (poMaskBand &&
7185 871 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7186 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7187 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7188 : nBlockXSize, nullptr) != CE_None)
7189 : {
7190 0 : poBlock->DropLock();
7191 0 : CPLFree(pabyMaskData);
7192 0 : return false;
7193 : }
7194 :
7195 11072 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7196 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
7197 : dfMax);
7198 :
7199 11072 : poBlock->DropLock();
7200 : }
7201 :
7202 705 : CPLFree(pabyMaskData);
7203 705 : return true;
7204 : }
7205 :
7206 : /**
7207 : * \brief Compute the min/max values for a band.
7208 : *
7209 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7210 : * be trusted. If it doesn't work, a subsample of blocks will be read to
7211 : * get an approximate min/max. If the band has a nodata value it will
7212 : * be excluded from the minimum and maximum.
7213 : *
7214 : * If bApprox is FALSE, then all pixels will be read and used to compute
7215 : * an exact range.
7216 : *
7217 : * This method is the same as the C function GDALComputeRasterMinMax().
7218 : *
7219 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7220 : * FALSE.
7221 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7222 : * maximum (adfMinMax[1]) are returned.
7223 : *
7224 : * @return CE_None on success or CE_Failure on failure.
7225 : */
7226 :
7227 1539 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7228 : {
7229 : /* -------------------------------------------------------------------- */
7230 : /* Does the driver already know the min/max? */
7231 : /* -------------------------------------------------------------------- */
7232 1539 : if (bApproxOK)
7233 : {
7234 21 : int bSuccessMin = FALSE;
7235 21 : int bSuccessMax = FALSE;
7236 :
7237 21 : double dfMin = GetMinimum(&bSuccessMin);
7238 21 : double dfMax = GetMaximum(&bSuccessMax);
7239 :
7240 21 : if (bSuccessMin && bSuccessMax)
7241 : {
7242 1 : adfMinMax[0] = dfMin;
7243 1 : adfMinMax[1] = dfMax;
7244 1 : return CE_None;
7245 : }
7246 : }
7247 :
7248 : /* -------------------------------------------------------------------- */
7249 : /* If we have overview bands, use them for min/max. */
7250 : /* -------------------------------------------------------------------- */
7251 : // cppcheck-suppress knownConditionTrueFalse
7252 1538 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7253 : {
7254 : GDALRasterBand *poBand =
7255 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7256 :
7257 0 : if (poBand != this)
7258 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7259 : }
7260 :
7261 : /* -------------------------------------------------------------------- */
7262 : /* Read actual data and compute minimum and maximum. */
7263 : /* -------------------------------------------------------------------- */
7264 1538 : GDALNoDataValues sNoDataValues(this, eDataType);
7265 1538 : GDALRasterBand *poMaskBand = nullptr;
7266 1538 : if (!sNoDataValues.bGotNoDataValue)
7267 : {
7268 1294 : const int l_nMaskFlags = GetMaskFlags();
7269 1334 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7270 40 : GetColorInterpretation() != GCI_AlphaBand)
7271 : {
7272 40 : poMaskBand = GetMaskBand();
7273 : }
7274 : }
7275 :
7276 1538 : bool bSignedByte = false;
7277 1538 : if (eDataType == GDT_Byte)
7278 : {
7279 628 : EnablePixelTypeSignedByteWarning(false);
7280 : const char *pszPixelType =
7281 628 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7282 628 : EnablePixelTypeSignedByteWarning(true);
7283 628 : bSignedByte =
7284 628 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7285 : }
7286 :
7287 : GDALRasterIOExtraArg sExtraArg;
7288 1538 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7289 :
7290 3076 : GUInt32 nMin = (eDataType == GDT_Byte)
7291 1538 : ? 255
7292 : : 65535; // used for GByte & GUInt16 cases
7293 1538 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
7294 1538 : GInt16 nMinInt16 =
7295 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
7296 1538 : GInt16 nMaxInt16 =
7297 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
7298 1538 : double dfMin =
7299 : std::numeric_limits<double>::max(); // used for generic code path
7300 1538 : double dfMax =
7301 : std::numeric_limits<double>::lowest(); // used for generic code path
7302 1538 : const bool bUseOptimizedPath =
7303 2439 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7304 901 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7305 :
7306 : const auto ComputeMinMaxForBlock =
7307 18188 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
7308 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
7309 225501 : int nYCheck)
7310 : {
7311 18188 : if (eDataType == GDT_Byte && !bSignedByte)
7312 : {
7313 : const bool bHasNoData =
7314 9561 : sNoDataValues.bGotNoDataValue &&
7315 25465 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
7316 9561 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
7317 9561 : sNoDataValues.dfNoDataValue;
7318 15904 : const GUInt32 nNoDataValue =
7319 15904 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
7320 : : 0;
7321 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7322 : ComputeStatisticsInternal<GByte,
7323 : /* COMPUTE_OTHER_STATS = */ false>::
7324 15904 : f(nXCheck, nBufferWidth, nYCheck,
7325 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7326 15904 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7327 : }
7328 2284 : else if (eDataType == GDT_UInt16)
7329 : {
7330 : const bool bHasNoData =
7331 83 : sNoDataValues.bGotNoDataValue &&
7332 979 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
7333 83 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
7334 83 : sNoDataValues.dfNoDataValue;
7335 896 : const GUInt32 nNoDataValue =
7336 896 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
7337 : : 0;
7338 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7339 : ComputeStatisticsInternal<GUInt16,
7340 : /* COMPUTE_OTHER_STATS = */ false>::
7341 896 : f(nXCheck, nBufferWidth, nYCheck,
7342 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7343 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7344 : }
7345 1388 : else if (eDataType == GDT_Int16)
7346 : {
7347 : const bool bHasNoData =
7348 1214 : sNoDataValues.bGotNoDataValue &&
7349 2602 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
7350 1214 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
7351 1214 : sNoDataValues.dfNoDataValue;
7352 1388 : if (bHasNoData)
7353 : {
7354 1214 : const int16_t nNoDataValue =
7355 1214 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
7356 120117 : for (int iY = 0; iY < nYCheck; iY++)
7357 : {
7358 118903 : ComputeMinMax<int16_t, true>(
7359 118903 : static_cast<const int16_t *>(pData) +
7360 118903 : static_cast<size_t>(iY) * nBufferWidth,
7361 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7362 : }
7363 : }
7364 : else
7365 : {
7366 1446 : for (int iY = 0; iY < nYCheck; iY++)
7367 : {
7368 1272 : ComputeMinMax<int16_t, false>(
7369 1272 : static_cast<const int16_t *>(pData) +
7370 1272 : static_cast<size_t>(iY) * nBufferWidth,
7371 : nXCheck, 0, &nMinInt16, &nMaxInt16);
7372 : }
7373 : }
7374 : }
7375 18188 : };
7376 :
7377 1538 : if (bApproxOK && HasArbitraryOverviews())
7378 : {
7379 : /* --------------------------------------------------------------------
7380 : */
7381 : /* Figure out how much the image should be reduced to get an */
7382 : /* approximate value. */
7383 : /* --------------------------------------------------------------------
7384 : */
7385 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7386 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7387 :
7388 0 : int nXReduced = nRasterXSize;
7389 0 : int nYReduced = nRasterYSize;
7390 0 : if (dfReduction > 1.0)
7391 : {
7392 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7393 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7394 :
7395 : // Catch the case of huge resizing ratios here
7396 0 : if (nXReduced == 0)
7397 0 : nXReduced = 1;
7398 0 : if (nYReduced == 0)
7399 0 : nYReduced = 1;
7400 : }
7401 :
7402 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
7403 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7404 :
7405 : const CPLErr eErr =
7406 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7407 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7408 0 : if (eErr != CE_None)
7409 : {
7410 0 : CPLFree(pData);
7411 0 : return eErr;
7412 : }
7413 :
7414 0 : GByte *pabyMaskData = nullptr;
7415 0 : if (poMaskBand)
7416 : {
7417 : pabyMaskData =
7418 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7419 0 : if (!pabyMaskData)
7420 : {
7421 0 : CPLFree(pData);
7422 0 : return CE_Failure;
7423 : }
7424 :
7425 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7426 : pabyMaskData, nXReduced, nYReduced,
7427 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
7428 : {
7429 0 : CPLFree(pData);
7430 0 : CPLFree(pabyMaskData);
7431 0 : return CE_Failure;
7432 : }
7433 : }
7434 :
7435 0 : if (bUseOptimizedPath)
7436 : {
7437 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7438 : }
7439 : else
7440 : {
7441 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
7442 : nYReduced, nXReduced, sNoDataValues,
7443 : pabyMaskData, dfMin, dfMax);
7444 : }
7445 :
7446 0 : CPLFree(pData);
7447 0 : CPLFree(pabyMaskData);
7448 : }
7449 :
7450 : else // No arbitrary overviews
7451 : {
7452 1538 : if (!InitBlockInfo())
7453 0 : return CE_Failure;
7454 :
7455 : /* --------------------------------------------------------------------
7456 : */
7457 : /* Figure out the ratio of blocks we will read to get an */
7458 : /* approximate value. */
7459 : /* --------------------------------------------------------------------
7460 : */
7461 1538 : int nSampleRate = 1;
7462 :
7463 1538 : if (bApproxOK)
7464 : {
7465 20 : nSampleRate = static_cast<int>(std::max(
7466 40 : 1.0,
7467 20 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7468 : // We want to avoid probing only the first column of blocks for
7469 : // a square shaped raster, because it is not unlikely that it may
7470 : // be padding only (#6378).
7471 20 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7472 0 : nSampleRate += 1;
7473 : }
7474 :
7475 1538 : if (bUseOptimizedPath)
7476 : {
7477 833 : for (GIntBig iSampleBlock = 0;
7478 18946 : iSampleBlock <
7479 18946 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7480 18113 : iSampleBlock += nSampleRate)
7481 : {
7482 18189 : const int iYBlock =
7483 18189 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7484 18189 : const int iXBlock =
7485 18189 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7486 :
7487 18189 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7488 18189 : if (poBlock == nullptr)
7489 1 : return CE_Failure;
7490 :
7491 18188 : void *const pData = poBlock->GetDataRef();
7492 :
7493 18188 : int nXCheck = 0, nYCheck = 0;
7494 18188 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7495 :
7496 18188 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7497 :
7498 18188 : poBlock->DropLock();
7499 :
7500 18188 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7501 4023 : nMax == 255)
7502 75 : break;
7503 : }
7504 : }
7505 : else
7506 : {
7507 705 : const GIntBig nTotalBlocks =
7508 705 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7509 705 : if (!ComputeMinMaxGenericIterBlocks(
7510 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7511 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
7512 : {
7513 0 : return CE_Failure;
7514 : }
7515 : }
7516 : }
7517 :
7518 1537 : if (bUseOptimizedPath)
7519 : {
7520 832 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7521 : {
7522 730 : dfMin = nMin;
7523 730 : dfMax = nMax;
7524 : }
7525 102 : else if (eDataType == GDT_Int16)
7526 : {
7527 102 : dfMin = nMinInt16;
7528 102 : dfMax = nMaxInt16;
7529 : }
7530 : }
7531 :
7532 1537 : if (dfMin > dfMax)
7533 : {
7534 4 : adfMinMax[0] = 0;
7535 4 : adfMinMax[1] = 0;
7536 4 : ReportError(
7537 : CE_Failure, CPLE_AppDefined,
7538 : "Failed to compute min/max, no valid pixels found in sampling.");
7539 4 : return CE_Failure;
7540 : }
7541 :
7542 1533 : adfMinMax[0] = dfMin;
7543 1533 : adfMinMax[1] = dfMax;
7544 :
7545 1533 : return CE_None;
7546 : }
7547 :
7548 : /************************************************************************/
7549 : /* GDALComputeRasterMinMax() */
7550 : /************************************************************************/
7551 :
7552 : /**
7553 : * \brief Compute the min/max values for a band.
7554 : *
7555 : * @see GDALRasterBand::ComputeRasterMinMax()
7556 : *
7557 : * @note Prior to GDAL 3.6, this function returned void
7558 : */
7559 :
7560 1461 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7561 : double adfMinMax[2])
7562 :
7563 : {
7564 1461 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7565 :
7566 1461 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7567 1461 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7568 : }
7569 :
7570 : /************************************************************************/
7571 : /* ComputeRasterMinMaxLocation() */
7572 : /************************************************************************/
7573 :
7574 : /**
7575 : * \brief Compute the min/max values for a band, and their location.
7576 : *
7577 : * Pixels whose value matches the nodata value or are masked by the mask
7578 : * band are ignored.
7579 : *
7580 : * If the minimum or maximum value is hit in several locations, it is not
7581 : * specified which one will be returned.
7582 : *
7583 : * @param[out] pdfMin Pointer to the minimum value.
7584 : * @param[out] pdfMax Pointer to the maximum value.
7585 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7586 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7587 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7588 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7589 : *
7590 : * @return CE_None in case of success, CE_Warning if there are no valid values,
7591 : * CE_Failure in case of error.
7592 : *
7593 : * @since GDAL 3.11
7594 : */
7595 :
7596 8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7597 : double *pdfMax, int *pnMinX,
7598 : int *pnMinY, int *pnMaxX,
7599 : int *pnMaxY)
7600 : {
7601 8 : int nMinX = -1;
7602 8 : int nMinY = -1;
7603 8 : int nMaxX = -1;
7604 8 : int nMaxY = -1;
7605 8 : double dfMin = std::numeric_limits<double>::infinity();
7606 8 : double dfMax = -std::numeric_limits<double>::infinity();
7607 8 : if (pdfMin)
7608 5 : *pdfMin = dfMin;
7609 8 : if (pdfMax)
7610 5 : *pdfMax = dfMax;
7611 8 : if (pnMinX)
7612 6 : *pnMinX = nMinX;
7613 8 : if (pnMinY)
7614 6 : *pnMinY = nMinY;
7615 8 : if (pnMaxX)
7616 6 : *pnMaxX = nMaxX;
7617 8 : if (pnMaxY)
7618 6 : *pnMaxY = nMaxY;
7619 :
7620 8 : if (GDALDataTypeIsComplex(eDataType))
7621 : {
7622 0 : CPLError(CE_Failure, CPLE_NotSupported,
7623 : "Complex data type not supported");
7624 0 : return CE_Failure;
7625 : }
7626 :
7627 8 : if (!InitBlockInfo())
7628 0 : return CE_Failure;
7629 :
7630 8 : GDALNoDataValues sNoDataValues(this, eDataType);
7631 8 : GDALRasterBand *poMaskBand = nullptr;
7632 8 : if (!sNoDataValues.bGotNoDataValue)
7633 : {
7634 8 : const int l_nMaskFlags = GetMaskFlags();
7635 9 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7636 1 : GetColorInterpretation() != GCI_AlphaBand)
7637 : {
7638 1 : poMaskBand = GetMaskBand();
7639 : }
7640 : }
7641 :
7642 8 : bool bSignedByte = false;
7643 8 : if (eDataType == GDT_Byte)
7644 : {
7645 7 : EnablePixelTypeSignedByteWarning(false);
7646 : const char *pszPixelType =
7647 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7648 7 : EnablePixelTypeSignedByteWarning(true);
7649 7 : bSignedByte =
7650 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7651 : }
7652 :
7653 8 : GByte *pabyMaskData = nullptr;
7654 8 : if (poMaskBand)
7655 : {
7656 : pabyMaskData =
7657 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7658 1 : if (!pabyMaskData)
7659 : {
7660 0 : return CE_Failure;
7661 : }
7662 : }
7663 :
7664 8 : const GIntBig nTotalBlocks =
7665 8 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7666 8 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7667 8 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7668 16 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7669 : {
7670 11 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7671 11 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7672 :
7673 11 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7674 11 : if (poBlock == nullptr)
7675 : {
7676 0 : CPLFree(pabyMaskData);
7677 0 : return CE_Failure;
7678 : }
7679 :
7680 11 : void *const pData = poBlock->GetDataRef();
7681 :
7682 11 : int nXCheck = 0, nYCheck = 0;
7683 11 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7684 :
7685 13 : if (poMaskBand &&
7686 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7687 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7688 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7689 2 : nBlockXSize, nullptr) != CE_None)
7690 : {
7691 0 : poBlock->DropLock();
7692 0 : CPLFree(pabyMaskData);
7693 0 : return CE_Failure;
7694 : }
7695 :
7696 11 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7697 : {
7698 4 : for (int iY = 0; iY < nYCheck; ++iY)
7699 : {
7700 6 : for (int iX = 0; iX < nXCheck; ++iX)
7701 : {
7702 4 : const GPtrDiff_t iOffset =
7703 4 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7704 4 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7705 2 : continue;
7706 2 : bool bValid = true;
7707 : double dfValue =
7708 2 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
7709 : sNoDataValues, bValid);
7710 2 : if (!bValid)
7711 0 : continue;
7712 2 : if (dfValue < dfMin)
7713 : {
7714 2 : dfMin = dfValue;
7715 2 : nMinX = iXBlock * nBlockXSize + iX;
7716 2 : nMinY = iYBlock * nBlockYSize + iY;
7717 : }
7718 2 : if (dfValue > dfMax)
7719 : {
7720 1 : dfMax = dfValue;
7721 1 : nMaxX = iXBlock * nBlockXSize + iX;
7722 1 : nMaxY = iYBlock * nBlockYSize + iY;
7723 : }
7724 : }
7725 2 : }
7726 : }
7727 : else
7728 : {
7729 9 : size_t pos_min = 0;
7730 9 : size_t pos_max = 0;
7731 9 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7732 9 : if (bNeedsMin && bNeedsMax)
7733 : {
7734 10 : std::tie(pos_min, pos_max) = gdal::minmax_element(
7735 5 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7736 5 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7737 10 : sNoDataValues.dfNoDataValue);
7738 : }
7739 4 : else if (bNeedsMin)
7740 : {
7741 1 : pos_min = gdal::min_element(
7742 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7743 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7744 : sNoDataValues.dfNoDataValue);
7745 : }
7746 3 : else if (bNeedsMax)
7747 : {
7748 2 : pos_max = gdal::max_element(
7749 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7750 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7751 : sNoDataValues.dfNoDataValue);
7752 : }
7753 :
7754 9 : if (bNeedsMin)
7755 : {
7756 6 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7757 6 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7758 6 : bool bValid = true;
7759 : const double dfMinValueBlock =
7760 6 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
7761 : sNoDataValues, bValid);
7762 6 : if (bValid && dfMinValueBlock < dfMin)
7763 : {
7764 5 : dfMin = dfMinValueBlock;
7765 5 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
7766 5 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
7767 : }
7768 : }
7769 :
7770 9 : if (bNeedsMax)
7771 : {
7772 7 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7773 7 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7774 7 : bool bValid = true;
7775 : const double dfMaxValueBlock =
7776 7 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
7777 : sNoDataValues, bValid);
7778 7 : if (bValid && dfMaxValueBlock > dfMax)
7779 : {
7780 5 : dfMax = dfMaxValueBlock;
7781 5 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7782 5 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7783 : }
7784 : }
7785 : }
7786 :
7787 11 : poBlock->DropLock();
7788 :
7789 11 : if (eDataType == GDT_Byte)
7790 : {
7791 10 : if (bNeedsMin && dfMin == 0)
7792 : {
7793 1 : bNeedsMin = false;
7794 : }
7795 10 : if (bNeedsMax && dfMax == 255)
7796 : {
7797 4 : bNeedsMax = false;
7798 : }
7799 10 : if (!bNeedsMin && !bNeedsMax)
7800 : {
7801 3 : break;
7802 : }
7803 : }
7804 : }
7805 :
7806 8 : CPLFree(pabyMaskData);
7807 :
7808 8 : if (pdfMin)
7809 5 : *pdfMin = dfMin;
7810 8 : if (pdfMax)
7811 5 : *pdfMax = dfMax;
7812 8 : if (pnMinX)
7813 6 : *pnMinX = nMinX;
7814 8 : if (pnMinY)
7815 6 : *pnMinY = nMinY;
7816 8 : if (pnMaxX)
7817 6 : *pnMaxX = nMaxX;
7818 8 : if (pnMaxY)
7819 6 : *pnMaxY = nMaxY;
7820 8 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
7821 8 : : CE_None;
7822 : }
7823 :
7824 : /************************************************************************/
7825 : /* GDALComputeRasterMinMaxLocation() */
7826 : /************************************************************************/
7827 :
7828 : /**
7829 : * \brief Compute the min/max values for a band, and their location.
7830 : *
7831 : * @see GDALRasterBand::ComputeRasterMinMax()
7832 : * @since GDAL 3.11
7833 : */
7834 :
7835 6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
7836 : double *pdfMax, int *pnMinX, int *pnMinY,
7837 : int *pnMaxX, int *pnMaxY)
7838 :
7839 : {
7840 6 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
7841 :
7842 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7843 6 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
7844 6 : pnMaxX, pnMaxY);
7845 : }
7846 :
7847 : /************************************************************************/
7848 : /* SetDefaultHistogram() */
7849 : /************************************************************************/
7850 :
7851 : /* FIXME : add proper documentation */
7852 : /**
7853 : * \brief Set default histogram.
7854 : *
7855 : * This method is the same as the C function GDALSetDefaultHistogram() and
7856 : * GDALSetDefaultHistogramEx()
7857 : */
7858 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
7859 : double /* dfMax */,
7860 : int /* nBuckets */,
7861 : GUIntBig * /* panHistogram */)
7862 :
7863 : {
7864 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
7865 0 : ReportError(CE_Failure, CPLE_NotSupported,
7866 : "SetDefaultHistogram() not implemented for this format.");
7867 :
7868 0 : return CE_Failure;
7869 : }
7870 :
7871 : /************************************************************************/
7872 : /* GDALSetDefaultHistogram() */
7873 : /************************************************************************/
7874 :
7875 : /**
7876 : * \brief Set default histogram.
7877 : *
7878 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
7879 : * 2 billion.
7880 : *
7881 : * @see GDALRasterBand::SetDefaultHistogram()
7882 : * @see GDALSetRasterHistogramEx()
7883 : */
7884 :
7885 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
7886 : double dfMax, int nBuckets,
7887 : int *panHistogram)
7888 :
7889 : {
7890 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
7891 :
7892 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7893 :
7894 : GUIntBig *panHistogramTemp =
7895 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
7896 0 : if (panHistogramTemp == nullptr)
7897 : {
7898 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
7899 : "Out of memory in GDALSetDefaultHistogram().");
7900 0 : return CE_Failure;
7901 : }
7902 :
7903 0 : for (int i = 0; i < nBuckets; ++i)
7904 : {
7905 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
7906 : }
7907 :
7908 : const CPLErr eErr =
7909 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
7910 :
7911 0 : CPLFree(panHistogramTemp);
7912 :
7913 0 : return eErr;
7914 : }
7915 :
7916 : /************************************************************************/
7917 : /* GDALSetDefaultHistogramEx() */
7918 : /************************************************************************/
7919 :
7920 : /**
7921 : * \brief Set default histogram.
7922 : *
7923 : * @see GDALRasterBand::SetDefaultHistogram()
7924 : *
7925 : * @since GDAL 2.0
7926 : */
7927 :
7928 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
7929 : double dfMin, double dfMax,
7930 : int nBuckets,
7931 : GUIntBig *panHistogram)
7932 :
7933 : {
7934 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
7935 :
7936 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7937 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
7938 : }
7939 :
7940 : /************************************************************************/
7941 : /* GetDefaultRAT() */
7942 : /************************************************************************/
7943 :
7944 : /**
7945 : * \brief Fetch default Raster Attribute Table.
7946 : *
7947 : * A RAT will be returned if there is a default one associated with the
7948 : * band, otherwise NULL is returned. The returned RAT is owned by the
7949 : * band and should not be deleted by the application.
7950 : *
7951 : * This method is the same as the C function GDALGetDefaultRAT().
7952 : *
7953 : * @return NULL, or a pointer to an internal RAT owned by the band.
7954 : */
7955 :
7956 112 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
7957 :
7958 : {
7959 112 : return nullptr;
7960 : }
7961 :
7962 : /************************************************************************/
7963 : /* GDALGetDefaultRAT() */
7964 : /************************************************************************/
7965 :
7966 : /**
7967 : * \brief Fetch default Raster Attribute Table.
7968 : *
7969 : * @see GDALRasterBand::GetDefaultRAT()
7970 : */
7971 :
7972 1017 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
7973 :
7974 : {
7975 1017 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
7976 :
7977 1017 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7978 1017 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
7979 : }
7980 :
7981 : /************************************************************************/
7982 : /* SetDefaultRAT() */
7983 : /************************************************************************/
7984 :
7985 : /**
7986 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
7987 : * \brief Set default Raster Attribute Table.
7988 : *
7989 : * Associates a default RAT with the band. If not implemented for the
7990 : * format a CPLE_NotSupported error will be issued. If successful a copy
7991 : * of the RAT is made, the original remains owned by the caller.
7992 : *
7993 : * This method is the same as the C function GDALSetDefaultRAT().
7994 : *
7995 : * @param poRAT the RAT to assign to the band.
7996 : *
7997 : * @return CE_None on success or CE_Failure if unsupported or otherwise
7998 : * failing.
7999 : */
8000 :
8001 : /**/
8002 : /**/
8003 :
8004 : CPLErr
8005 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8006 : {
8007 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8008 : {
8009 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
8010 0 : ReportError(CE_Failure, CPLE_NotSupported,
8011 : "SetDefaultRAT() not implemented for this format.");
8012 0 : CPLPopErrorHandler();
8013 : }
8014 0 : return CE_Failure;
8015 : }
8016 :
8017 : /************************************************************************/
8018 : /* GDALSetDefaultRAT() */
8019 : /************************************************************************/
8020 :
8021 : /**
8022 : * \brief Set default Raster Attribute Table.
8023 : *
8024 : * @see GDALRasterBand::GDALSetDefaultRAT()
8025 : */
8026 :
8027 18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
8028 : GDALRasterAttributeTableH hRAT)
8029 :
8030 : {
8031 18 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
8032 :
8033 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8034 :
8035 18 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
8036 : }
8037 :
8038 : /************************************************************************/
8039 : /* GetMaskBand() */
8040 : /************************************************************************/
8041 :
8042 : /**
8043 : * \brief Return the mask band associated with the band.
8044 : *
8045 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8046 : * that returns one of four default implementations :
8047 : * <ul>
8048 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8049 : * </li>
8050 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8051 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8052 : * GMF_NODATA | GMF_PER_DATASET.
8053 : * </li>
8054 : * <li>If the band has a nodata value set, an instance of the new
8055 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8056 : * GMF_NODATA.
8057 : * </li>
8058 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
8059 : * to apply to this band (specific rules yet to be determined) and that is of
8060 : * type GDT_Byte then that alpha band will be returned, and the flags
8061 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8062 : * </li>
8063 : * <li>If neither of the above apply, an instance of the new
8064 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8065 : * pixels. The null flags will return GMF_ALL_VALID.
8066 : * </li>
8067 : * </ul>
8068 : *
8069 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
8070 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
8071 : *
8072 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8073 : * dataset, with the same name as the main dataset and suffixed with .msk,
8074 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8075 : * main dataset.
8076 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8077 : * level, where xx matches the band number of a band of the main dataset. The
8078 : * value of those items is a combination of the flags GMF_ALL_VALID,
8079 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8080 : * a band, then the other rules explained above will be used to generate a
8081 : * on-the-fly mask band.
8082 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8083 : *
8084 : * This method is the same as the C function GDALGetMaskBand().
8085 : *
8086 : * @return a valid mask band.
8087 : *
8088 : * @since GDAL 1.5.0
8089 : *
8090 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8091 : *
8092 : */
8093 696190 : GDALRasterBand *GDALRasterBand::GetMaskBand()
8094 :
8095 : {
8096 179606 : const auto HasNoData = [this]()
8097 : {
8098 59615 : int bHaveNoDataRaw = FALSE;
8099 59615 : bool bHaveNoData = false;
8100 59615 : if (eDataType == GDT_Int64)
8101 : {
8102 59 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
8103 59 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8104 : }
8105 59556 : else if (eDataType == GDT_UInt64)
8106 : {
8107 46 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
8108 46 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8109 : }
8110 : else
8111 : {
8112 59510 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
8113 59179 : if (bHaveNoDataRaw &&
8114 59179 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
8115 : {
8116 791 : bHaveNoData = true;
8117 : }
8118 : }
8119 58977 : return bHaveNoData;
8120 696190 : };
8121 :
8122 696190 : if (poMask != nullptr)
8123 : {
8124 656177 : if (poMask.IsOwned())
8125 : {
8126 311434 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
8127 : {
8128 31808 : if (HasNoData())
8129 : {
8130 9 : InvalidateMaskBand();
8131 : }
8132 : }
8133 284420 : else if (auto poNoDataMaskBand =
8134 282284 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
8135 : {
8136 180 : int bHaveNoDataRaw = FALSE;
8137 180 : bool bIsSame = false;
8138 180 : if (eDataType == GDT_Int64)
8139 9 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
8140 11 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
8141 2 : bHaveNoDataRaw;
8142 171 : else if (eDataType == GDT_UInt64)
8143 9 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8144 11 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8145 2 : bHaveNoDataRaw;
8146 : else
8147 : {
8148 : const double dfNoDataValue =
8149 162 : GetNoDataValue(&bHaveNoDataRaw);
8150 162 : if (bHaveNoDataRaw)
8151 : {
8152 159 : bIsSame =
8153 159 : std::isnan(dfNoDataValue)
8154 159 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8155 133 : : poNoDataMaskBand->m_dfNoDataValue ==
8156 : dfNoDataValue;
8157 : }
8158 : }
8159 180 : if (!bIsSame)
8160 23 : InvalidateMaskBand();
8161 : }
8162 : }
8163 :
8164 681871 : if (poMask)
8165 687829 : return poMask.get();
8166 : }
8167 :
8168 : /* -------------------------------------------------------------------- */
8169 : /* Check for a mask in a .msk file. */
8170 : /* -------------------------------------------------------------------- */
8171 27888 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8172 : {
8173 46 : poMask.reset(poDS->oOvManager.GetMaskBand(nBand), false);
8174 46 : if (poMask != nullptr)
8175 : {
8176 44 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8177 44 : return poMask.get();
8178 : }
8179 : }
8180 :
8181 : /* -------------------------------------------------------------------- */
8182 : /* Check for NODATA_VALUES metadata. */
8183 : /* -------------------------------------------------------------------- */
8184 27844 : if (poDS != nullptr)
8185 : {
8186 : const char *pszGDALNoDataValues =
8187 27832 : poDS->GetMetadataItem("NODATA_VALUES");
8188 27831 : if (pszGDALNoDataValues != nullptr)
8189 : {
8190 66 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
8191 : pszGDALNoDataValues, " ", FALSE, FALSE);
8192 :
8193 : // Make sure we have as many values as bands.
8194 132 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
8195 66 : poDS->GetRasterCount() != 0)
8196 : {
8197 : // Make sure that all bands have the same data type
8198 : // This is clearly not a fundamental condition, just a
8199 : // condition to make implementation easier.
8200 66 : GDALDataType eDT = GDT_Unknown;
8201 66 : int i = 0; // Used after for.
8202 263 : for (; i < poDS->GetRasterCount(); ++i)
8203 : {
8204 197 : if (i == 0)
8205 66 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8206 131 : else if (eDT !=
8207 131 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
8208 : {
8209 0 : break;
8210 : }
8211 : }
8212 66 : if (i == poDS->GetRasterCount())
8213 : {
8214 66 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8215 : try
8216 : {
8217 66 : poMask.reset(new GDALNoDataValuesMaskBand(poDS), true);
8218 : }
8219 0 : catch (const std::bad_alloc &)
8220 : {
8221 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8222 0 : poMask.reset();
8223 : }
8224 66 : CSLDestroy(papszGDALNoDataValues);
8225 66 : return poMask.get();
8226 : }
8227 : else
8228 : {
8229 0 : ReportError(CE_Warning, CPLE_AppDefined,
8230 : "All bands should have the same type in "
8231 : "order the NODATA_VALUES metadata item "
8232 : "to be used as a mask.");
8233 : }
8234 : }
8235 : else
8236 : {
8237 0 : ReportError(
8238 : CE_Warning, CPLE_AppDefined,
8239 : "NODATA_VALUES metadata item doesn't have the same number "
8240 : "of values as the number of bands. "
8241 : "Ignoring it for mask.");
8242 : }
8243 :
8244 0 : CSLDestroy(papszGDALNoDataValues);
8245 : }
8246 : }
8247 :
8248 : /* -------------------------------------------------------------------- */
8249 : /* Check for nodata case. */
8250 : /* -------------------------------------------------------------------- */
8251 27777 : if (HasNoData())
8252 : {
8253 813 : nMaskFlags = GMF_NODATA;
8254 : try
8255 : {
8256 813 : poMask.reset(new GDALNoDataMaskBand(this), true);
8257 : }
8258 0 : catch (const std::bad_alloc &)
8259 : {
8260 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8261 0 : poMask.reset();
8262 : }
8263 813 : return poMask.get();
8264 : }
8265 :
8266 : /* -------------------------------------------------------------------- */
8267 : /* Check for alpha case. */
8268 : /* -------------------------------------------------------------------- */
8269 26952 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8270 54469 : this == poDS->GetRasterBand(1) &&
8271 552 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8272 : {
8273 197 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8274 : {
8275 153 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8276 153 : poMask.reset(poDS->GetRasterBand(2), false);
8277 153 : return poMask.get();
8278 : }
8279 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8280 : {
8281 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8282 : try
8283 : {
8284 23 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(2)),
8285 : true);
8286 : }
8287 0 : catch (const std::bad_alloc &)
8288 : {
8289 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8290 0 : poMask.reset();
8291 : }
8292 23 : return poMask.get();
8293 : }
8294 : }
8295 :
8296 26777 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8297 2682 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8298 54202 : this == poDS->GetRasterBand(3)) &&
8299 2093 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8300 : {
8301 1223 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8302 : {
8303 1176 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8304 1176 : poMask.reset(poDS->GetRasterBand(4), false);
8305 1176 : return poMask.get();
8306 : }
8307 47 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8308 : {
8309 35 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8310 : try
8311 : {
8312 35 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(4)),
8313 : true);
8314 : }
8315 0 : catch (const std::bad_alloc &)
8316 : {
8317 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8318 0 : poMask.reset();
8319 : }
8320 35 : return poMask.get();
8321 : }
8322 : }
8323 :
8324 : /* -------------------------------------------------------------------- */
8325 : /* Fallback to all valid case. */
8326 : /* -------------------------------------------------------------------- */
8327 25578 : nMaskFlags = GMF_ALL_VALID;
8328 : try
8329 : {
8330 25578 : poMask.reset(new GDALAllValidMaskBand(this), true);
8331 : }
8332 0 : catch (const std::bad_alloc &)
8333 : {
8334 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8335 0 : poMask.reset();
8336 : }
8337 :
8338 25576 : return poMask.get();
8339 : }
8340 :
8341 : /************************************************************************/
8342 : /* GDALGetMaskBand() */
8343 : /************************************************************************/
8344 :
8345 : /**
8346 : * \brief Return the mask band associated with the band.
8347 : *
8348 : * @see GDALRasterBand::GetMaskBand()
8349 : */
8350 :
8351 10943 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8352 :
8353 : {
8354 10943 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8355 :
8356 10943 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8357 10943 : return poBand->GetMaskBand();
8358 : }
8359 :
8360 : /************************************************************************/
8361 : /* GetMaskFlags() */
8362 : /************************************************************************/
8363 :
8364 : /**
8365 : * \brief Return the status flags of the mask band associated with the band.
8366 : *
8367 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8368 : * the following available definitions that may be extended in the future:
8369 : * <ul>
8370 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8371 : * 255. When used this will normally be the only flag set.
8372 : * </li>
8373 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8374 : * dataset.
8375 : * </li>
8376 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8377 : * and may have values other than 0 and 255.
8378 : * </li>
8379 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8380 : * nodata values. (mutually exclusive of GMF_ALPHA)
8381 : * </li>
8382 : * </ul>
8383 : *
8384 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8385 : * that returns one of four default implementations:
8386 : * <ul>
8387 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8388 : * </li>
8389 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8390 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8391 : * GMF_NODATA | GMF_PER_DATASET.
8392 : * </li>
8393 : * <li>If the band has a nodata value set, an instance of the new
8394 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8395 : * GMF_NODATA.
8396 : * </li>
8397 : * <li>If there is no nodata value, but the dataset has an alpha band that
8398 : * seems to apply to this band (specific rules yet to be determined) and that is
8399 : * of type GDT_Byte then that alpha band will be returned, and the flags
8400 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8401 : * </li>
8402 : * <li>If neither of the above apply, an instance of the new
8403 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8404 : * pixels. The null flags will return GMF_ALL_VALID.
8405 : * </li>
8406 : * </ul>
8407 : *
8408 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8409 : * dataset, with the same name as the main dataset and suffixed with .msk,
8410 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8411 : * main dataset.
8412 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8413 : * level, where xx matches the band number of a band of the main dataset. The
8414 : * value of those items is a combination of the flags GMF_ALL_VALID,
8415 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8416 : * a band, then the other rules explained above will be used to generate a
8417 : * on-the-fly mask band.
8418 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8419 : *
8420 : * This method is the same as the C function GDALGetMaskFlags().
8421 : *
8422 : * @since GDAL 1.5.0
8423 : *
8424 : * @return a valid mask band.
8425 : *
8426 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8427 : *
8428 : */
8429 78987 : int GDALRasterBand::GetMaskFlags()
8430 :
8431 : {
8432 : // If we don't have a band yet, force this now so that the masks value
8433 : // will be initialized.
8434 :
8435 78987 : if (poMask == nullptr)
8436 26653 : GetMaskBand();
8437 :
8438 78980 : return nMaskFlags;
8439 : }
8440 :
8441 : /************************************************************************/
8442 : /* GDALGetMaskFlags() */
8443 : /************************************************************************/
8444 :
8445 : /**
8446 : * \brief Return the status flags of the mask band associated with the band.
8447 : *
8448 : * @see GDALRasterBand::GetMaskFlags()
8449 : */
8450 :
8451 6269 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8452 :
8453 : {
8454 6269 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8455 :
8456 6269 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8457 6269 : return poBand->GetMaskFlags();
8458 : }
8459 :
8460 : /************************************************************************/
8461 : /* InvalidateMaskBand() */
8462 : /************************************************************************/
8463 :
8464 : //! @cond Doxygen_Suppress
8465 1200860 : void GDALRasterBand::InvalidateMaskBand()
8466 : {
8467 1200860 : poMask.reset();
8468 1200850 : nMaskFlags = 0;
8469 1200850 : }
8470 :
8471 : //! @endcond
8472 :
8473 : /************************************************************************/
8474 : /* CreateMaskBand() */
8475 : /************************************************************************/
8476 :
8477 : /**
8478 : * \brief Adds a mask band to the current band
8479 : *
8480 : * The default implementation of the CreateMaskBand() method is implemented
8481 : * based on similar rules to the .ovr handling implemented using the
8482 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8483 : * be created with the same basename as the original file, and it will have
8484 : * as many bands as the original image (or just one for GMF_PER_DATASET).
8485 : * The mask images will be deflate compressed tiled images with the same
8486 : * block size as the original image if possible.
8487 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8488 : * level, where xx matches the band number of a band of the main dataset. The
8489 : * value of those items will be the one of the nFlagsIn parameter.
8490 : *
8491 : * Note that if you got a mask band with a previous call to GetMaskBand(),
8492 : * it might be invalidated by CreateMaskBand(). So you have to call
8493 : * GetMaskBand() again.
8494 : *
8495 : * This method is the same as the C function GDALCreateMaskBand().
8496 : *
8497 : * @since GDAL 1.5.0
8498 : *
8499 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8500 : *
8501 : * @return CE_None on success or CE_Failure on an error.
8502 : *
8503 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8504 : * @see GDALDataset::CreateMaskBand()
8505 : *
8506 : */
8507 :
8508 9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8509 :
8510 : {
8511 9 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8512 : {
8513 9 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8514 9 : if (eErr != CE_None)
8515 1 : return eErr;
8516 :
8517 8 : InvalidateMaskBand();
8518 :
8519 8 : return CE_None;
8520 : }
8521 :
8522 0 : ReportError(CE_Failure, CPLE_NotSupported,
8523 : "CreateMaskBand() not supported for this band.");
8524 :
8525 0 : return CE_Failure;
8526 : }
8527 :
8528 : /************************************************************************/
8529 : /* GDALCreateMaskBand() */
8530 : /************************************************************************/
8531 :
8532 : /**
8533 : * \brief Adds a mask band to the current band
8534 : *
8535 : * @see GDALRasterBand::CreateMaskBand()
8536 : */
8537 :
8538 33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8539 :
8540 : {
8541 33 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8542 :
8543 33 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8544 33 : return poBand->CreateMaskBand(nFlags);
8545 : }
8546 :
8547 : /************************************************************************/
8548 : /* IsMaskBand() */
8549 : /************************************************************************/
8550 :
8551 : /**
8552 : * \brief Returns whether a band is a mask band.
8553 : *
8554 : * Mask band must be understood in the broad term: it can be a per-dataset
8555 : * mask band, an alpha band, or an implicit mask band.
8556 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8557 : *
8558 : * This method is the same as the C function GDALIsMaskBand().
8559 : *
8560 : * @return true if the band is a mask band.
8561 : *
8562 : * @see GDALDataset::CreateMaskBand()
8563 : *
8564 : * @since GDAL 3.5.0
8565 : *
8566 : */
8567 :
8568 409 : bool GDALRasterBand::IsMaskBand() const
8569 : {
8570 : // The GeoTIFF driver, among others, override this method to
8571 : // also handle external .msk bands.
8572 409 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8573 409 : GCI_AlphaBand;
8574 : }
8575 :
8576 : /************************************************************************/
8577 : /* GDALIsMaskBand() */
8578 : /************************************************************************/
8579 :
8580 : /**
8581 : * \brief Returns whether a band is a mask band.
8582 : *
8583 : * Mask band must be understood in the broad term: it can be a per-dataset
8584 : * mask band, an alpha band, or an implicit mask band.
8585 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8586 : *
8587 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8588 : *
8589 : * @return true if the band is a mask band.
8590 : *
8591 : * @see GDALRasterBand::IsMaskBand()
8592 : *
8593 : * @since GDAL 3.5.0
8594 : *
8595 : */
8596 :
8597 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
8598 :
8599 : {
8600 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8601 :
8602 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8603 37 : return poBand->IsMaskBand();
8604 : }
8605 :
8606 : /************************************************************************/
8607 : /* GetMaskValueRange() */
8608 : /************************************************************************/
8609 :
8610 : /**
8611 : * \brief Returns the range of values that a mask band can take.
8612 : *
8613 : * @return the range of values that a mask band can take.
8614 : *
8615 : * @since GDAL 3.5.0
8616 : *
8617 : */
8618 :
8619 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8620 : {
8621 0 : return GMVR_UNKNOWN;
8622 : }
8623 :
8624 : /************************************************************************/
8625 : /* GetIndexColorTranslationTo() */
8626 : /************************************************************************/
8627 :
8628 : /**
8629 : * \brief Compute translation table for color tables.
8630 : *
8631 : * When the raster band has a palette index, it may be useful to compute
8632 : * the "translation" of this palette to the palette of another band.
8633 : * The translation tries to do exact matching first, and then approximate
8634 : * matching if no exact matching is possible.
8635 : * This method returns a table such that table[i] = j where i is an index
8636 : * of the 'this' rasterband and j the corresponding index for the reference
8637 : * rasterband.
8638 : *
8639 : * This method is thought as internal to GDAL and is used for drivers
8640 : * like RPFTOC.
8641 : *
8642 : * The implementation only supports 1-byte palette rasterbands.
8643 : *
8644 : * @param poReferenceBand the raster band
8645 : * @param pTranslationTable an already allocated translation table (at least 256
8646 : * bytes), or NULL to let the method allocate it
8647 : * @param pApproximateMatching a pointer to a flag that is set if the matching
8648 : * is approximate. May be NULL.
8649 : *
8650 : * @return a translation table if the two bands are palette index and that they
8651 : * do not match or NULL in other cases. The table must be freed with CPLFree if
8652 : * NULL was passed for pTranslationTable.
8653 : */
8654 :
8655 : unsigned char *
8656 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8657 : unsigned char *pTranslationTable,
8658 : int *pApproximateMatching)
8659 : {
8660 4 : if (poReferenceBand == nullptr)
8661 0 : return nullptr;
8662 :
8663 : // cppcheck-suppress knownConditionTrueFalse
8664 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8665 : // cppcheck-suppress knownConditionTrueFalse
8666 4 : GetColorInterpretation() == GCI_PaletteIndex &&
8667 12 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
8668 4 : GetRasterDataType() == GDT_Byte)
8669 : {
8670 4 : const GDALColorTable *srcColorTable = GetColorTable();
8671 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8672 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
8673 : {
8674 4 : const int nEntries = srcColorTable->GetColorEntryCount();
8675 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
8676 :
8677 4 : int bHasNoDataValueSrc = FALSE;
8678 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8679 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8680 4 : dfNoDataValueSrc <= 255 &&
8681 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8682 0 : bHasNoDataValueSrc = FALSE;
8683 4 : const int noDataValueSrc =
8684 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8685 :
8686 4 : int bHasNoDataValueRef = FALSE;
8687 : const double dfNoDataValueRef =
8688 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8689 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8690 3 : dfNoDataValueRef <= 255 &&
8691 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8692 1 : bHasNoDataValueRef = FALSE;
8693 4 : const int noDataValueRef =
8694 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8695 :
8696 4 : bool samePalette = false;
8697 :
8698 4 : if (pApproximateMatching)
8699 3 : *pApproximateMatching = FALSE;
8700 :
8701 4 : if (nEntries == nRefEntries &&
8702 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
8703 3 : (bHasNoDataValueSrc == FALSE ||
8704 : noDataValueSrc == noDataValueRef))
8705 : {
8706 3 : samePalette = true;
8707 654 : for (int i = 0; i < nEntries; ++i)
8708 : {
8709 651 : if (noDataValueSrc == i)
8710 3 : continue;
8711 : const GDALColorEntry *entry =
8712 648 : srcColorTable->GetColorEntry(i);
8713 : const GDALColorEntry *entryRef =
8714 648 : destColorTable->GetColorEntry(i);
8715 648 : if (entry->c1 != entryRef->c1 ||
8716 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8717 : {
8718 0 : samePalette = false;
8719 : }
8720 : }
8721 : }
8722 :
8723 4 : if (!samePalette)
8724 : {
8725 1 : if (pTranslationTable == nullptr)
8726 : {
8727 : pTranslationTable = static_cast<unsigned char *>(
8728 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8729 1 : if (pTranslationTable == nullptr)
8730 1 : return nullptr;
8731 : }
8732 :
8733 : // Trying to remap the product palette on the subdataset
8734 : // palette.
8735 5 : for (int i = 0; i < nEntries; ++i)
8736 : {
8737 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8738 : noDataValueSrc == i)
8739 0 : continue;
8740 : const GDALColorEntry *entry =
8741 4 : srcColorTable->GetColorEntry(i);
8742 4 : bool bMatchFound = false;
8743 13 : for (int j = 0; j < nRefEntries; ++j)
8744 : {
8745 10 : if (bHasNoDataValueRef && noDataValueRef == j)
8746 0 : continue;
8747 : const GDALColorEntry *entryRef =
8748 10 : destColorTable->GetColorEntry(j);
8749 10 : if (entry->c1 == entryRef->c1 &&
8750 2 : entry->c2 == entryRef->c2 &&
8751 2 : entry->c3 == entryRef->c3)
8752 : {
8753 1 : pTranslationTable[i] =
8754 : static_cast<unsigned char>(j);
8755 1 : bMatchFound = true;
8756 1 : break;
8757 : }
8758 : }
8759 4 : if (!bMatchFound)
8760 : {
8761 : // No exact match. Looking for closest color now.
8762 3 : int best_j = 0;
8763 3 : int best_distance = 0;
8764 3 : if (pApproximateMatching)
8765 0 : *pApproximateMatching = TRUE;
8766 12 : for (int j = 0; j < nRefEntries; ++j)
8767 : {
8768 : const GDALColorEntry *entryRef =
8769 9 : destColorTable->GetColorEntry(j);
8770 9 : int distance = (entry->c1 - entryRef->c1) *
8771 9 : (entry->c1 - entryRef->c1) +
8772 9 : (entry->c2 - entryRef->c2) *
8773 9 : (entry->c2 - entryRef->c2) +
8774 9 : (entry->c3 - entryRef->c3) *
8775 9 : (entry->c3 - entryRef->c3);
8776 9 : if (j == 0 || distance < best_distance)
8777 : {
8778 7 : best_j = j;
8779 7 : best_distance = distance;
8780 : }
8781 : }
8782 3 : pTranslationTable[i] =
8783 : static_cast<unsigned char>(best_j);
8784 : }
8785 : }
8786 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
8787 0 : pTranslationTable[noDataValueSrc] =
8788 : static_cast<unsigned char>(noDataValueRef);
8789 :
8790 1 : return pTranslationTable;
8791 : }
8792 : }
8793 : }
8794 3 : return nullptr;
8795 : }
8796 :
8797 : /************************************************************************/
8798 : /* SetFlushBlockErr() */
8799 : /************************************************************************/
8800 :
8801 : /**
8802 : * \brief Store that an error occurred while writing a dirty block.
8803 : *
8804 : * This function stores the fact that an error occurred while writing a dirty
8805 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8806 : * flushed when the block cache get full, it is not convenient/possible to
8807 : * report that a dirty block could not be written correctly. This function
8808 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8809 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8810 : * places where the user can easily match the error with the relevant dataset.
8811 : */
8812 :
8813 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8814 : {
8815 0 : eFlushBlockErr = eErr;
8816 0 : }
8817 :
8818 : /************************************************************************/
8819 : /* IncDirtyBlocks() */
8820 : /************************************************************************/
8821 :
8822 : /**
8823 : * \brief Increment/decrement the number of dirty blocks
8824 : */
8825 :
8826 536715 : void GDALRasterBand::IncDirtyBlocks(int nInc)
8827 : {
8828 536715 : if (poBandBlockCache)
8829 536714 : poBandBlockCache->IncDirtyBlocks(nInc);
8830 536712 : }
8831 :
8832 : /************************************************************************/
8833 : /* ReportError() */
8834 : /************************************************************************/
8835 :
8836 : #ifndef DOXYGEN_XML
8837 : /**
8838 : * \brief Emits an error related to a raster band.
8839 : *
8840 : * This function is a wrapper for regular CPLError(). The only difference
8841 : * with CPLError() is that it prepends the error message with the dataset
8842 : * name and the band number.
8843 : *
8844 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
8845 : * @param err_no the error number (CPLE_*) from cpl_error.h.
8846 : * @param fmt a printf() style format string. Any additional arguments
8847 : * will be treated as arguments to fill in this format in a manner
8848 : * similar to printf().
8849 : *
8850 : * @since GDAL 1.9.0
8851 : */
8852 :
8853 2447 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
8854 : const char *fmt, ...) const
8855 : {
8856 : va_list args;
8857 :
8858 2447 : va_start(args, fmt);
8859 :
8860 2447 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
8861 2446 : pszDSName = CPLGetFilename(pszDSName);
8862 2447 : if (pszDSName[0] != '\0')
8863 : {
8864 2384 : CPLError(eErrClass, err_no, "%s",
8865 4768 : CPLString()
8866 2384 : .Printf("%s, band %d: ", pszDSName, GetBand())
8867 4768 : .append(CPLString().vPrintf(fmt, args))
8868 : .c_str());
8869 : }
8870 : else
8871 : {
8872 63 : CPLErrorV(eErrClass, err_no, fmt, args);
8873 : }
8874 :
8875 2447 : va_end(args);
8876 2447 : }
8877 : #endif
8878 :
8879 : /************************************************************************/
8880 : /* GetVirtualMemAuto() */
8881 : /************************************************************************/
8882 :
8883 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
8884 : *
8885 : * Only supported on Linux and Unix systems with mmap() for now.
8886 : *
8887 : * This method allows creating a virtual memory object for a GDALRasterBand,
8888 : * that exposes the whole image data as a virtual array.
8889 : *
8890 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
8891 : * specialized implementation, such as for raw files, may also directly use
8892 : * mechanisms of the operating system to create a view of the underlying file
8893 : * into virtual memory ( CPLVirtualMemFileMapNew() )
8894 : *
8895 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
8896 : * offer a specialized implementation with direct file mapping, provided that
8897 : * some requirements are met :
8898 : * - for all drivers, the dataset must be backed by a "real" file in the file
8899 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
8900 : * must match the native ordering of the CPU.
8901 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
8902 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
8903 : * the file in sequential order, and be equally spaced (which is generally the
8904 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
8905 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
8906 : *
8907 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
8908 : * CPLVirtualMemFree() must be called before the raster band object is
8909 : * destroyed.
8910 : *
8911 : * If p is such a pointer and base_type the type matching
8912 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
8913 : * accessed with
8914 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
8915 : *
8916 : * This method is the same as the C GDALGetVirtualMemAuto() function.
8917 : *
8918 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
8919 : * read/write the band.
8920 : *
8921 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
8922 : * one pixel value in the buffer to the start of the next pixel value within a
8923 : * scanline.
8924 : *
8925 : * @param pnLineSpace Output parameter giving the byte offset from the start of
8926 : * one scanline in the buffer to the start of the next.
8927 : *
8928 : * @param papszOptions NULL terminated list of options.
8929 : * If a specialized implementation exists, defining
8930 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
8931 : * used. On the contrary, starting with GDAL 2.2, defining
8932 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
8933 : * being used (thus only allowing efficient implementations to be used). When
8934 : * requiring or falling back to the default implementation, the following
8935 : * options are available : CACHE_SIZE (in bytes, defaults to
8936 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
8937 : * to FALSE)
8938 : *
8939 : * @return a virtual memory object that must be unreferenced by
8940 : * CPLVirtualMemFree(), or NULL in case of failure.
8941 : *
8942 : * @since GDAL 1.11
8943 : */
8944 :
8945 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
8946 : int *pnPixelSpace,
8947 : GIntBig *pnLineSpace,
8948 : char **papszOptions)
8949 : {
8950 9 : const char *pszImpl = CSLFetchNameValueDef(
8951 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
8952 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
8953 8 : EQUAL(pszImpl, "FALSE"))
8954 : {
8955 1 : return nullptr;
8956 : }
8957 :
8958 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
8959 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
8960 8 : if (pnPixelSpace)
8961 8 : *pnPixelSpace = nPixelSpace;
8962 8 : if (pnLineSpace)
8963 8 : *pnLineSpace = nLineSpace;
8964 : const size_t nCacheSize =
8965 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
8966 : const size_t nPageSizeHint =
8967 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
8968 8 : const bool bSingleThreadUsage = CPLTestBool(
8969 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
8970 8 : return GDALRasterBandGetVirtualMem(
8971 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
8972 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
8973 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
8974 8 : papszOptions);
8975 : }
8976 :
8977 : /************************************************************************/
8978 : /* GDALGetVirtualMemAuto() */
8979 : /************************************************************************/
8980 :
8981 : /**
8982 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
8983 : *
8984 : * @see GDALRasterBand::GetVirtualMemAuto()
8985 : */
8986 :
8987 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
8988 : int *pnPixelSpace, GIntBig *pnLineSpace,
8989 : CSLConstList papszOptions)
8990 : {
8991 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
8992 :
8993 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8994 :
8995 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
8996 31 : const_cast<char **>(papszOptions));
8997 : }
8998 :
8999 : /************************************************************************/
9000 : /* GDALGetDataCoverageStatus() */
9001 : /************************************************************************/
9002 :
9003 : /**
9004 : * \brief Get the coverage status of a sub-window of the raster.
9005 : *
9006 : * Returns whether a sub-window of the raster contains only data, only empty
9007 : * blocks or a mix of both. This function can be used to determine quickly
9008 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9009 : * be sparse.
9010 : *
9011 : * Empty blocks are blocks that are generally not physically present in the
9012 : * file, and when read through GDAL, contain only pixels whose value is the
9013 : * nodata value when it is set, or whose value is 0 when the nodata value is
9014 : * not set.
9015 : *
9016 : * The query is done in an efficient way without reading the actual pixel
9017 : * values. If not possible, or not implemented at all by the driver,
9018 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9019 : * be returned.
9020 : *
9021 : * The values that can be returned by the function are the following,
9022 : * potentially combined with the binary or operator :
9023 : * <ul>
9024 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9025 : * GetDataCoverageStatus(). This flag should be returned together with
9026 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9027 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9028 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9029 : * the queried window. This is typically identified by the concept of missing
9030 : * block in formats that supports it.
9031 : * </li>
9032 : * </ul>
9033 : *
9034 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9035 : * should be interpreted more as hint of potential presence of data. For example
9036 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9037 : * nodata value), instead of using the missing block mechanism,
9038 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9039 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9040 : *
9041 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9042 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9043 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9044 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9045 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9046 : * the function will exit, so that you can potentially refine the requested area
9047 : * to find which particular region(s) have missing blocks.
9048 : *
9049 : * @see GDALRasterBand::GetDataCoverageStatus()
9050 : *
9051 : * @param hBand raster band
9052 : *
9053 : * @param nXOff The pixel offset to the top left corner of the region
9054 : * of the band to be queried. This would be zero to start from the left side.
9055 : *
9056 : * @param nYOff The line offset to the top left corner of the region
9057 : * of the band to be queried. This would be zero to start from the top.
9058 : *
9059 : * @param nXSize The width of the region of the band to be queried in pixels.
9060 : *
9061 : * @param nYSize The height of the region of the band to be queried in lines.
9062 : *
9063 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9064 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9065 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9066 : * as the computation of the coverage matches the mask, the computation will be
9067 : * stopped. *pdfDataPct will not be valid in that case.
9068 : *
9069 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9070 : * to the (approximate) percentage in [0,100] of pixels in the queried
9071 : * sub-window that have valid values. The implementation might not always be
9072 : * able to compute it, in which case it will be set to a negative value.
9073 : *
9074 : * @return a binary-or'ed combination of possible values
9075 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9076 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9077 : *
9078 : * @note Added in GDAL 2.2
9079 : */
9080 :
9081 26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
9082 : int nYOff, int nXSize, int nYSize,
9083 : int nMaskFlagStop, double *pdfDataPct)
9084 : {
9085 26 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
9086 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
9087 :
9088 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9089 :
9090 26 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
9091 26 : nMaskFlagStop, pdfDataPct);
9092 : }
9093 :
9094 : /************************************************************************/
9095 : /* GetDataCoverageStatus() */
9096 : /************************************************************************/
9097 :
9098 : /**
9099 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
9100 : * int nYOff,
9101 : * int nXSize,
9102 : * int nYSize,
9103 : * int nMaskFlagStop,
9104 : * double* pdfDataPct)
9105 : * \brief Get the coverage status of a sub-window of the raster.
9106 : *
9107 : * Returns whether a sub-window of the raster contains only data, only empty
9108 : * blocks or a mix of both. This function can be used to determine quickly
9109 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9110 : * be sparse.
9111 : *
9112 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9113 : * value when it is set, or whose value is 0 when the nodata value is not set.
9114 : *
9115 : * The query is done in an efficient way without reading the actual pixel
9116 : * values. If not possible, or not implemented at all by the driver,
9117 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9118 : * be returned.
9119 : *
9120 : * The values that can be returned by the function are the following,
9121 : * potentially combined with the binary or operator :
9122 : * <ul>
9123 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9124 : * GetDataCoverageStatus(). This flag should be returned together with
9125 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9126 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9127 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9128 : * the queried window. This is typically identified by the concept of missing
9129 : * block in formats that supports it.
9130 : * </li>
9131 : * </ul>
9132 : *
9133 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9134 : * should be interpreted more as hint of potential presence of data. For example
9135 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9136 : * nodata value), instead of using the missing block mechanism,
9137 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9138 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9139 : *
9140 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9141 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9142 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9143 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9144 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9145 : * the function will exit, so that you can potentially refine the requested area
9146 : * to find which particular region(s) have missing blocks.
9147 : *
9148 : * @see GDALGetDataCoverageStatus()
9149 : *
9150 : * @param nXOff The pixel offset to the top left corner of the region
9151 : * of the band to be queried. This would be zero to start from the left side.
9152 : *
9153 : * @param nYOff The line offset to the top left corner of the region
9154 : * of the band to be queried. This would be zero to start from the top.
9155 : *
9156 : * @param nXSize The width of the region of the band to be queried in pixels.
9157 : *
9158 : * @param nYSize The height of the region of the band to be queried in lines.
9159 : *
9160 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9161 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9162 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9163 : * as the computation of the coverage matches the mask, the computation will be
9164 : * stopped. *pdfDataPct will not be valid in that case.
9165 : *
9166 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9167 : * to the (approximate) percentage in [0,100] of pixels in the queried
9168 : * sub-window that have valid values. The implementation might not always be
9169 : * able to compute it, in which case it will be set to a negative value.
9170 : *
9171 : * @return a binary-or'ed combination of possible values
9172 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9173 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9174 : *
9175 : * @note Added in GDAL 2.2
9176 : */
9177 :
9178 : /**
9179 : * \brief Get the coverage status of a sub-window of the raster.
9180 : *
9181 : * Returns whether a sub-window of the raster contains only data, only empty
9182 : * blocks or a mix of both. This function can be used to determine quickly
9183 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9184 : * be sparse.
9185 : *
9186 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9187 : * value when it is set, or whose value is 0 when the nodata value is not set.
9188 : *
9189 : * The query is done in an efficient way without reading the actual pixel
9190 : * values. If not possible, or not implemented at all by the driver,
9191 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9192 : * be returned.
9193 : *
9194 : * The values that can be returned by the function are the following,
9195 : * potentially combined with the binary or operator :
9196 : * <ul>
9197 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9198 : * GetDataCoverageStatus(). This flag should be returned together with
9199 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9200 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9201 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9202 : * the queried window. This is typically identified by the concept of missing
9203 : * block in formats that supports it.
9204 : * </li>
9205 : * </ul>
9206 : *
9207 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9208 : * should be interpreted more as hint of potential presence of data. For example
9209 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9210 : * nodata value), instead of using the missing block mechanism,
9211 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9212 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9213 : *
9214 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9215 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9216 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9217 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9218 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9219 : * the function will exit, so that you can potentially refine the requested area
9220 : * to find which particular region(s) have missing blocks.
9221 : *
9222 : * @see GDALGetDataCoverageStatus()
9223 : *
9224 : * @param nXOff The pixel offset to the top left corner of the region
9225 : * of the band to be queried. This would be zero to start from the left side.
9226 : *
9227 : * @param nYOff The line offset to the top left corner of the region
9228 : * of the band to be queried. This would be zero to start from the top.
9229 : *
9230 : * @param nXSize The width of the region of the band to be queried in pixels.
9231 : *
9232 : * @param nYSize The height of the region of the band to be queried in lines.
9233 : *
9234 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9235 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9236 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9237 : * as the computation of the coverage matches the mask, the computation will be
9238 : * stopped. *pdfDataPct will not be valid in that case.
9239 : *
9240 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9241 : * to the (approximate) percentage in [0,100] of pixels in the queried
9242 : * sub-window that have valid values. The implementation might not always be
9243 : * able to compute it, in which case it will be set to a negative value.
9244 : *
9245 : * @return a binary-or'ed combination of possible values
9246 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9247 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9248 : *
9249 : * @note Added in GDAL 2.2
9250 : */
9251 :
9252 4499 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9253 : int nYSize, int nMaskFlagStop,
9254 : double *pdfDataPct)
9255 : {
9256 4499 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9257 4499 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9258 4499 : nYOff + nYSize > nRasterYSize)
9259 : {
9260 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9261 0 : if (pdfDataPct)
9262 0 : *pdfDataPct = 0.0;
9263 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9264 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
9265 : }
9266 4499 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9267 4499 : pdfDataPct);
9268 : }
9269 :
9270 : /************************************************************************/
9271 : /* IGetDataCoverageStatus() */
9272 : /************************************************************************/
9273 :
9274 635 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9275 : int /*nXSize*/, int /*nYSize*/,
9276 : int /*nMaskFlagStop*/,
9277 : double *pdfDataPct)
9278 : {
9279 635 : if (pdfDataPct != nullptr)
9280 0 : *pdfDataPct = 100.0;
9281 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9282 635 : GDAL_DATA_COVERAGE_STATUS_DATA;
9283 : }
9284 :
9285 : //! @cond Doxygen_Suppress
9286 : /************************************************************************/
9287 : /* EnterReadWrite() */
9288 : /************************************************************************/
9289 :
9290 6913420 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9291 : {
9292 6913420 : if (poDS != nullptr)
9293 6161400 : return poDS->EnterReadWrite(eRWFlag);
9294 752012 : return FALSE;
9295 : }
9296 :
9297 : /************************************************************************/
9298 : /* LeaveReadWrite() */
9299 : /************************************************************************/
9300 :
9301 643502 : void GDALRasterBand::LeaveReadWrite()
9302 : {
9303 643502 : if (poDS != nullptr)
9304 642993 : poDS->LeaveReadWrite();
9305 643594 : }
9306 :
9307 : /************************************************************************/
9308 : /* InitRWLock() */
9309 : /************************************************************************/
9310 :
9311 3655740 : void GDALRasterBand::InitRWLock()
9312 : {
9313 3655740 : if (poDS != nullptr)
9314 3655340 : poDS->InitRWLock();
9315 3655740 : }
9316 :
9317 : //! @endcond
9318 :
9319 : // clang-format off
9320 :
9321 : /**
9322 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9323 : * \brief Set metadata.
9324 : *
9325 : * CAUTION: depending on the format, older values of the updated information
9326 : * might still be found in the file in a "ghost" state, even if no longer
9327 : * accessible through the GDAL API. This is for example the case of the GTiff
9328 : * format (this is not a exhaustive list)
9329 : *
9330 : * The C function GDALSetMetadata() does the same thing as this method.
9331 : *
9332 : * @param papszMetadata the metadata in name=value string list format to
9333 : * apply.
9334 : * @param pszDomain the domain of interest. Use "" or NULL for the default
9335 : * domain.
9336 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9337 : * metadata has been accepted, but is likely not maintained persistently
9338 : * by the underlying object between sessions.
9339 : */
9340 :
9341 : /**
9342 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9343 : * \brief Set single metadata item.
9344 : *
9345 : * CAUTION: depending on the format, older values of the updated information
9346 : * might still be found in the file in a "ghost" state, even if no longer
9347 : * accessible through the GDAL API. This is for example the case of the GTiff
9348 : * format (this is not a exhaustive list)
9349 : *
9350 : * The C function GDALSetMetadataItem() does the same thing as this method.
9351 : *
9352 : * @param pszName the key for the metadata item to fetch.
9353 : * @param pszValue the value to assign to the key.
9354 : * @param pszDomain the domain to set within, use NULL for the default domain.
9355 : *
9356 : * @return CE_None on success, or an error code on failure.
9357 : */
9358 :
9359 : // clang-format on
9360 :
9361 : //! @cond Doxygen_Suppress
9362 : /************************************************************************/
9363 : /* EnablePixelTypeSignedByteWarning() */
9364 : /************************************************************************/
9365 :
9366 27027 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9367 : {
9368 27027 : m_bEnablePixelTypeSignedByteWarning = b;
9369 27027 : }
9370 :
9371 8416 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9372 : {
9373 8416 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9374 8416 : }
9375 :
9376 : //! @endcond
9377 :
9378 : /************************************************************************/
9379 : /* GetMetadataItem() */
9380 : /************************************************************************/
9381 :
9382 61392 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9383 : const char *pszDomain)
9384 : {
9385 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9386 61392 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9387 37060 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9388 28128 : EQUAL(pszName, "PIXELTYPE"))
9389 : {
9390 2 : CPLError(CE_Warning, CPLE_AppDefined,
9391 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9392 : "used to signal signed 8-bit raster. Change your code to "
9393 : "test for the new GDT_Int8 data type instead.");
9394 : }
9395 61392 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9396 : }
9397 :
9398 : /************************************************************************/
9399 : /* GDALMDArrayFromRasterBand */
9400 : /************************************************************************/
9401 :
9402 : class GDALMDArrayFromRasterBand final : public GDALMDArray
9403 : {
9404 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9405 :
9406 : GDALDataset *m_poDS;
9407 : GDALRasterBand *m_poBand;
9408 : GDALExtendedDataType m_dt;
9409 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9410 : std::string m_osUnit;
9411 : std::vector<GByte> m_pabyNoData{};
9412 : std::shared_ptr<GDALMDArray> m_varX{};
9413 : std::shared_ptr<GDALMDArray> m_varY{};
9414 : std::string m_osFilename{};
9415 :
9416 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9417 : const size_t *count, const GInt64 *arrayStep,
9418 : const GPtrDiff_t *bufferStride,
9419 : const GDALExtendedDataType &bufferDataType,
9420 : void *pBuffer) const;
9421 :
9422 : protected:
9423 23 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9424 46 : : GDALAbstractMDArray(std::string(),
9425 46 : std::string(poDS->GetDescription()) +
9426 : CPLSPrintf(" band %d", poBand->GetBand())),
9427 46 : GDALMDArray(std::string(),
9428 46 : std::string(poDS->GetDescription()) +
9429 : CPLSPrintf(" band %d", poBand->GetBand())),
9430 : m_poDS(poDS), m_poBand(poBand),
9431 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9432 115 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9433 : {
9434 23 : m_poDS->Reference();
9435 :
9436 23 : int bHasNoData = false;
9437 23 : if (m_poBand->GetRasterDataType() == GDT_Int64)
9438 : {
9439 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9440 0 : if (bHasNoData)
9441 : {
9442 0 : m_pabyNoData.resize(m_dt.GetSize());
9443 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9444 : m_dt.GetNumericDataType(), 0, 1);
9445 : }
9446 : }
9447 23 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9448 : {
9449 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9450 0 : if (bHasNoData)
9451 : {
9452 0 : m_pabyNoData.resize(m_dt.GetSize());
9453 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9454 : m_dt.GetNumericDataType(), 0, 1);
9455 : }
9456 : }
9457 : else
9458 : {
9459 23 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9460 23 : if (bHasNoData)
9461 : {
9462 1 : m_pabyNoData.resize(m_dt.GetSize());
9463 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9464 : m_dt.GetNumericDataType(), 0, 1);
9465 : }
9466 : }
9467 :
9468 23 : const int nXSize = poBand->GetXSize();
9469 23 : const int nYSize = poBand->GetYSize();
9470 :
9471 23 : auto poSRS = m_poDS->GetSpatialRef();
9472 46 : std::string osTypeY;
9473 46 : std::string osTypeX;
9474 46 : std::string osDirectionY;
9475 46 : std::string osDirectionX;
9476 23 : if (poSRS && poSRS->GetAxesCount() == 2)
9477 : {
9478 21 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9479 21 : OGRAxisOrientation eOrientation1 = OAO_Other;
9480 21 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
9481 21 : OGRAxisOrientation eOrientation2 = OAO_Other;
9482 21 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
9483 21 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9484 : {
9485 5 : if (mapping == std::vector<int>{1, 2})
9486 : {
9487 5 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9488 5 : osDirectionY = "NORTH";
9489 5 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9490 5 : osDirectionX = "EAST";
9491 : }
9492 : }
9493 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9494 : {
9495 16 : if (mapping == std::vector<int>{2, 1})
9496 : {
9497 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9498 16 : osDirectionY = "NORTH";
9499 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9500 16 : osDirectionX = "EAST";
9501 : }
9502 : }
9503 : }
9504 :
9505 115 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9506 : "/", "Y", osTypeY, osDirectionY, nYSize),
9507 46 : std::make_shared<GDALDimensionWeakIndexingVar>(
9508 69 : "/", "X", osTypeX, osDirectionX, nXSize)};
9509 :
9510 : double adfGeoTransform[6];
9511 23 : if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
9512 23 : adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
9513 : {
9514 44 : m_varX = GDALMDArrayRegularlySpaced::Create(
9515 22 : "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
9516 22 : 0.5);
9517 22 : m_dims[1]->SetIndexingVariable(m_varX);
9518 :
9519 44 : m_varY = GDALMDArrayRegularlySpaced::Create(
9520 22 : "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
9521 22 : 0.5);
9522 22 : m_dims[0]->SetIndexingVariable(m_varY);
9523 : }
9524 23 : }
9525 :
9526 31 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9527 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9528 : const GDALExtendedDataType &bufferDataType,
9529 : void *pDstBuffer) const override
9530 : {
9531 31 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9532 31 : bufferDataType, pDstBuffer);
9533 : }
9534 :
9535 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9536 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9537 : const GDALExtendedDataType &bufferDataType,
9538 : const void *pSrcBuffer) override
9539 : {
9540 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9541 : bufferStride, bufferDataType,
9542 1 : const_cast<void *>(pSrcBuffer));
9543 : }
9544 :
9545 : public:
9546 46 : ~GDALMDArrayFromRasterBand()
9547 23 : {
9548 23 : m_poDS->ReleaseRef();
9549 46 : }
9550 :
9551 23 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9552 : GDALRasterBand *poBand)
9553 : {
9554 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9555 46 : new GDALMDArrayFromRasterBand(poDS, poBand)));
9556 23 : array->SetSelf(array);
9557 46 : return array;
9558 : }
9559 :
9560 2 : bool IsWritable() const override
9561 : {
9562 2 : return m_poDS->GetAccess() == GA_Update;
9563 : }
9564 :
9565 97 : const std::string &GetFilename() const override
9566 : {
9567 97 : return m_osFilename;
9568 : }
9569 :
9570 : const std::vector<std::shared_ptr<GDALDimension>> &
9571 299 : GetDimensions() const override
9572 : {
9573 299 : return m_dims;
9574 : }
9575 :
9576 138 : const GDALExtendedDataType &GetDataType() const override
9577 : {
9578 138 : return m_dt;
9579 : }
9580 :
9581 3 : const std::string &GetUnit() const override
9582 : {
9583 3 : return m_osUnit;
9584 : }
9585 :
9586 29 : const void *GetRawNoDataValue() const override
9587 : {
9588 29 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9589 : }
9590 :
9591 2 : double GetOffset(bool *pbHasOffset,
9592 : GDALDataType *peStorageType) const override
9593 : {
9594 2 : int bHasOffset = false;
9595 2 : double dfRes = m_poBand->GetOffset(&bHasOffset);
9596 2 : if (pbHasOffset)
9597 2 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9598 2 : if (peStorageType)
9599 1 : *peStorageType = GDT_Unknown;
9600 2 : return dfRes;
9601 : }
9602 :
9603 2 : double GetScale(bool *pbHasScale,
9604 : GDALDataType *peStorageType) const override
9605 : {
9606 2 : int bHasScale = false;
9607 2 : double dfRes = m_poBand->GetScale(&bHasScale);
9608 2 : if (pbHasScale)
9609 2 : *pbHasScale = CPL_TO_BOOL(bHasScale);
9610 2 : if (peStorageType)
9611 1 : *peStorageType = GDT_Unknown;
9612 2 : return dfRes;
9613 : }
9614 :
9615 84 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9616 : {
9617 84 : auto poSrcSRS = m_poDS->GetSpatialRef();
9618 84 : if (!poSrcSRS)
9619 2 : return nullptr;
9620 164 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9621 :
9622 164 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9623 82 : constexpr int iYDim = 0;
9624 82 : constexpr int iXDim = 1;
9625 246 : for (auto &m : axisMapping)
9626 : {
9627 164 : if (m == 1)
9628 82 : m = iXDim + 1;
9629 82 : else if (m == 2)
9630 82 : m = iYDim + 1;
9631 : else
9632 0 : m = 0;
9633 : }
9634 82 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9635 82 : return poSRS;
9636 : }
9637 :
9638 29 : std::vector<GUInt64> GetBlockSize() const override
9639 : {
9640 29 : int nBlockXSize = 0;
9641 29 : int nBlockYSize = 0;
9642 29 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9643 29 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9644 29 : static_cast<GUInt64>(nBlockXSize)};
9645 : }
9646 :
9647 : class MDIAsAttribute : public GDALAttribute
9648 : {
9649 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9650 : const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
9651 : std::string m_osValue;
9652 :
9653 : public:
9654 2 : MDIAsAttribute(const std::string &name, const std::string &value)
9655 2 : : GDALAbstractMDArray(std::string(), name),
9656 4 : GDALAttribute(std::string(), name), m_osValue(value)
9657 : {
9658 2 : }
9659 :
9660 : const std::vector<std::shared_ptr<GDALDimension>> &
9661 3 : GetDimensions() const override
9662 : {
9663 3 : return m_dims;
9664 : }
9665 :
9666 2 : const GDALExtendedDataType &GetDataType() const override
9667 : {
9668 2 : return m_dt;
9669 : }
9670 :
9671 1 : bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
9672 : const GPtrDiff_t *,
9673 : const GDALExtendedDataType &bufferDataType,
9674 : void *pDstBuffer) const override
9675 : {
9676 1 : const char *pszStr = m_osValue.c_str();
9677 1 : GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
9678 : bufferDataType);
9679 1 : return true;
9680 : }
9681 : };
9682 :
9683 : std::vector<std::shared_ptr<GDALAttribute>>
9684 14 : GetAttributes(CSLConstList) const override
9685 : {
9686 14 : std::vector<std::shared_ptr<GDALAttribute>> res;
9687 14 : auto papszMD = m_poBand->GetMetadata();
9688 16 : for (auto iter = papszMD; iter && iter[0]; ++iter)
9689 : {
9690 2 : char *pszKey = nullptr;
9691 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9692 2 : if (pszKey && pszValue)
9693 : {
9694 : res.emplace_back(
9695 2 : std::make_shared<MDIAsAttribute>(pszKey, pszValue));
9696 : }
9697 2 : CPLFree(pszKey);
9698 : }
9699 14 : return res;
9700 : }
9701 : };
9702 :
9703 : /************************************************************************/
9704 : /* ReadWrite() */
9705 : /************************************************************************/
9706 :
9707 32 : bool GDALMDArrayFromRasterBand::ReadWrite(
9708 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
9709 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9710 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
9711 : {
9712 32 : constexpr size_t iDimX = 1;
9713 32 : constexpr size_t iDimY = 0;
9714 32 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
9715 : arrayStartIdx, count, arrayStep, bufferStride,
9716 32 : bufferDataType, pBuffer);
9717 : }
9718 :
9719 : /************************************************************************/
9720 : /* GDALMDRasterIOFromBand() */
9721 : /************************************************************************/
9722 :
9723 65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
9724 : size_t iDimX, size_t iDimY,
9725 : const GUInt64 *arrayStartIdx, const size_t *count,
9726 : const GInt64 *arrayStep,
9727 : const GPtrDiff_t *bufferStride,
9728 : const GDALExtendedDataType &bufferDataType,
9729 : void *pBuffer)
9730 : {
9731 65 : const auto eDT(bufferDataType.GetNumericDataType());
9732 65 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
9733 65 : const int nX =
9734 65 : arrayStep[iDimX] > 0
9735 65 : ? static_cast<int>(arrayStartIdx[iDimX])
9736 2 : : static_cast<int>(arrayStartIdx[iDimX] -
9737 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
9738 65 : const int nY =
9739 65 : arrayStep[iDimY] > 0
9740 65 : ? static_cast<int>(arrayStartIdx[iDimY])
9741 2 : : static_cast<int>(arrayStartIdx[iDimY] -
9742 2 : (count[iDimY] - 1) * -arrayStep[iDimY]);
9743 65 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
9744 65 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
9745 65 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
9746 65 : int nStrideXSign = 1;
9747 65 : if (arrayStep[iDimX] < 0)
9748 : {
9749 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
9750 2 : nStrideXSign = -1;
9751 : }
9752 65 : int nStrideYSign = 1;
9753 65 : if (arrayStep[iDimY] < 0)
9754 : {
9755 2 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
9756 2 : nStrideYSign = -1;
9757 : }
9758 :
9759 130 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
9760 65 : static_cast<int>(count[iDimX]),
9761 65 : static_cast<int>(count[iDimY]), eDT,
9762 : static_cast<GSpacing>(
9763 65 : nStrideXSign * bufferStride[iDimX] * nDTSize),
9764 : static_cast<GSpacing>(
9765 65 : nStrideYSign * bufferStride[iDimY] * nDTSize),
9766 65 : nullptr) == CE_None;
9767 : }
9768 :
9769 : /************************************************************************/
9770 : /* AsMDArray() */
9771 : /************************************************************************/
9772 :
9773 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
9774 : *
9775 : * The band must be linked to a GDALDataset. If this dataset is not already
9776 : * marked as shared, it will be, so that the returned array holds a reference
9777 : * to it.
9778 : *
9779 : * If the dataset has a geotransform attached, the X and Y dimensions of the
9780 : * returned array will have an associated indexing variable.
9781 : *
9782 : * This is the same as the C function GDALRasterBandAsMDArray().
9783 : *
9784 : * The "reverse" method is GDALMDArray::AsClassicDataset().
9785 : *
9786 : * @return a new array, or nullptr.
9787 : *
9788 : * @since GDAL 3.1
9789 : */
9790 23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
9791 : {
9792 23 : if (!poDS)
9793 : {
9794 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
9795 0 : return nullptr;
9796 : }
9797 23 : if (!poDS->GetShared())
9798 : {
9799 23 : poDS->MarkAsShared();
9800 : }
9801 : return GDALMDArrayFromRasterBand::Create(
9802 23 : poDS, const_cast<GDALRasterBand *>(this));
9803 : }
9804 :
9805 : /************************************************************************/
9806 : /* InterpolateAtPoint() */
9807 : /************************************************************************/
9808 :
9809 : /**
9810 : * \brief Interpolates the value between pixels using a resampling algorithm,
9811 : * taking pixel/line coordinates as input.
9812 : *
9813 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
9814 : * @param dfLine line coordinate as a double, where interpolation should be done.
9815 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
9816 : * @param pdfRealValue pointer to real part of interpolated value
9817 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
9818 : *
9819 : * @return CE_None on success, or an error code on failure.
9820 : * @since GDAL 3.10
9821 : */
9822 :
9823 124 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
9824 : GDALRIOResampleAlg eInterpolation,
9825 : double *pdfRealValue,
9826 : double *pdfImagValue) const
9827 : {
9828 124 : if (eInterpolation != GRIORA_NearestNeighbour &&
9829 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
9830 : eInterpolation != GRIORA_CubicSpline)
9831 : {
9832 2 : CPLError(CE_Failure, CPLE_AppDefined,
9833 : "Only nearest, bilinear, cubic and cubicspline interpolation "
9834 : "methods "
9835 : "allowed");
9836 :
9837 2 : return CE_Failure;
9838 : }
9839 :
9840 122 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
9841 122 : if (!m_poPointsCache)
9842 52 : m_poPointsCache = new GDALDoublePointsCache();
9843 :
9844 : const bool res =
9845 122 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
9846 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
9847 :
9848 122 : return res ? CE_None : CE_Failure;
9849 : }
9850 :
9851 : /************************************************************************/
9852 : /* GDALRasterInterpolateAtPoint() */
9853 : /************************************************************************/
9854 :
9855 : /**
9856 : * \brief Interpolates the value between pixels using
9857 : * a resampling algorithm
9858 : *
9859 : * @see GDALRasterBand::InterpolateAtPoint()
9860 : * @since GDAL 3.10
9861 : */
9862 :
9863 106 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
9864 : double dfLine,
9865 : GDALRIOResampleAlg eInterpolation,
9866 : double *pdfRealValue, double *pdfImagValue)
9867 : {
9868 106 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
9869 :
9870 106 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9871 106 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
9872 106 : pdfRealValue, pdfImagValue);
9873 : }
9874 :
9875 : /************************************************************************/
9876 : /* InterpolateAtGeolocation() */
9877 : /************************************************************************/
9878 :
9879 : /**
9880 : * \brief Interpolates the value between pixels using a resampling algorithm,
9881 : * taking georeferenced coordinates as input.
9882 : *
9883 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
9884 : * must be in the "natural" SRS of the dataset, that is the one returned by
9885 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
9886 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
9887 : * array (generally WGS 84) if there is a geolocation array.
9888 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
9889 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
9890 : * be a easting, and dfGeolocY a northing.
9891 : *
9892 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
9893 : * expressed in that CRS, and that tuple must be conformant with the
9894 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
9895 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
9896 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
9897 : * before calling this method, and in that case, dfGeolocX must be a longitude
9898 : * or an easting value, and dfGeolocX a latitude or a northing value.
9899 : *
9900 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
9901 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
9902 : * it for details on how that transformation is done.
9903 : *
9904 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
9905 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
9906 : * where interpolation should be done.
9907 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
9908 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
9909 : * where interpolation should be done.
9910 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
9911 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
9912 : * @param pdfRealValue pointer to real part of interpolated value
9913 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
9914 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
9915 : *
9916 : * @return CE_None on success, or an error code on failure.
9917 : * @since GDAL 3.11
9918 : */
9919 :
9920 10 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
9921 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
9922 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
9923 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
9924 : {
9925 : double dfPixel;
9926 : double dfLine;
9927 10 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
9928 : &dfLine,
9929 10 : papszTransformerOptions) != CE_None)
9930 : {
9931 1 : return CE_Failure;
9932 : }
9933 9 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
9934 9 : pdfImagValue);
9935 : }
9936 :
9937 : /************************************************************************/
9938 : /* GDALRasterInterpolateAtGeolocation() */
9939 : /************************************************************************/
9940 :
9941 : /**
9942 : * \brief Interpolates the value between pixels using a resampling algorithm,
9943 : * taking georeferenced coordinates as input.
9944 : *
9945 : * @see GDALRasterBand::InterpolateAtGeolocation()
9946 : * @since GDAL 3.11
9947 : */
9948 :
9949 10 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
9950 : double dfGeolocX, double dfGeolocY,
9951 : OGRSpatialReferenceH hSRS,
9952 : GDALRIOResampleAlg eInterpolation,
9953 : double *pdfRealValue,
9954 : double *pdfImagValue,
9955 : CSLConstList papszTransformerOptions)
9956 : {
9957 10 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
9958 :
9959 10 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9960 10 : return poBand->InterpolateAtGeolocation(
9961 10 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
9962 10 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
9963 : }
|