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_progress.h"
34 : #include "cpl_string.h"
35 : #include "cpl_virtualmem.h"
36 : #include "cpl_vsi.h"
37 : #include "gdal.h"
38 : #include "gdal_rat.h"
39 : #include "gdal_priv_templates.hpp"
40 : #include "gdal_interpolateatpoint.h"
41 : #include "gdal_minmax_element.hpp"
42 :
43 : /************************************************************************/
44 : /* GDALRasterBand() */
45 : /************************************************************************/
46 :
47 : /*! Constructor. Applications should never create GDALRasterBands directly. */
48 :
49 995277 : GDALRasterBand::GDALRasterBand()
50 : : GDALRasterBand(
51 995277 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
52 : {
53 995176 : }
54 :
55 : /** Constructor. Applications should never create GDALRasterBands directly.
56 : * @param bForceCachedIOIn Whether cached IO should be forced.
57 : */
58 1063820 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
59 1063820 : : bForceCachedIO(bForceCachedIOIn)
60 :
61 : {
62 1063640 : }
63 :
64 : /************************************************************************/
65 : /* ~GDALRasterBand() */
66 : /************************************************************************/
67 :
68 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
69 : instead destroy the GDALDataset. */
70 :
71 1063800 : GDALRasterBand::~GDALRasterBand()
72 :
73 : {
74 1063820 : if (poDS && poDS->IsMarkedSuppressOnClose())
75 : {
76 433 : if (poBandBlockCache)
77 384 : poBandBlockCache->DisableDirtyBlockWriting();
78 : }
79 1063820 : GDALRasterBand::FlushCache(true);
80 :
81 1063820 : delete poBandBlockCache;
82 :
83 1063820 : if (static_cast<GIntBig>(nBlockReads) >
84 1063820 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
85 204 : nBand == 1 && poDS != nullptr)
86 : {
87 288 : CPLDebug(
88 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
89 144 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
90 144 : poDS->GetDescription());
91 : }
92 :
93 1063820 : InvalidateMaskBand();
94 1063800 : nBand = -nBand;
95 :
96 1063800 : delete m_poPointsCache;
97 1063810 : }
98 :
99 : /************************************************************************/
100 : /* RasterIO() */
101 : /************************************************************************/
102 :
103 : /**
104 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
105 : * int nXOff, int nYOff, int nXSize, int nYSize,
106 : * void * pData, int nBufXSize, int nBufYSize,
107 : * GDALDataType eBufType,
108 : * GSpacing nPixelSpace,
109 : * GSpacing nLineSpace,
110 : * GDALRasterIOExtraArg* psExtraArg )
111 : * \brief Read/write a region of image data for this band.
112 : *
113 : * This method allows reading a region of a GDALRasterBand into a buffer,
114 : * or writing data from a buffer into a region of a GDALRasterBand. It
115 : * automatically takes care of data type translation if the data type
116 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
117 : * The method also takes care of image decimation / replication if the
118 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
119 : * region being accessed (nXSize x nYSize).
120 : *
121 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
122 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
123 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
124 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
125 : * Or use nLineSpace and a possibly shifted pData value.
126 : *
127 : * The nPixelSpace and nLineSpace parameters allow reading into or
128 : * writing from unusually organized buffers. This is primarily used
129 : * for buffers containing more than one bands raster data in interleaved
130 : * format.
131 : *
132 : * Some formats may efficiently implement decimation into a buffer by
133 : * reading from lower resolution overview images. The logic of the default
134 : * implementation in the base class GDALRasterBand is the following one. It
135 : * computes a target_downscaling_factor from the window of interest and buffer
136 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
137 : * It then walks through overviews and will select the first one whose
138 : * downscaling factor is greater than target_downscaling_factor / 1.2.
139 : *
140 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
141 : * The relationship between target_downscaling_factor and the select overview
142 : * level is the following one:
143 : *
144 : * target_downscaling_factor | selected_overview
145 : * ------------------------- | -----------------
146 : * ]0, 2 / 1.2] | full resolution band
147 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
148 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
149 : * ]8 / 1.2, infinity[ | 8x downsampled band
150 : *
151 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
152 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
153 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
154 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
155 : * this oversampling threshold defaults to 1. Consequently if there are overviews
156 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
157 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
158 : *
159 : * For highest performance full resolution data access, read and write
160 : * on "block boundaries" as returned by GetBlockSize(), or use the
161 : * ReadBlock() and WriteBlock() methods.
162 : *
163 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
164 : * functions.
165 : *
166 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
167 : * write a region of data.
168 : *
169 : * @param nXOff The pixel offset to the top left corner of the region
170 : * of the band to be accessed. This would be zero to start from the left side.
171 : *
172 : * @param nYOff The line offset to the top left corner of the region
173 : * of the band to be accessed. This would be zero to start from the top.
174 : *
175 : * @param nXSize The width of the region of the band to be accessed in pixels.
176 : *
177 : * @param nYSize The height of the region of the band to be accessed in lines.
178 : *
179 : * @param pData The buffer into which the data should be read, or from which
180 : * it should be written. This buffer must contain at least nBufXSize *
181 : * nBufYSize words of type eBufType. It is organized in left to right,
182 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
183 : * and nLineSpace parameters.
184 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
185 : * temporarily modified during the execution of this method (and eventually
186 : * restored back to its original content), so it is not safe to use a buffer
187 : * stored in a read-only section of the calling program.
188 : *
189 : * @param nBufXSize the width of the buffer image into which the desired region
190 : * is to be read, or from which it is to be written.
191 : *
192 : * @param nBufYSize the height of the buffer image into which the desired region
193 : * is to be read, or from which it is to be written.
194 : *
195 : * @param eBufType the type of the pixel values in the pData data buffer. The
196 : * pixel values will automatically be translated to/from the GDALRasterBand
197 : * data type as needed. Most driver implementations will use GDALCopyWords64()
198 : * to perform data type translation.
199 : *
200 : * @param nPixelSpace The byte offset from the start of one pixel value in
201 : * pData to the start of the next pixel value within a scanline. If defaulted
202 : * (0) the size of the datatype eBufType is used.
203 : *
204 : * @param nLineSpace The byte offset from the start of one scanline in
205 : * pData to the start of the next. If defaulted (0) the size of the datatype
206 : * eBufType * nBufXSize is used.
207 : *
208 : * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
209 : * structure with additional arguments to specify resampling and progress
210 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
211 : * configuration option can also be defined to override the default resampling
212 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
213 : *
214 : * @return CE_Failure if the access fails, otherwise CE_None.
215 : */
216 :
217 : /**
218 : * \brief Read/write a region of image data for this band.
219 : *
220 : * This method allows reading a region of a GDALRasterBand into a buffer,
221 : * or writing data from a buffer into a region of a GDALRasterBand. It
222 : * automatically takes care of data type translation if the data type
223 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
224 : * The method also takes care of image decimation / replication if the
225 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
226 : * region being accessed (nXSize x nYSize).
227 : *
228 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
229 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
230 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
231 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
232 : * Or use nLineSpace and a possibly shifted pData value.
233 : *
234 : * The nPixelSpace and nLineSpace parameters allow reading into or
235 : * writing from unusually organized buffers. This is primarily used
236 : * for buffers containing more than one bands raster data in interleaved
237 : * format.
238 : *
239 : * Some formats may efficiently implement decimation into a buffer by
240 : * reading from lower resolution overview images. The logic of the default
241 : * implementation in the base class GDALRasterBand is the following one. It
242 : * computes a target_downscaling_factor from the window of interest and buffer
243 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
244 : * It then walks through overviews and will select the first one whose
245 : * downscaling factor is greater than target_downscaling_factor / 1.2.
246 : *
247 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
248 : * The relationship between target_downscaling_factor and the select overview
249 : * level is the following one:
250 : *
251 : * target_downscaling_factor | selected_overview
252 : * ------------------------- | -----------------
253 : * ]0, 2 / 1.2] | full resolution band
254 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
255 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
256 : * ]8 / 1.2, infinity[ | 8x downsampled band
257 : *
258 : * For highest performance full resolution data access, read and write
259 : * on "block boundaries" as returned by GetBlockSize(), or use the
260 : * ReadBlock() and WriteBlock() methods.
261 : *
262 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
263 : * functions.
264 : *
265 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
266 : * more convenient to use for most common use cases.
267 : *
268 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
269 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
270 : * instance of this dataset) concurrently from several threads.
271 : *
272 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
273 : * write a region of data.
274 : *
275 : * @param nXOff The pixel offset to the top left corner of the region
276 : * of the band to be accessed. This would be zero to start from the left side.
277 : *
278 : * @param nYOff The line offset to the top left corner of the region
279 : * of the band to be accessed. This would be zero to start from the top.
280 : *
281 : * @param nXSize The width of the region of the band to be accessed in pixels.
282 : *
283 : * @param nYSize The height of the region of the band to be accessed in lines.
284 : *
285 : * @param[in,out] pData The buffer into which the data should be read, or from
286 : * which it should be written. This buffer must contain at least nBufXSize *
287 : * nBufYSize words of type eBufType. It is organized in left to right,
288 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
289 : * and nLineSpace parameters.
290 : *
291 : * @param nBufXSize the width of the buffer image into which the desired region
292 : * is to be read, or from which it is to be written.
293 : *
294 : * @param nBufYSize the height of the buffer image into which the desired region
295 : * is to be read, or from which it is to be written.
296 : *
297 : * @param eBufType the type of the pixel values in the pData data buffer. The
298 : * pixel values will automatically be translated to/from the GDALRasterBand
299 : * data type as needed.
300 : *
301 : * @param nPixelSpace The byte offset from the start of one pixel value in
302 : * pData to the start of the next pixel value within a scanline. If defaulted
303 : * (0) the size of the datatype eBufType is used.
304 : *
305 : * @param nLineSpace The byte offset from the start of one scanline in
306 : * pData to the start of the next. If defaulted (0) the size of the datatype
307 : * eBufType * nBufXSize is used.
308 : *
309 : * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
310 : * structure with additional arguments to specify resampling and progress
311 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
312 : * configuration option can also be defined to override the default resampling
313 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
314 : *
315 : * @return CE_Failure if the access fails, otherwise CE_None.
316 : *
317 : * @see GDALRasterBand::ReadRaster()
318 : */
319 :
320 3661470 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
321 : int nXSize, int nYSize, void *pData,
322 : int nBufXSize, int nBufYSize,
323 : GDALDataType eBufType, GSpacing nPixelSpace,
324 : GSpacing nLineSpace,
325 : GDALRasterIOExtraArg *psExtraArg)
326 :
327 : {
328 : GDALRasterIOExtraArg sExtraArg;
329 3661470 : if (psExtraArg == nullptr)
330 : {
331 3578820 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
332 3578820 : psExtraArg = &sExtraArg;
333 : }
334 82650 : else if (CPL_UNLIKELY(psExtraArg->nVersion !=
335 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
336 : {
337 0 : ReportError(CE_Failure, CPLE_AppDefined,
338 : "Unhandled version of GDALRasterIOExtraArg");
339 0 : return CE_Failure;
340 : }
341 :
342 3661470 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
343 : nBufYSize);
344 :
345 3658890 : if (CPL_UNLIKELY(nullptr == pData))
346 : {
347 0 : ReportError(CE_Failure, CPLE_AppDefined,
348 : "The buffer into which the data should be read is null");
349 0 : return CE_Failure;
350 : }
351 :
352 : /* -------------------------------------------------------------------- */
353 : /* Some size values are "noop". Lets just return to avoid */
354 : /* stressing lower level functions. */
355 : /* -------------------------------------------------------------------- */
356 3658890 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
357 : nBufYSize < 1))
358 : {
359 2 : CPLDebug("GDAL",
360 : "RasterIO() skipped for odd window or buffer size.\n"
361 : " Window = (%d,%d)x%dx%d\n"
362 : " Buffer = %dx%d\n",
363 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
364 :
365 2 : return CE_None;
366 : }
367 :
368 3658880 : if (eRWFlag == GF_Write)
369 : {
370 172032 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
371 : {
372 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
373 : "An error occurred while writing a dirty block "
374 : "from GDALRasterBand::RasterIO");
375 0 : CPLErr eErr = eFlushBlockErr;
376 0 : eFlushBlockErr = CE_None;
377 0 : return eErr;
378 : }
379 172032 : if (CPL_UNLIKELY(eAccess != GA_Update))
380 : {
381 3 : ReportError(CE_Failure, CPLE_AppDefined,
382 : "Write operation not permitted on dataset opened "
383 : "in read-only mode");
384 3 : return CE_Failure;
385 : }
386 : }
387 :
388 : /* -------------------------------------------------------------------- */
389 : /* If pixel and line spacing are defaulted assign reasonable */
390 : /* value assuming a packed buffer. */
391 : /* -------------------------------------------------------------------- */
392 3658880 : if (nPixelSpace == 0)
393 : {
394 3575480 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
395 : }
396 :
397 3656220 : if (nLineSpace == 0)
398 : {
399 3567420 : nLineSpace = nPixelSpace * nBufXSize;
400 : }
401 :
402 : /* -------------------------------------------------------------------- */
403 : /* Do some validation of parameters. */
404 : /* -------------------------------------------------------------------- */
405 3656220 : if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
406 : nXOff + nXSize > nRasterXSize || nYOff < 0 ||
407 : nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
408 : {
409 14 : ReportError(CE_Failure, CPLE_IllegalArg,
410 : "Access window out of range in RasterIO(). Requested\n"
411 : "(%d,%d) of size %dx%d on raster of %dx%d.",
412 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
413 14 : return CE_Failure;
414 : }
415 :
416 3656200 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
417 : {
418 0 : ReportError(
419 : CE_Failure, CPLE_IllegalArg,
420 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
421 : eRWFlag);
422 0 : return CE_Failure;
423 : }
424 3656200 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
425 : {
426 2 : ReportError(CE_Failure, CPLE_IllegalArg,
427 : "Illegal GDT_Unknown/GDT_TypeCount argument");
428 2 : return CE_Failure;
429 : }
430 :
431 : /* -------------------------------------------------------------------- */
432 : /* Call the format specific function. */
433 : /* -------------------------------------------------------------------- */
434 :
435 3656200 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
436 :
437 : CPLErr eErr;
438 3658390 : if (bForceCachedIO)
439 22 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
440 : pData, nBufXSize, nBufYSize, eBufType,
441 : nPixelSpace, nLineSpace, psExtraArg);
442 : else
443 : eErr =
444 3661100 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
445 3658360 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
446 :
447 3661120 : if (bCallLeaveReadWrite)
448 178828 : LeaveReadWrite();
449 :
450 3659480 : return eErr;
451 : }
452 :
453 : /************************************************************************/
454 : /* GDALRasterIO() */
455 : /************************************************************************/
456 :
457 : /**
458 : * \brief Read/write a region of image data for this band.
459 : *
460 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
461 : * resolution, progress callback, etc. are needed)
462 : *
463 : * @see GDALRasterBand::RasterIO()
464 : */
465 :
466 3358410 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
467 : int nXOff, int nYOff, int nXSize, int nYSize,
468 : void *pData, int nBufXSize, int nBufYSize,
469 : GDALDataType eBufType, int nPixelSpace,
470 : int nLineSpace)
471 :
472 : {
473 3358410 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
474 :
475 3358410 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
476 :
477 3356480 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
478 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
479 3357520 : nLineSpace, nullptr));
480 : }
481 :
482 : /************************************************************************/
483 : /* GDALRasterIOEx() */
484 : /************************************************************************/
485 :
486 : /**
487 : * \brief Read/write a region of image data for this band.
488 : *
489 : * @see GDALRasterBand::RasterIO()
490 : * @since GDAL 2.0
491 : */
492 :
493 31573 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
494 : int nXOff, int nYOff, int nXSize, int nYSize,
495 : void *pData, int nBufXSize, int nBufYSize,
496 : GDALDataType eBufType, GSpacing nPixelSpace,
497 : GSpacing nLineSpace,
498 : GDALRasterIOExtraArg *psExtraArg)
499 :
500 : {
501 31573 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
502 :
503 31573 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
504 :
505 31573 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
506 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
507 31572 : nLineSpace, psExtraArg));
508 : }
509 :
510 : /************************************************************************/
511 : /* GetGDTFromCppType() */
512 : /************************************************************************/
513 :
514 : namespace
515 : {
516 : template <class T> struct GetGDTFromCppType;
517 :
518 : #define DEFINE_GetGDTFromCppType(T, eDT) \
519 : template <> struct GetGDTFromCppType<T> \
520 : { \
521 : static constexpr GDALDataType GDT = eDT; \
522 : }
523 :
524 : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
525 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
526 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
527 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
528 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
529 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
530 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
531 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
532 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
533 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
534 : // Not allowed by C++ standard
535 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
536 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
537 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
538 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
539 : } // namespace
540 :
541 : /************************************************************************/
542 : /* ReadRaster() */
543 : /************************************************************************/
544 :
545 : // clang-format off
546 : /** Read a region of image data for this band.
547 : *
548 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
549 : * for common use cases, like reading a whole band.
550 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
551 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
552 : * float, double, std::complex<float|double>.
553 : *
554 : * 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>&,
555 : * and can allocate memory automatically.
556 : *
557 : * To read a whole band (assuming it fits into memory), as an array of double:
558 : *
559 : \code{.cpp}
560 : double* myArray = static_cast<double*>(
561 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
562 : // TODO: check here that myArray != nullptr
563 : const size_t nArrayEltCount =
564 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
565 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
566 : {
567 : // do something
568 : }
569 : VSIFree(myArray)
570 : \endcode
571 : *
572 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
573 : *
574 : \code{.cpp}
575 : double* myArray = static_cast<double*>(
576 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
577 : // TODO: check here that myArray != nullptr
578 : const size_t nArrayEltCount = 128 * 128;
579 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
580 : {
581 : // do something
582 : }
583 : VSIFree(myArray)
584 : \endcode
585 : *
586 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
587 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
588 : * instance of this dataset) concurrently from several threads.
589 : *
590 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
591 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
592 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
593 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
594 : * Or use nLineSpace and a possibly shifted pData value.
595 : *
596 : * @param[out] pData The buffer into which the data should be written.
597 : * This buffer must contain at least nBufXSize *
598 : * nBufYSize words of type T. It is organized in left to right,
599 : * top to bottom pixel order, and fully packed.
600 : * The type of the buffer does not need to be the one of GetDataType(). The
601 : * method will perform data type translation (with potential rounding, clamping)
602 : * if needed.
603 : *
604 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
605 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
606 : * return in error if it is not. If set to zero, then pData is trusted to be
607 : * large enough.
608 : *
609 : * @param dfXOff The pixel offset to the top left corner of the region
610 : * of the band to be accessed. This would be zero to start from the left side.
611 : * Defaults to 0.
612 : *
613 : * @param dfYOff The line offset to the top left corner of the region
614 : * of the band to be accessed. This would be zero to start from the top.
615 : * Defaults to 0.
616 : *
617 : * @param dfXSize The width of the region of the band to be accessed in pixels.
618 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
619 : * dfXSize is set to the band width.
620 : *
621 : * @param dfYSize The height of the region of the band to be accessed in lines.
622 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
623 : * dfYSize is set to the band height.
624 : *
625 : * @param nBufXSize the width of the buffer image into which the desired region
626 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
627 : * then nBufXSize is initialized with dfXSize.
628 : *
629 : * @param nBufYSize the height of the buffer image into which the desired region
630 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
631 : * then nBufYSize is initialized with dfYSize.
632 : *
633 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
634 : *
635 : * @param pfnProgress Progress function. May be nullptr.
636 : *
637 : * @param pProgressData User data of pfnProgress. May be nullptr.
638 : *
639 : * @return CE_Failure if the access fails, otherwise CE_None.
640 : *
641 : * @see GDALRasterBand::RasterIO()
642 : * @since GDAL 3.10
643 : */
644 : // clang-format on
645 :
646 : template <class T>
647 19 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
648 : double dfXOff, double dfYOff, double dfXSize,
649 : double dfYSize, size_t nBufXSize,
650 : size_t nBufYSize,
651 : GDALRIOResampleAlg eResampleAlg,
652 : GDALProgressFunc pfnProgress,
653 : void *pProgressData) const
654 : {
655 19 : if (((nBufXSize | nBufYSize) >> 31) != 0)
656 : {
657 2 : return CE_Failure;
658 : }
659 :
660 17 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
661 : {
662 15 : dfXSize = nRasterXSize;
663 15 : dfYSize = nRasterYSize;
664 : }
665 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
666 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
667 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
668 2 : dfYOff + dfYSize > INT_MAX)
669 : {
670 0 : return CE_Failure;
671 : }
672 :
673 : GDALRasterIOExtraArg sExtraArg;
674 17 : sExtraArg.nVersion = 1;
675 17 : sExtraArg.eResampleAlg = eResampleAlg;
676 17 : sExtraArg.pfnProgress = pfnProgress;
677 17 : sExtraArg.pProgressData = pProgressData;
678 17 : sExtraArg.bFloatingPointWindowValidity = true;
679 17 : sExtraArg.dfXOff = dfXOff;
680 17 : sExtraArg.dfYOff = dfYOff;
681 17 : sExtraArg.dfXSize = dfXSize;
682 17 : sExtraArg.dfYSize = dfYSize;
683 17 : const int nXOff = static_cast<int>(dfXOff);
684 17 : const int nYOff = static_cast<int>(dfYOff);
685 17 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
686 17 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
687 17 : if (nBufXSize == 0 && nBufYSize == 0)
688 : {
689 16 : if (static_cast<int>(dfXSize) == dfXSize &&
690 16 : static_cast<int>(dfYSize) == dfYSize)
691 : {
692 16 : nBufXSize = static_cast<int>(dfXSize);
693 16 : nBufYSize = static_cast<int>(dfYSize);
694 : }
695 : else
696 : {
697 0 : CPLError(CE_Failure, CPLE_AppDefined,
698 : "nBufXSize and nBufYSize must be provided if dfXSize or "
699 : "dfYSize is not an integer value");
700 0 : return CE_Failure;
701 : }
702 : }
703 17 : if (nBufXSize == 0 || nBufYSize == 0)
704 : {
705 0 : CPLDebug("GDAL",
706 : "RasterIO() skipped for odd window or buffer size.\n"
707 : " Window = (%d,%d)x%dx%d\n"
708 : " Buffer = %dx%d\n",
709 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
710 : static_cast<int>(nBufYSize));
711 :
712 0 : return CE_None;
713 : }
714 :
715 17 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
716 : {
717 1 : CPLError(CE_Failure, CPLE_AppDefined,
718 : "Provided array is not large enough");
719 1 : return CE_Failure;
720 : }
721 :
722 16 : constexpr GSpacing nPixelSpace = sizeof(T);
723 16 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
724 16 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
725 :
726 16 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
727 :
728 : const bool bCallLeaveReadWrite =
729 16 : CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
730 : CPLErr eErr;
731 : // coverity[identical_branches]
732 16 : if (bForceCachedIO)
733 0 : eErr = pThis->GDALRasterBand::IRasterIO(
734 : GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
735 : static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
736 : nPixelSpace, nLineSpace, &sExtraArg);
737 : else
738 16 : eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
739 : static_cast<int>(nBufXSize),
740 : static_cast<int>(nBufYSize), eBufType,
741 : nPixelSpace, nLineSpace, &sExtraArg);
742 :
743 16 : if (bCallLeaveReadWrite)
744 0 : pThis->LeaveReadWrite();
745 :
746 16 : return eErr;
747 : }
748 :
749 : //! @cond Doxygen_Suppress
750 :
751 : #define INSTANTIATE_READ_RASTER(T) \
752 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
753 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
754 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
755 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
756 : void *pProgressData) const;
757 :
758 : INSTANTIATE_READ_RASTER(uint8_t)
759 : INSTANTIATE_READ_RASTER(int8_t)
760 : INSTANTIATE_READ_RASTER(uint16_t)
761 : INSTANTIATE_READ_RASTER(int16_t)
762 : INSTANTIATE_READ_RASTER(uint32_t)
763 : INSTANTIATE_READ_RASTER(int32_t)
764 : INSTANTIATE_READ_RASTER(uint64_t)
765 : INSTANTIATE_READ_RASTER(int64_t)
766 : INSTANTIATE_READ_RASTER(float)
767 : INSTANTIATE_READ_RASTER(double)
768 : // Not allowed by C++ standard
769 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
770 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
771 : INSTANTIATE_READ_RASTER(std::complex<float>)
772 : INSTANTIATE_READ_RASTER(std::complex<double>)
773 :
774 : //! @endcond
775 :
776 : /************************************************************************/
777 : /* ReadRaster() */
778 : /************************************************************************/
779 :
780 : /** Read a region of image data for this band.
781 : *
782 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
783 : * for common use cases, like reading a whole band.
784 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
785 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
786 : * float, double, std::complex<float|double>.
787 : *
788 : * To read a whole band (assuming it fits into memory), as a vector of double:
789 : *
790 : \code
791 : std::vector<double> myArray;
792 : if (poBand->ReadRaster(myArray) == CE_None)
793 : {
794 : // do something
795 : }
796 : \endcode
797 : *
798 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
799 : *
800 : \code{.cpp}
801 : std::vector<double> myArray;
802 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
803 : {
804 : // do something
805 : }
806 : \endcode
807 : *
808 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
809 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
810 : * instance of this dataset) concurrently from several threads.
811 : *
812 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
813 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
814 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
815 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
816 : * Or use nLineSpace and a possibly shifted pData value.
817 : *
818 : * @param[out] vData The vector into which the data should be written.
819 : * The vector will be resized, if needed, to contain at least nBufXSize *
820 : * nBufYSize values. The values in the vector are organized in left to right,
821 : * top to bottom pixel order, and fully packed.
822 : * The type of the vector does not need to be the one of GetDataType(). The
823 : * method will perform data type translation (with potential rounding, clamping)
824 : * if needed.
825 : *
826 : * @param dfXOff The pixel offset to the top left corner of the region
827 : * of the band to be accessed. This would be zero to start from the left side.
828 : * Defaults to 0.
829 : *
830 : * @param dfYOff The line offset to the top left corner of the region
831 : * of the band to be accessed. This would be zero to start from the top.
832 : * Defaults to 0.
833 : *
834 : * @param dfXSize The width of the region of the band to be accessed in pixels.
835 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
836 : * dfXSize is set to the band width.
837 : *
838 : * @param dfYSize The height of the region of the band to be accessed in lines.
839 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
840 : * dfYSize is set to the band height.
841 : *
842 : * @param nBufXSize the width of the buffer image into which the desired region
843 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
844 : * then nBufXSize is initialized with dfXSize.
845 : *
846 : * @param nBufYSize the height of the buffer image into which the desired region
847 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
848 : * then nBufYSize is initialized with dfYSize.
849 : *
850 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
851 : *
852 : * @param pfnProgress Progress function. May be nullptr.
853 : *
854 : * @param pProgressData User data of pfnProgress. May be nullptr.
855 : *
856 : * @return CE_Failure if the access fails, otherwise CE_None.
857 : *
858 : * @see GDALRasterBand::RasterIO()
859 : * @since GDAL 3.10
860 : */
861 : template <class T>
862 21 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
863 : double dfYOff, double dfXSize, double dfYSize,
864 : size_t nBufXSize, size_t nBufYSize,
865 : GDALRIOResampleAlg eResampleAlg,
866 : GDALProgressFunc pfnProgress,
867 : void *pProgressData) const
868 : {
869 21 : if (((nBufXSize | nBufYSize) >> 31) != 0)
870 : {
871 2 : return CE_Failure;
872 : }
873 :
874 19 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
875 : {
876 12 : dfXSize = nRasterXSize;
877 12 : dfYSize = nRasterYSize;
878 : }
879 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
880 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
881 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
882 7 : dfYOff + dfYSize > INT_MAX)
883 : {
884 0 : return CE_Failure;
885 : }
886 :
887 : GDALRasterIOExtraArg sExtraArg;
888 19 : sExtraArg.nVersion = 1;
889 19 : sExtraArg.eResampleAlg = eResampleAlg;
890 19 : sExtraArg.pfnProgress = pfnProgress;
891 19 : sExtraArg.pProgressData = pProgressData;
892 19 : sExtraArg.bFloatingPointWindowValidity = true;
893 19 : sExtraArg.dfXOff = dfXOff;
894 19 : sExtraArg.dfYOff = dfYOff;
895 19 : sExtraArg.dfXSize = dfXSize;
896 19 : sExtraArg.dfYSize = dfYSize;
897 19 : const int nXOff = static_cast<int>(dfXOff);
898 19 : const int nYOff = static_cast<int>(dfYOff);
899 19 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
900 19 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
901 19 : if (nBufXSize == 0 && nBufYSize == 0)
902 : {
903 15 : if (static_cast<int>(dfXSize) == dfXSize &&
904 14 : static_cast<int>(dfYSize) == dfYSize)
905 : {
906 14 : nBufXSize = static_cast<int>(dfXSize);
907 14 : nBufYSize = static_cast<int>(dfYSize);
908 : }
909 : else
910 : {
911 1 : CPLError(CE_Failure, CPLE_AppDefined,
912 : "nBufXSize and nBufYSize must be provided if "
913 : "dfXSize or dfYSize is not an integer value");
914 1 : return CE_Failure;
915 : }
916 : }
917 18 : if (nBufXSize == 0 || nBufYSize == 0)
918 : {
919 0 : CPLDebug("GDAL",
920 : "RasterIO() skipped for odd window or buffer size.\n"
921 : " Window = (%d,%d)x%dx%d\n"
922 : " Buffer = %dx%d\n",
923 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
924 : static_cast<int>(nBufYSize));
925 :
926 0 : return CE_None;
927 : }
928 :
929 : if constexpr (SIZEOF_VOIDP < 8)
930 : {
931 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
932 : {
933 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
934 : return CE_Failure;
935 : }
936 : }
937 :
938 18 : if (vData.size() < nBufXSize * nBufYSize)
939 : {
940 : try
941 : {
942 16 : vData.resize(nBufXSize * nBufYSize);
943 : }
944 1 : catch (const std::exception &)
945 : {
946 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
947 1 : return CE_Failure;
948 : }
949 : }
950 :
951 17 : constexpr GSpacing nPixelSpace = sizeof(T);
952 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
953 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
954 :
955 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
956 :
957 : const bool bCallLeaveReadWrite =
958 17 : CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
959 :
960 : CPLErr eErr;
961 : // coverity[identical_branches]
962 17 : if (bForceCachedIO)
963 0 : eErr = pThis->GDALRasterBand::IRasterIO(
964 : GF_Read, nXOff, nYOff, nXSize, nYSize, vData.data(),
965 : static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
966 : nPixelSpace, nLineSpace, &sExtraArg);
967 : else
968 17 : eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
969 : vData.data(), static_cast<int>(nBufXSize),
970 : static_cast<int>(nBufYSize), eBufType,
971 : nPixelSpace, nLineSpace, &sExtraArg);
972 :
973 17 : if (bCallLeaveReadWrite)
974 0 : pThis->LeaveReadWrite();
975 :
976 17 : return eErr;
977 : }
978 :
979 : //! @cond Doxygen_Suppress
980 :
981 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
982 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
983 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
984 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
985 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
986 : void *pProgressData) const;
987 :
988 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
989 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
990 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
991 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
992 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
993 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
994 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
995 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
996 : INSTANTIATE_READ_RASTER_VECTOR(float)
997 : INSTANTIATE_READ_RASTER_VECTOR(double)
998 : // Not allowed by C++ standard
999 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
1000 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
1001 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
1002 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
1003 :
1004 : //! @endcond
1005 :
1006 : /************************************************************************/
1007 : /* ReadBlock() */
1008 : /************************************************************************/
1009 :
1010 : /**
1011 : * \brief Read a block of image data efficiently.
1012 : *
1013 : * This method accesses a "natural" block from the raster band without
1014 : * resampling, or data type conversion. For a more generalized, but
1015 : * potentially less efficient access use RasterIO().
1016 : *
1017 : * This method is the same as the C GDALReadBlock() function.
1018 : *
1019 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1020 : * block oriented data without an extra copy into an application buffer.
1021 : *
1022 : * The following code would efficiently compute a histogram of eight bit
1023 : * raster data. Note that the final block may be partial ... data beyond
1024 : * the edge of the underlying raster band in these edge blocks is of an
1025 : * undetermined value.
1026 : *
1027 : \code{.cpp}
1028 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1029 :
1030 : {
1031 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1032 :
1033 : CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1034 :
1035 : int nXBlockSize, nYBlockSize;
1036 :
1037 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1038 : int nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
1039 : int nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
1040 :
1041 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1042 :
1043 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1044 : {
1045 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1046 : {
1047 : int nXValid, nYValid;
1048 :
1049 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1050 :
1051 : // Compute the portion of the block that is valid
1052 : // for partial edge blocks.
1053 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1054 :
1055 : // Collect the histogram counts.
1056 : for( int iY = 0; iY < nYValid; iY++ )
1057 : {
1058 : for( int iX = 0; iX < nXValid; iX++ )
1059 : {
1060 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1061 : }
1062 : }
1063 : }
1064 : }
1065 : }
1066 : \endcode
1067 : *
1068 : * @param nXBlockOff the horizontal block offset, with zero indicating
1069 : * the left most block, 1 the next block and so forth.
1070 : *
1071 : * @param nYBlockOff the vertical block offset, with zero indicating
1072 : * the top most block, 1 the next block and so forth.
1073 : *
1074 : * @param pImage the buffer into which the data will be read. The buffer
1075 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1076 : * of type GetRasterDataType().
1077 : *
1078 : * @return CE_None on success or CE_Failure on an error.
1079 : */
1080 :
1081 644 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1082 :
1083 : {
1084 : /* -------------------------------------------------------------------- */
1085 : /* Validate arguments. */
1086 : /* -------------------------------------------------------------------- */
1087 644 : CPLAssert(pImage != nullptr);
1088 :
1089 644 : if (!InitBlockInfo())
1090 0 : return CE_Failure;
1091 :
1092 644 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1093 : {
1094 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1095 : "Illegal nXBlockOff value (%d) in "
1096 : "GDALRasterBand::ReadBlock()\n",
1097 : nXBlockOff);
1098 :
1099 0 : return (CE_Failure);
1100 : }
1101 :
1102 644 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1103 : {
1104 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1105 : "Illegal nYBlockOff value (%d) in "
1106 : "GDALRasterBand::ReadBlock()\n",
1107 : nYBlockOff);
1108 :
1109 0 : return (CE_Failure);
1110 : }
1111 :
1112 : /* -------------------------------------------------------------------- */
1113 : /* Invoke underlying implementation method. */
1114 : /* -------------------------------------------------------------------- */
1115 :
1116 644 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1117 644 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1118 644 : if (bCallLeaveReadWrite)
1119 4 : LeaveReadWrite();
1120 644 : return eErr;
1121 : }
1122 :
1123 : /************************************************************************/
1124 : /* GDALReadBlock() */
1125 : /************************************************************************/
1126 :
1127 : /**
1128 : * \brief Read a block of image data efficiently.
1129 : *
1130 : * @see GDALRasterBand::ReadBlock()
1131 : */
1132 :
1133 67 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1134 : void *pData)
1135 :
1136 : {
1137 67 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1138 :
1139 67 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1140 67 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1141 : }
1142 :
1143 : /************************************************************************/
1144 : /* IReadBlock() */
1145 : /************************************************************************/
1146 :
1147 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1148 : * ) \brief Read a block of data.
1149 : *
1150 : * Default internal implementation ... to be overridden by
1151 : * subclasses that support reading.
1152 : * @param nBlockXOff Block X Offset
1153 : * @param nBlockYOff Block Y Offset
1154 : * @param pData Pixel buffer into which to place read data.
1155 : * @return CE_None on success or CE_Failure on an error.
1156 : */
1157 :
1158 : /************************************************************************/
1159 : /* IWriteBlock() */
1160 : /************************************************************************/
1161 :
1162 : /**
1163 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1164 : * Write a block of data.
1165 : *
1166 : * Default internal implementation ... to be overridden by
1167 : * subclasses that support writing.
1168 : * @param nBlockXOff Block X Offset
1169 : * @param nBlockYOff Block Y Offset
1170 : * @param pData Pixel buffer to write
1171 : * @return CE_None on success or CE_Failure on an error.
1172 : */
1173 :
1174 : /**/
1175 : /**/
1176 :
1177 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1178 : void * /*pData*/)
1179 :
1180 : {
1181 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1182 0 : ReportError(CE_Failure, CPLE_NotSupported,
1183 : "WriteBlock() not supported for this dataset.");
1184 :
1185 0 : return (CE_Failure);
1186 : }
1187 :
1188 : /************************************************************************/
1189 : /* WriteBlock() */
1190 : /************************************************************************/
1191 :
1192 : /**
1193 : * \brief Write a block of image data efficiently.
1194 : *
1195 : * This method accesses a "natural" block from the raster band without
1196 : * resampling, or data type conversion. For a more generalized, but
1197 : * potentially less efficient access use RasterIO().
1198 : *
1199 : * This method is the same as the C GDALWriteBlock() function.
1200 : *
1201 : * See ReadBlock() for an example of block oriented data access.
1202 : *
1203 : * @param nXBlockOff the horizontal block offset, with zero indicating
1204 : * the left most block, 1 the next block and so forth.
1205 : *
1206 : * @param nYBlockOff the vertical block offset, with zero indicating
1207 : * the left most block, 1 the next block and so forth.
1208 : *
1209 : * @param pImage the buffer from which the data will be written. The buffer
1210 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1211 : * of type GetRasterDataType(). Note that the content of the buffer might be
1212 : * temporarily modified during the execution of this method (and eventually
1213 : * restored back to its original content), so it is not safe to use a buffer
1214 : * stored in a read-only section of the calling program.
1215 : *
1216 : * @return CE_None on success or CE_Failure on an error.
1217 : */
1218 :
1219 4807 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1220 :
1221 : {
1222 : /* -------------------------------------------------------------------- */
1223 : /* Validate arguments. */
1224 : /* -------------------------------------------------------------------- */
1225 4807 : CPLAssert(pImage != nullptr);
1226 :
1227 4807 : if (!InitBlockInfo())
1228 0 : return CE_Failure;
1229 :
1230 4807 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1231 : {
1232 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1233 : "Illegal nXBlockOff value (%d) in "
1234 : "GDALRasterBand::WriteBlock()\n",
1235 : nXBlockOff);
1236 :
1237 0 : return (CE_Failure);
1238 : }
1239 :
1240 4807 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1241 : {
1242 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1243 : "Illegal nYBlockOff value (%d) in "
1244 : "GDALRasterBand::WriteBlock()\n",
1245 : nYBlockOff);
1246 :
1247 0 : return (CE_Failure);
1248 : }
1249 :
1250 4807 : if (eAccess == GA_ReadOnly)
1251 : {
1252 0 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1253 : "Attempt to write to read only dataset in"
1254 : "GDALRasterBand::WriteBlock().\n");
1255 :
1256 0 : return (CE_Failure);
1257 : }
1258 :
1259 4807 : if (eFlushBlockErr != CE_None)
1260 : {
1261 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1262 : "An error occurred while writing a dirty block "
1263 : "from GDALRasterBand::WriteBlock");
1264 0 : CPLErr eErr = eFlushBlockErr;
1265 0 : eFlushBlockErr = CE_None;
1266 0 : return eErr;
1267 : }
1268 :
1269 : /* -------------------------------------------------------------------- */
1270 : /* Invoke underlying implementation method. */
1271 : /* -------------------------------------------------------------------- */
1272 :
1273 4807 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1274 4807 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1275 4807 : if (bCallLeaveReadWrite)
1276 4807 : LeaveReadWrite();
1277 :
1278 4807 : return eErr;
1279 : }
1280 :
1281 : /************************************************************************/
1282 : /* GDALWriteBlock() */
1283 : /************************************************************************/
1284 :
1285 : /**
1286 : * \brief Write a block of image data efficiently.
1287 : *
1288 : * @see GDALRasterBand::WriteBlock()
1289 : */
1290 :
1291 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1292 : void *pData)
1293 :
1294 : {
1295 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1296 :
1297 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1298 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1299 : }
1300 :
1301 : /************************************************************************/
1302 : /* GetActualBlockSize() */
1303 : /************************************************************************/
1304 : /**
1305 : * \brief Fetch the actual block size for a given block offset.
1306 : *
1307 : * Handles partial blocks at the edges of the raster and returns the true
1308 : * number of pixels
1309 : *
1310 : * @param nXBlockOff the horizontal block offset for which to calculate the
1311 : * number of valid pixels, with zero indicating the left most block, 1 the next
1312 : * block and so forth.
1313 : *
1314 : * @param nYBlockOff the vertical block offset, with zero indicating
1315 : * the top most block, 1 the next block and so forth.
1316 : *
1317 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1318 : * the x direction will be stored
1319 : *
1320 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1321 : * the y direction will be stored
1322 : *
1323 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1324 : *
1325 : * @since GDAL 2.2
1326 : */
1327 47863 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1328 : int *pnXValid, int *pnYValid) const
1329 : {
1330 95723 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1331 95711 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1332 95705 : nYBlockOff < 0 || nBlockYSize == 0 ||
1333 47854 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1334 : {
1335 10 : return CE_Failure;
1336 : }
1337 :
1338 47853 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1339 47853 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1340 :
1341 47853 : *pnXValid = nBlockXSize;
1342 47853 : *pnYValid = nBlockYSize;
1343 :
1344 47853 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1345 : {
1346 46245 : *pnXValid = nRasterXSize - nXPixelOff;
1347 : }
1348 :
1349 47853 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1350 : {
1351 3392 : *pnYValid = nRasterYSize - nYPixelOff;
1352 : }
1353 :
1354 47853 : return CE_None;
1355 : }
1356 :
1357 : /************************************************************************/
1358 : /* GDALGetActualBlockSize() */
1359 : /************************************************************************/
1360 :
1361 : /**
1362 : * \brief Retrieve the actual block size for a given block offset.
1363 : *
1364 : * @see GDALRasterBand::GetActualBlockSize()
1365 : */
1366 :
1367 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1368 : int nYBlockOff, int *pnXValid,
1369 : int *pnYValid)
1370 :
1371 : {
1372 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1373 :
1374 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1375 : return (
1376 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1377 : }
1378 :
1379 : /************************************************************************/
1380 : /* GetSuggestedBlockAccessPattern() */
1381 : /************************************************************************/
1382 :
1383 : /**
1384 : * \brief Return the suggested/most efficient access pattern to blocks
1385 : * (for read operations).
1386 : *
1387 : * While all GDAL drivers have to expose a block size, not all can guarantee
1388 : * efficient random access (GSBAP_RANDOM) to any block.
1389 : * Some drivers for example decompress sequentially a compressed stream from
1390 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1391 : * case best performance will be achieved while reading blocks in that order.
1392 : * (accessing blocks in random access in such rasters typically causes the
1393 : * decoding to be re-initialized from the start if accessing blocks in
1394 : * a non-sequential order)
1395 : *
1396 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1397 : * returned by drivers that expose a somewhat artificial block size, because
1398 : * they can extract any part of a raster, but in a rather inefficient way.
1399 : *
1400 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1401 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1402 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1403 : * most efficient strategy is to read as many pixels as possible in the less
1404 : * RasterIO() operations.
1405 : *
1406 : * The return of this method is for example used to determine the swath size
1407 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1408 : *
1409 : * @since GDAL 3.6
1410 : */
1411 :
1412 : GDALSuggestedBlockAccessPattern
1413 2118 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1414 : {
1415 2118 : return GSBAP_UNKNOWN;
1416 : }
1417 :
1418 : /************************************************************************/
1419 : /* GetRasterDataType() */
1420 : /************************************************************************/
1421 :
1422 : /**
1423 : * \brief Fetch the pixel data type for this band.
1424 : *
1425 : * This method is the same as the C function GDALGetRasterDataType().
1426 : *
1427 : * @return the data type of pixels for this band.
1428 : */
1429 :
1430 7551750 : GDALDataType GDALRasterBand::GetRasterDataType() const
1431 :
1432 : {
1433 7551750 : return eDataType;
1434 : }
1435 :
1436 : /************************************************************************/
1437 : /* GDALGetRasterDataType() */
1438 : /************************************************************************/
1439 :
1440 : /**
1441 : * \brief Fetch the pixel data type for this band.
1442 : *
1443 : * @see GDALRasterBand::GetRasterDataType()
1444 : */
1445 :
1446 896181 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1447 :
1448 : {
1449 896181 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1450 :
1451 896181 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1452 896181 : return poBand->GetRasterDataType();
1453 : }
1454 :
1455 : /************************************************************************/
1456 : /* GetBlockSize() */
1457 : /************************************************************************/
1458 :
1459 : /**
1460 : * \brief Fetch the "natural" block size of this band.
1461 : *
1462 : * GDAL contains a concept of the natural block size of rasters so that
1463 : * applications can organized data access efficiently for some file formats.
1464 : * The natural block size is the block size that is most efficient for
1465 : * accessing the format. For many formats this is simple a whole scanline
1466 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1467 : *
1468 : * However, for tiled images this will typically be the tile size.
1469 : *
1470 : * Note that the X and Y block sizes don't have to divide the image size
1471 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1472 : * See ReadBlock() for an example of code dealing with these issues.
1473 : *
1474 : * This method is the same as the C function GDALGetBlockSize().
1475 : *
1476 : * @param pnXSize integer to put the X block size into or NULL.
1477 : *
1478 : * @param pnYSize integer to put the Y block size into or NULL.
1479 : */
1480 :
1481 4962530 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1482 :
1483 : {
1484 4962530 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1485 : {
1486 728 : ReportError(CE_Failure, CPLE_AppDefined,
1487 728 : "Invalid block dimension : %d * %d", nBlockXSize,
1488 728 : nBlockYSize);
1489 0 : if (pnXSize != nullptr)
1490 0 : *pnXSize = 0;
1491 0 : if (pnYSize != nullptr)
1492 0 : *pnYSize = 0;
1493 : }
1494 : else
1495 : {
1496 4961800 : if (pnXSize != nullptr)
1497 4962610 : *pnXSize = nBlockXSize;
1498 4961800 : if (pnYSize != nullptr)
1499 4961340 : *pnYSize = nBlockYSize;
1500 : }
1501 4961800 : }
1502 :
1503 : /************************************************************************/
1504 : /* GDALGetBlockSize() */
1505 : /************************************************************************/
1506 :
1507 : /**
1508 : * \brief Fetch the "natural" block size of this band.
1509 : *
1510 : * @see GDALRasterBand::GetBlockSize()
1511 : */
1512 :
1513 39010 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1514 : int *pnYSize)
1515 :
1516 : {
1517 39010 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1518 :
1519 39010 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1520 39010 : poBand->GetBlockSize(pnXSize, pnYSize);
1521 : }
1522 :
1523 : /************************************************************************/
1524 : /* InitBlockInfo() */
1525 : /************************************************************************/
1526 :
1527 : //! @cond Doxygen_Suppress
1528 3305770 : int GDALRasterBand::InitBlockInfo()
1529 :
1530 : {
1531 3305770 : if (poBandBlockCache != nullptr)
1532 3272750 : return poBandBlockCache->IsInitOK();
1533 :
1534 : /* Do some validation of raster and block dimensions in case the driver */
1535 : /* would have neglected to do it itself */
1536 33019 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1537 : {
1538 0 : ReportError(CE_Failure, CPLE_AppDefined,
1539 : "Invalid block dimension : %d * %d", nBlockXSize,
1540 : nBlockYSize);
1541 0 : return FALSE;
1542 : }
1543 :
1544 33022 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1545 : {
1546 0 : ReportError(CE_Failure, CPLE_AppDefined,
1547 : "Invalid raster dimension : %d * %d", nRasterXSize,
1548 : nRasterYSize);
1549 0 : return FALSE;
1550 : }
1551 :
1552 33022 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1553 33023 : if (nDataTypeSize == 0)
1554 : {
1555 0 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1556 0 : return FALSE;
1557 : }
1558 :
1559 : #if SIZEOF_VOIDP == 4
1560 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1561 : {
1562 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1563 : * multiplication in other cases */
1564 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1565 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1566 : {
1567 : ReportError(CE_Failure, CPLE_NotSupported,
1568 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1569 : nBlockYSize);
1570 : return FALSE;
1571 : }
1572 : }
1573 : #endif
1574 :
1575 33023 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1576 33023 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1577 :
1578 : const char *pszBlockStrategy =
1579 33023 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1580 33023 : bool bUseArray = true;
1581 33023 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1582 : {
1583 32983 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1584 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1585 : {
1586 32964 : GUIntBig nBlockCount =
1587 32964 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1588 32964 : if (poDS != nullptr)
1589 32701 : nBlockCount *= poDS->GetRasterCount();
1590 32964 : bUseArray = (nBlockCount < 1024 * 1024);
1591 : }
1592 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1593 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1594 : {
1595 0 : bUseArray = false;
1596 32983 : }
1597 : }
1598 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1599 40 : bUseArray = false;
1600 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1601 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1602 : pszBlockStrategy);
1603 :
1604 33023 : if (bUseArray)
1605 32953 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1606 : else
1607 : {
1608 70 : if (nBand == 1)
1609 25 : CPLDebug("GDAL", "Use hashset band block cache");
1610 70 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1611 : }
1612 33023 : if (poBandBlockCache == nullptr)
1613 0 : return FALSE;
1614 33023 : return poBandBlockCache->Init();
1615 : }
1616 :
1617 : //! @endcond
1618 :
1619 : /************************************************************************/
1620 : /* FlushCache() */
1621 : /************************************************************************/
1622 :
1623 : /**
1624 : * \brief Flush raster data cache.
1625 : *
1626 : * This call will recover memory used to cache data blocks for this raster
1627 : * band, and ensure that new requests are referred to the underlying driver.
1628 : *
1629 : * This method is the same as the C function GDALFlushRasterCache().
1630 : *
1631 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1632 : * @return CE_None on success.
1633 : */
1634 :
1635 3719800 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1636 :
1637 : {
1638 3764260 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1639 44455 : poBandBlockCache)
1640 2089 : poBandBlockCache->DisableDirtyBlockWriting();
1641 :
1642 3720770 : CPLErr eGlobalErr = eFlushBlockErr;
1643 :
1644 3720770 : if (eFlushBlockErr != CE_None)
1645 : {
1646 0 : ReportError(
1647 : eFlushBlockErr, CPLE_AppDefined,
1648 : "An error occurred while writing a dirty block from FlushCache");
1649 0 : eFlushBlockErr = CE_None;
1650 : }
1651 :
1652 3720770 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1653 3571000 : return eGlobalErr;
1654 :
1655 149770 : return poBandBlockCache->FlushCache();
1656 : }
1657 :
1658 : /************************************************************************/
1659 : /* GDALFlushRasterCache() */
1660 : /************************************************************************/
1661 :
1662 : /**
1663 : * \brief Flush raster data cache.
1664 : *
1665 : * @see GDALRasterBand::FlushCache()
1666 : */
1667 :
1668 129 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1669 :
1670 : {
1671 129 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1672 :
1673 129 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1674 : }
1675 :
1676 : /************************************************************************/
1677 : /* DropCache() */
1678 : /************************************************************************/
1679 :
1680 : /**
1681 : * \brief Drop raster data cache : data in cache will be lost.
1682 : *
1683 : * This call will recover memory used to cache data blocks for this raster
1684 : * band, and ensure that new requests are referred to the underlying driver.
1685 : *
1686 : * This method is the same as the C function GDALDropRasterCache().
1687 : *
1688 : * @return CE_None on success.
1689 : * @since 3.9
1690 : */
1691 :
1692 1 : CPLErr GDALRasterBand::DropCache()
1693 :
1694 : {
1695 1 : CPLErr result = CE_None;
1696 :
1697 1 : if (poBandBlockCache)
1698 1 : poBandBlockCache->DisableDirtyBlockWriting();
1699 :
1700 1 : CPLErr eGlobalErr = eFlushBlockErr;
1701 :
1702 1 : if (eFlushBlockErr != CE_None)
1703 : {
1704 0 : ReportError(
1705 : eFlushBlockErr, CPLE_AppDefined,
1706 : "An error occurred while writing a dirty block from DropCache");
1707 0 : eFlushBlockErr = CE_None;
1708 : }
1709 :
1710 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1711 0 : result = eGlobalErr;
1712 : else
1713 1 : result = poBandBlockCache->FlushCache();
1714 :
1715 1 : if (poBandBlockCache)
1716 1 : poBandBlockCache->EnableDirtyBlockWriting();
1717 :
1718 1 : return result;
1719 : }
1720 :
1721 : /************************************************************************/
1722 : /* GDALDropRasterCache() */
1723 : /************************************************************************/
1724 :
1725 : /**
1726 : * \brief Drop raster data cache.
1727 : *
1728 : * @see GDALRasterBand::DropCache()
1729 : * @since 3.9
1730 : */
1731 :
1732 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1733 :
1734 : {
1735 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1736 :
1737 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1738 : }
1739 :
1740 : /************************************************************************/
1741 : /* UnreferenceBlock() */
1742 : /* */
1743 : /* Unreference the block from our array of blocks */
1744 : /* This method should only be called by */
1745 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1746 : /* the block cache mutex) */
1747 : /************************************************************************/
1748 :
1749 29590 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1750 : {
1751 : #ifdef notdef
1752 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1753 : {
1754 : if (poBandBlockCache == nullptr)
1755 : printf("poBandBlockCache == NULL\n"); /*ok*/
1756 : else
1757 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1758 : printf("caller = %s\n", pszCaller); /*ok*/
1759 : printf("GDALRasterBand: %p\n", this); /*ok*/
1760 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1761 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1762 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1763 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1764 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1765 : poBlock->DumpBlock();
1766 : if (GetDataset() != nullptr)
1767 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1768 : GDALRasterBlock::Verify();
1769 : abort();
1770 : }
1771 : #endif
1772 29590 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1773 29590 : return poBandBlockCache->UnreferenceBlock(poBlock);
1774 : }
1775 :
1776 : /************************************************************************/
1777 : /* AddBlockToFreeList() */
1778 : /* */
1779 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1780 : /* finished with a block about to be free'd, they pass it to that */
1781 : /* method. */
1782 : /************************************************************************/
1783 :
1784 : //! @cond Doxygen_Suppress
1785 29590 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1786 : {
1787 29590 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1788 29590 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1789 : }
1790 :
1791 : //! @endcond
1792 :
1793 : /************************************************************************/
1794 : /* FlushBlock() */
1795 : /************************************************************************/
1796 :
1797 : /** Flush a block out of the block cache.
1798 : * @param nXBlockOff block x offset
1799 : * @param nYBlockOff blocky offset
1800 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1801 : * @return CE_None in case of success, an error code otherwise.
1802 : */
1803 2298 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1804 : int bWriteDirtyBlock)
1805 :
1806 : {
1807 2298 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1808 0 : return (CE_Failure);
1809 :
1810 : /* -------------------------------------------------------------------- */
1811 : /* Validate the request */
1812 : /* -------------------------------------------------------------------- */
1813 2298 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1814 : {
1815 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1816 : "Illegal nBlockXOff value (%d) in "
1817 : "GDALRasterBand::FlushBlock()\n",
1818 : nXBlockOff);
1819 :
1820 0 : return (CE_Failure);
1821 : }
1822 :
1823 2298 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1824 : {
1825 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1826 : "Illegal nBlockYOff value (%d) in "
1827 : "GDALRasterBand::FlushBlock()\n",
1828 : nYBlockOff);
1829 :
1830 0 : return (CE_Failure);
1831 : }
1832 :
1833 2298 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1834 2298 : bWriteDirtyBlock);
1835 : }
1836 :
1837 : /************************************************************************/
1838 : /* TryGetLockedBlockRef() */
1839 : /************************************************************************/
1840 :
1841 : /**
1842 : * \brief Try fetching block ref.
1843 : *
1844 : * This method will returned the requested block (locked) if it is already
1845 : * in the block cache for the layer. If not, nullptr is returned.
1846 : *
1847 : * If a non-NULL value is returned, then a lock for the block will have been
1848 : * acquired on behalf of the caller. It is absolutely imperative that the
1849 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1850 : * severe problems may result.
1851 : *
1852 : * @param nXBlockOff the horizontal block offset, with zero indicating
1853 : * the left most block, 1 the next block and so forth.
1854 : *
1855 : * @param nYBlockOff the vertical block offset, with zero indicating
1856 : * the top most block, 1 the next block and so forth.
1857 : *
1858 : * @return NULL if block not available, or locked block pointer.
1859 : */
1860 :
1861 9919580 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1862 : int nYBlockOff)
1863 :
1864 : {
1865 9919580 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1866 58289 : return nullptr;
1867 :
1868 : /* -------------------------------------------------------------------- */
1869 : /* Validate the request */
1870 : /* -------------------------------------------------------------------- */
1871 9863050 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1872 : {
1873 2404 : ReportError(CE_Failure, CPLE_IllegalArg,
1874 : "Illegal nBlockXOff value (%d) in "
1875 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1876 : nXBlockOff);
1877 :
1878 0 : return (nullptr);
1879 : }
1880 :
1881 9860650 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1882 : {
1883 791 : ReportError(CE_Failure, CPLE_IllegalArg,
1884 : "Illegal nBlockYOff value (%d) in "
1885 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1886 : nYBlockOff);
1887 :
1888 0 : return (nullptr);
1889 : }
1890 :
1891 9859860 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1892 : }
1893 :
1894 : /************************************************************************/
1895 : /* GetLockedBlockRef() */
1896 : /************************************************************************/
1897 :
1898 : /**
1899 : * \brief Fetch a pointer to an internally cached raster block.
1900 : *
1901 : * This method will returned the requested block (locked) if it is already
1902 : * in the block cache for the layer. If not, the block will be read from
1903 : * the driver, and placed in the layer block cached, then returned. If an
1904 : * error occurs reading the block from the driver, a NULL value will be
1905 : * returned.
1906 : *
1907 : * If a non-NULL value is returned, then a lock for the block will have been
1908 : * acquired on behalf of the caller. It is absolutely imperative that the
1909 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1910 : * severe problems may result.
1911 : *
1912 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1913 : * enable caching.
1914 : *
1915 : * @param nXBlockOff the horizontal block offset, with zero indicating
1916 : * the left most block, 1 the next block and so forth.
1917 : *
1918 : * @param nYBlockOff the vertical block offset, with zero indicating
1919 : * the top most block, 1 the next block and so forth.
1920 : *
1921 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1922 : * but not actually read from the source. This is useful when it will just
1923 : * be completely set and written back.
1924 : *
1925 : * @return pointer to the block object, or NULL on failure.
1926 : */
1927 :
1928 9725580 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1929 : int nYBlockOff,
1930 : int bJustInitialize)
1931 :
1932 : {
1933 : /* -------------------------------------------------------------------- */
1934 : /* Try and fetch from cache. */
1935 : /* -------------------------------------------------------------------- */
1936 9725580 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1937 :
1938 : /* -------------------------------------------------------------------- */
1939 : /* If we didn't find it in our memory cache, instantiate a */
1940 : /* block (potentially load from disk) and "adopt" it into the */
1941 : /* cache. */
1942 : /* -------------------------------------------------------------------- */
1943 9729310 : if (poBlock == nullptr)
1944 : {
1945 3129140 : if (!InitBlockInfo())
1946 0 : return (nullptr);
1947 :
1948 : /* --------------------------------------------------------------------
1949 : */
1950 : /* Validate the request */
1951 : /* --------------------------------------------------------------------
1952 : */
1953 3129100 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1954 : {
1955 64 : ReportError(CE_Failure, CPLE_IllegalArg,
1956 : "Illegal nBlockXOff value (%d) in "
1957 : "GDALRasterBand::GetLockedBlockRef()\n",
1958 : nXBlockOff);
1959 :
1960 0 : return (nullptr);
1961 : }
1962 :
1963 3129040 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1964 : {
1965 53 : ReportError(CE_Failure, CPLE_IllegalArg,
1966 : "Illegal nBlockYOff value (%d) in "
1967 : "GDALRasterBand::GetLockedBlockRef()\n",
1968 : nYBlockOff);
1969 :
1970 0 : return (nullptr);
1971 : }
1972 :
1973 3128990 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1974 3129080 : if (poBlock == nullptr)
1975 0 : return nullptr;
1976 :
1977 3129080 : poBlock->AddLock();
1978 :
1979 : /* We need to temporarily drop the read-write lock in the following */
1980 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
1981 : */
1982 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
1983 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
1984 : */
1985 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
1986 : */
1987 : /* called and attempt at taking the lock on T2 (already taken).
1988 : * Similarly */
1989 : /* for T2 with D1, hence a deadlock situation (#6163) */
1990 : /* But this may open the door to other problems... */
1991 3129140 : if (poDS)
1992 3128090 : poDS->TemporarilyDropReadWriteLock();
1993 : /* allocate data space */
1994 3129130 : CPLErr eErr = poBlock->Internalize();
1995 3129270 : if (poDS)
1996 3128200 : poDS->ReacquireReadWriteLock();
1997 3129260 : if (eErr != CE_None)
1998 : {
1999 0 : poBlock->DropLock();
2000 0 : delete poBlock;
2001 0 : return nullptr;
2002 : }
2003 :
2004 3129260 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2005 : {
2006 0 : poBlock->DropLock();
2007 0 : delete poBlock;
2008 0 : return nullptr;
2009 : }
2010 :
2011 3129200 : if (!bJustInitialize)
2012 : {
2013 2782720 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2014 2782690 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2015 2782710 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2016 2782750 : if (bCallLeaveReadWrite)
2017 125797 : LeaveReadWrite();
2018 2782740 : if (eErr != CE_None)
2019 : {
2020 1148 : poBlock->DropLock();
2021 1148 : FlushBlock(nXBlockOff, nYBlockOff);
2022 1148 : ReportError(CE_Failure, CPLE_AppDefined,
2023 : "IReadBlock failed at X offset %d, Y offset %d%s",
2024 : nXBlockOff, nYBlockOff,
2025 1148 : (nErrorCounter != CPLGetErrorCounter())
2026 1146 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2027 : : "");
2028 1148 : return nullptr;
2029 : }
2030 :
2031 2781600 : nBlockReads++;
2032 2781600 : if (static_cast<GIntBig>(nBlockReads) ==
2033 2781600 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2034 204 : 1 &&
2035 204 : nBand == 1 && poDS != nullptr)
2036 : {
2037 144 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2038 144 : poDS->GetDescription());
2039 : }
2040 : }
2041 : }
2042 :
2043 9728230 : return poBlock;
2044 : }
2045 :
2046 : /************************************************************************/
2047 : /* Fill() */
2048 : /************************************************************************/
2049 :
2050 : /**
2051 : * \brief Fill this band with a constant value.
2052 : *
2053 : * GDAL makes no guarantees
2054 : * about what values pixels in newly created files are set to, so this
2055 : * method can be used to clear a band to a specified "default" value.
2056 : * The fill value is passed in as a double but this will be converted
2057 : * to the underlying type before writing to the file. An optional
2058 : * second argument allows the imaginary component of a complex
2059 : * constant value to be specified.
2060 : *
2061 : * This method is the same as the C function GDALFillRaster().
2062 : *
2063 : * @param dfRealValue Real component of fill value
2064 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2065 : *
2066 : * @return CE_Failure if the write fails, otherwise CE_None
2067 : */
2068 169144 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2069 : {
2070 :
2071 : // General approach is to construct a source block of the file's
2072 : // native type containing the appropriate value and then copy this
2073 : // to each block in the image via the RasterBlock cache. Using
2074 : // the cache means we avoid file I/O if it is not necessary, at the
2075 : // expense of some extra memcpy's (since we write to the
2076 : // RasterBlock cache, which is then at some point written to the
2077 : // underlying file, rather than simply directly to the underlying
2078 : // file.)
2079 :
2080 : // Check we can write to the file.
2081 169144 : if (eAccess == GA_ReadOnly)
2082 : {
2083 1 : ReportError(CE_Failure, CPLE_NoWriteAccess,
2084 : "Attempt to write to read only dataset in "
2085 : "GDALRasterBand::Fill().");
2086 1 : return CE_Failure;
2087 : }
2088 :
2089 : // Make sure block parameters are set.
2090 169143 : if (!InitBlockInfo())
2091 0 : return CE_Failure;
2092 :
2093 : // Allocate the source block.
2094 169143 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2095 169143 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2096 169143 : auto blockByteSize = blockSize * elementSize;
2097 : unsigned char *srcBlock =
2098 169143 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2099 169143 : if (srcBlock == nullptr)
2100 : {
2101 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2102 : "GDALRasterBand::Fill(): Out of memory "
2103 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2104 : static_cast<GUIntBig>(blockByteSize));
2105 0 : return CE_Failure;
2106 : }
2107 :
2108 : // Initialize the source block.
2109 169143 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2110 169143 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2111 : elementSize, blockSize);
2112 :
2113 169143 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2114 :
2115 : // Write block to block cache
2116 627247 : for (int j = 0; j < nBlocksPerColumn; ++j)
2117 : {
2118 1210540 : for (int i = 0; i < nBlocksPerRow; ++i)
2119 : {
2120 752437 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2121 752437 : if (destBlock == nullptr)
2122 : {
2123 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2124 : "GDALRasterBand::Fill(): Error "
2125 : "while retrieving cache block.");
2126 0 : VSIFree(srcBlock);
2127 0 : return CE_Failure;
2128 : }
2129 752437 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2130 752437 : destBlock->MarkDirty();
2131 752437 : destBlock->DropLock();
2132 : }
2133 : }
2134 :
2135 169143 : if (bCallLeaveReadWrite)
2136 168668 : LeaveReadWrite();
2137 :
2138 : // Free up the source block
2139 169143 : VSIFree(srcBlock);
2140 :
2141 169143 : return CE_None;
2142 : }
2143 :
2144 : /************************************************************************/
2145 : /* GDALFillRaster() */
2146 : /************************************************************************/
2147 :
2148 : /**
2149 : * \brief Fill this band with a constant value.
2150 : *
2151 : * @see GDALRasterBand::Fill()
2152 : */
2153 169110 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2154 : double dfImaginaryValue)
2155 : {
2156 169110 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2157 :
2158 169110 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2159 169110 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2160 : }
2161 :
2162 : /************************************************************************/
2163 : /* GetAccess() */
2164 : /************************************************************************/
2165 :
2166 : /**
2167 : * \brief Find out if we have update permission for this band.
2168 : *
2169 : * This method is the same as the C function GDALGetRasterAccess().
2170 : *
2171 : * @return Either GA_Update or GA_ReadOnly.
2172 : */
2173 :
2174 2473 : GDALAccess GDALRasterBand::GetAccess()
2175 :
2176 : {
2177 2473 : return eAccess;
2178 : }
2179 :
2180 : /************************************************************************/
2181 : /* GDALGetRasterAccess() */
2182 : /************************************************************************/
2183 :
2184 : /**
2185 : * \brief Find out if we have update permission for this band.
2186 : *
2187 : * @see GDALRasterBand::GetAccess()
2188 : */
2189 :
2190 1835 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2191 :
2192 : {
2193 1835 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2194 :
2195 1835 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2196 1835 : return poBand->GetAccess();
2197 : }
2198 :
2199 : /************************************************************************/
2200 : /* GetCategoryNames() */
2201 : /************************************************************************/
2202 :
2203 : /**
2204 : * \brief Fetch the list of category names for this raster.
2205 : *
2206 : * The return list is a "StringList" in the sense of the CPL functions.
2207 : * That is a NULL terminated array of strings. Raster values without
2208 : * associated names will have an empty string in the returned list. The
2209 : * first entry in the list is for raster values of zero, and so on.
2210 : *
2211 : * The returned stringlist should not be altered or freed by the application.
2212 : * It may change on the next GDAL call, so please copy it if it is needed
2213 : * for any period of time.
2214 : *
2215 : * This method is the same as the C function GDALGetRasterCategoryNames().
2216 : *
2217 : * @return list of names, or NULL if none.
2218 : */
2219 :
2220 231 : char **GDALRasterBand::GetCategoryNames()
2221 :
2222 : {
2223 231 : return nullptr;
2224 : }
2225 :
2226 : /************************************************************************/
2227 : /* GDALGetRasterCategoryNames() */
2228 : /************************************************************************/
2229 :
2230 : /**
2231 : * \brief Fetch the list of category names for this raster.
2232 : *
2233 : * @see GDALRasterBand::GetCategoryNames()
2234 : */
2235 :
2236 161 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2237 :
2238 : {
2239 161 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2240 :
2241 161 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2242 161 : return poBand->GetCategoryNames();
2243 : }
2244 :
2245 : /************************************************************************/
2246 : /* SetCategoryNames() */
2247 : /************************************************************************/
2248 :
2249 : /**
2250 : * \fn GDALRasterBand::SetCategoryNames(char**)
2251 : * \brief Set the category names for this band.
2252 : *
2253 : * See the GetCategoryNames() method for more on the interpretation of
2254 : * category names.
2255 : *
2256 : * This method is the same as the C function GDALSetRasterCategoryNames().
2257 : *
2258 : * @param papszNames the NULL terminated StringList of category names. May
2259 : * be NULL to just clear the existing list.
2260 : *
2261 : * @return CE_None on success of CE_Failure on failure. If unsupported
2262 : * by the driver CE_Failure is returned, but no error message is reported.
2263 : */
2264 :
2265 : /**/
2266 : /**/
2267 :
2268 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2269 : {
2270 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2271 0 : ReportError(CE_Failure, CPLE_NotSupported,
2272 : "SetCategoryNames() not supported for this dataset.");
2273 :
2274 0 : return CE_Failure;
2275 : }
2276 :
2277 : /************************************************************************/
2278 : /* GDALSetCategoryNames() */
2279 : /************************************************************************/
2280 :
2281 : /**
2282 : * \brief Set the category names for this band.
2283 : *
2284 : * @see GDALRasterBand::SetCategoryNames()
2285 : */
2286 :
2287 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2288 : CSLConstList papszNames)
2289 :
2290 : {
2291 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2292 :
2293 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2294 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2295 : }
2296 :
2297 : /************************************************************************/
2298 : /* GetNoDataValue() */
2299 : /************************************************************************/
2300 :
2301 : /**
2302 : * \brief Fetch the no data value for this band.
2303 : *
2304 : * If there is no out of data value, an out of range value will generally
2305 : * be returned. The no data value for a band is generally a special marker
2306 : * value used to mark pixels that are not valid data. Such pixels should
2307 : * generally not be displayed, nor contribute to analysis operations.
2308 : *
2309 : * The no data value returned is 'raw', meaning that it has no offset and
2310 : * scale applied.
2311 : *
2312 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2313 : * lossy if the nodata value cannot exactly been represented by a double.
2314 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2315 : *
2316 : * This method is the same as the C function GDALGetRasterNoDataValue().
2317 : *
2318 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2319 : * is actually associated with this layer. May be NULL (default).
2320 : *
2321 : * @return the nodata value for this band.
2322 : */
2323 :
2324 31328 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2325 :
2326 : {
2327 31328 : if (pbSuccess != nullptr)
2328 31328 : *pbSuccess = FALSE;
2329 :
2330 31328 : return -1e10;
2331 : }
2332 :
2333 : /************************************************************************/
2334 : /* GDALGetRasterNoDataValue() */
2335 : /************************************************************************/
2336 :
2337 : /**
2338 : * \brief Fetch the no data value for this band.
2339 : *
2340 : * @see GDALRasterBand::GetNoDataValue()
2341 : */
2342 :
2343 413650 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2344 : int *pbSuccess)
2345 :
2346 : {
2347 413650 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2348 :
2349 413650 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2350 413650 : return poBand->GetNoDataValue(pbSuccess);
2351 : }
2352 :
2353 : /************************************************************************/
2354 : /* GetNoDataValueAsInt64() */
2355 : /************************************************************************/
2356 :
2357 : /**
2358 : * \brief Fetch the no data value for this band.
2359 : *
2360 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2361 : *
2362 : * If there is no out of data value, an out of range value will generally
2363 : * be returned. The no data value for a band is generally a special marker
2364 : * value used to mark pixels that are not valid data. Such pixels should
2365 : * generally not be displayed, nor contribute to analysis operations.
2366 : *
2367 : * The no data value returned is 'raw', meaning that it has no offset and
2368 : * scale applied.
2369 : *
2370 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2371 : *
2372 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2373 : * is actually associated with this layer. May be NULL (default).
2374 : *
2375 : * @return the nodata value for this band.
2376 : *
2377 : * @since GDAL 3.5
2378 : */
2379 :
2380 4 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2381 :
2382 : {
2383 4 : if (pbSuccess != nullptr)
2384 4 : *pbSuccess = FALSE;
2385 :
2386 4 : return std::numeric_limits<int64_t>::min();
2387 : }
2388 :
2389 : /************************************************************************/
2390 : /* GDALGetRasterNoDataValueAsInt64() */
2391 : /************************************************************************/
2392 :
2393 : /**
2394 : * \brief Fetch the no data value for this band.
2395 : *
2396 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2397 : *
2398 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2399 : *
2400 : * @since GDAL 3.5
2401 : */
2402 :
2403 23 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2404 : int *pbSuccess)
2405 :
2406 : {
2407 23 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2408 : std::numeric_limits<int64_t>::min());
2409 :
2410 23 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2411 23 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2412 : }
2413 :
2414 : /************************************************************************/
2415 : /* GetNoDataValueAsUInt64() */
2416 : /************************************************************************/
2417 :
2418 : /**
2419 : * \brief Fetch the no data value for this band.
2420 : *
2421 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2422 : *
2423 : * If there is no out of data value, an out of range value will generally
2424 : * be returned. The no data value for a band is generally a special marker
2425 : * value used to mark pixels that are not valid data. Such pixels should
2426 : * generally not be displayed, nor contribute to analysis operations.
2427 : *
2428 : * The no data value returned is 'raw', meaning that it has no offset and
2429 : * scale applied.
2430 : *
2431 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2432 : *
2433 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2434 : * is actually associated with this layer. May be NULL (default).
2435 : *
2436 : * @return the nodata value for this band.
2437 : *
2438 : * @since GDAL 3.5
2439 : */
2440 :
2441 3 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2442 :
2443 : {
2444 3 : if (pbSuccess != nullptr)
2445 3 : *pbSuccess = FALSE;
2446 :
2447 3 : return std::numeric_limits<uint64_t>::max();
2448 : }
2449 :
2450 : /************************************************************************/
2451 : /* GDALGetRasterNoDataValueAsUInt64() */
2452 : /************************************************************************/
2453 :
2454 : /**
2455 : * \brief Fetch the no data value for this band.
2456 : *
2457 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2458 : *
2459 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2460 : *
2461 : * @since GDAL 3.5
2462 : */
2463 :
2464 18 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2465 : int *pbSuccess)
2466 :
2467 : {
2468 18 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2469 : std::numeric_limits<uint64_t>::max());
2470 :
2471 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2472 18 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2473 : }
2474 :
2475 : /************************************************************************/
2476 : /* SetNoDataValue() */
2477 : /************************************************************************/
2478 :
2479 : /**
2480 : * \fn GDALRasterBand::SetNoDataValue(double)
2481 : * \brief Set the no data value for this band.
2482 : *
2483 : * Depending on drivers, changing the no data value may or may not have an
2484 : * effect on the pixel values of a raster that has just been created. It is
2485 : * thus advised to explicitly called Fill() if the intent is to initialize
2486 : * the raster to the nodata value.
2487 : * In any case, changing an existing no data value, when one already exists and
2488 : * the dataset exists or has been initialized, has no effect on the pixel whose
2489 : * value matched the previous nodata value.
2490 : *
2491 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2492 : * be represented by a double, use SetNoDataValueAsInt64() or
2493 : * SetNoDataValueAsUInt64() instead.
2494 : *
2495 : * To clear the nodata value, use DeleteNoDataValue().
2496 : *
2497 : * This method is the same as the C function GDALSetRasterNoDataValue().
2498 : *
2499 : * @param dfNoData the value to set.
2500 : *
2501 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2502 : * by the driver, CE_Failure is returned by no error message will have
2503 : * been emitted.
2504 : */
2505 :
2506 : /**/
2507 : /**/
2508 :
2509 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2510 :
2511 : {
2512 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2513 0 : ReportError(CE_Failure, CPLE_NotSupported,
2514 : "SetNoDataValue() not supported for this dataset.");
2515 :
2516 0 : return CE_Failure;
2517 : }
2518 :
2519 : /************************************************************************/
2520 : /* GDALSetRasterNoDataValue() */
2521 : /************************************************************************/
2522 :
2523 : /**
2524 : * \brief Set the no data value for this band.
2525 : *
2526 : * Depending on drivers, changing the no data value may or may not have an
2527 : * effect on the pixel values of a raster that has just been created. It is
2528 : * thus advised to explicitly called Fill() if the intent is to initialize
2529 : * the raster to the nodata value.
2530 : * In any case, changing an existing no data value, when one already exists and
2531 : * the dataset exists or has been initialized, has no effect on the pixel whose
2532 : * value matched the previous nodata value.
2533 : *
2534 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2535 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2536 : * GDALSetRasterNoDataValueAsUInt64() instead.
2537 : *
2538 : * @see GDALRasterBand::SetNoDataValue()
2539 : */
2540 :
2541 649 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2542 : double dfValue)
2543 :
2544 : {
2545 649 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2546 :
2547 649 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2548 649 : return poBand->SetNoDataValue(dfValue);
2549 : }
2550 :
2551 : /************************************************************************/
2552 : /* SetNoDataValueAsInt64() */
2553 : /************************************************************************/
2554 :
2555 : /**
2556 : * \brief Set the no data value for this band.
2557 : *
2558 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2559 : *
2560 : * Depending on drivers, changing the no data value may or may not have an
2561 : * effect on the pixel values of a raster that has just been created. It is
2562 : * thus advised to explicitly called Fill() if the intent is to initialize
2563 : * the raster to the nodata value.
2564 : * In ay case, changing an existing no data value, when one already exists and
2565 : * the dataset exists or has been initialized, has no effect on the pixel whose
2566 : * value matched the previous nodata value.
2567 : *
2568 : * To clear the nodata value, use DeleteNoDataValue().
2569 : *
2570 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2571 : *
2572 : * @param nNoDataValue the value to set.
2573 : *
2574 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2575 : * by the driver, CE_Failure is returned by no error message will have
2576 : * been emitted.
2577 : *
2578 : * @since GDAL 3.5
2579 : */
2580 :
2581 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2582 :
2583 : {
2584 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2585 0 : ReportError(CE_Failure, CPLE_NotSupported,
2586 : "SetNoDataValueAsInt64() not supported for this dataset.");
2587 :
2588 0 : return CE_Failure;
2589 : }
2590 :
2591 : /************************************************************************/
2592 : /* GDALSetRasterNoDataValueAsInt64() */
2593 : /************************************************************************/
2594 :
2595 : /**
2596 : * \brief Set the no data value for this band.
2597 : *
2598 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2599 : *
2600 : * Depending on drivers, changing the no data value may or may not have an
2601 : * effect on the pixel values of a raster that has just been created. It is
2602 : * thus advised to explicitly called Fill() if the intent is to initialize
2603 : * the raster to the nodata value.
2604 : * In ay case, changing an existing no data value, when one already exists and
2605 : * the dataset exists or has been initialized, has no effect on the pixel whose
2606 : * value matched the previous nodata value.
2607 : *
2608 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2609 : *
2610 : * @since GDAL 3.5
2611 : */
2612 :
2613 18 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2614 : int64_t nValue)
2615 :
2616 : {
2617 18 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2618 :
2619 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2620 18 : return poBand->SetNoDataValueAsInt64(nValue);
2621 : }
2622 :
2623 : /************************************************************************/
2624 : /* SetNoDataValueAsUInt64() */
2625 : /************************************************************************/
2626 :
2627 : /**
2628 : * \brief Set the no data value for this band.
2629 : *
2630 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2631 : *
2632 : * Depending on drivers, changing the no data value may or may not have an
2633 : * effect on the pixel values of a raster that has just been created. It is
2634 : * thus advised to explicitly called Fill() if the intent is to initialize
2635 : * the raster to the nodata value.
2636 : * In ay case, changing an existing no data value, when one already exists and
2637 : * the dataset exists or has been initialized, has no effect on the pixel whose
2638 : * value matched the previous nodata value.
2639 : *
2640 : * To clear the nodata value, use DeleteNoDataValue().
2641 : *
2642 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2643 : *
2644 : * @param nNoDataValue the value to set.
2645 : *
2646 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2647 : * by the driver, CE_Failure is returned by no error message will have
2648 : * been emitted.
2649 : *
2650 : * @since GDAL 3.5
2651 : */
2652 :
2653 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2654 :
2655 : {
2656 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2657 0 : ReportError(CE_Failure, CPLE_NotSupported,
2658 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2659 :
2660 0 : return CE_Failure;
2661 : }
2662 :
2663 : /************************************************************************/
2664 : /* GDALSetRasterNoDataValueAsUInt64() */
2665 : /************************************************************************/
2666 :
2667 : /**
2668 : * \brief Set the no data value for this band.
2669 : *
2670 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2671 : *
2672 : * Depending on drivers, changing the no data value may or may not have an
2673 : * effect on the pixel values of a raster that has just been created. It is
2674 : * thus advised to explicitly called Fill() if the intent is to initialize
2675 : * the raster to the nodata value.
2676 : * In ay case, changing an existing no data value, when one already exists and
2677 : * the dataset exists or has been initialized, has no effect on the pixel whose
2678 : * value matched the previous nodata value.
2679 : *
2680 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2681 : *
2682 : * @since GDAL 3.5
2683 : */
2684 :
2685 16 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2686 : uint64_t nValue)
2687 :
2688 : {
2689 16 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2690 :
2691 16 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2692 16 : return poBand->SetNoDataValueAsUInt64(nValue);
2693 : }
2694 :
2695 : /************************************************************************/
2696 : /* DeleteNoDataValue() */
2697 : /************************************************************************/
2698 :
2699 : /**
2700 : * \brief Remove the no data value for this band.
2701 : *
2702 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2703 : *
2704 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2705 : * by the driver, CE_Failure is returned by no error message will have
2706 : * been emitted.
2707 : *
2708 : * @since GDAL 2.1
2709 : */
2710 :
2711 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2712 :
2713 : {
2714 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2715 0 : ReportError(CE_Failure, CPLE_NotSupported,
2716 : "DeleteNoDataValue() not supported for this dataset.");
2717 :
2718 0 : return CE_Failure;
2719 : }
2720 :
2721 : /************************************************************************/
2722 : /* GDALDeleteRasterNoDataValue() */
2723 : /************************************************************************/
2724 :
2725 : /**
2726 : * \brief Remove the no data value for this band.
2727 : *
2728 : * @see GDALRasterBand::DeleteNoDataValue()
2729 : *
2730 : * @since GDAL 2.1
2731 : */
2732 :
2733 41 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2734 :
2735 : {
2736 41 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2737 :
2738 41 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2739 41 : return poBand->DeleteNoDataValue();
2740 : }
2741 :
2742 : /************************************************************************/
2743 : /* GetMaximum() */
2744 : /************************************************************************/
2745 :
2746 : /**
2747 : * \brief Fetch the maximum value for this band.
2748 : *
2749 : * For file formats that don't know this intrinsically, the maximum supported
2750 : * value for the data type will generally be returned.
2751 : *
2752 : * This method is the same as the C function GDALGetRasterMaximum().
2753 : *
2754 : * @param pbSuccess pointer to a boolean to use to indicate if the
2755 : * returned value is a tight maximum or not. May be NULL (default).
2756 : *
2757 : * @return the maximum raster value (excluding no data pixels)
2758 : */
2759 :
2760 460 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2761 :
2762 : {
2763 460 : const char *pszValue = nullptr;
2764 :
2765 460 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2766 : {
2767 38 : if (pbSuccess != nullptr)
2768 33 : *pbSuccess = TRUE;
2769 :
2770 38 : return CPLAtofM(pszValue);
2771 : }
2772 :
2773 422 : if (pbSuccess != nullptr)
2774 390 : *pbSuccess = FALSE;
2775 :
2776 422 : switch (eDataType)
2777 : {
2778 299 : case GDT_Byte:
2779 : {
2780 299 : EnablePixelTypeSignedByteWarning(false);
2781 : const char *pszPixelType =
2782 299 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2783 299 : EnablePixelTypeSignedByteWarning(true);
2784 299 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2785 0 : return 127;
2786 :
2787 299 : return 255;
2788 : }
2789 :
2790 0 : case GDT_Int8:
2791 0 : return 127;
2792 :
2793 19 : case GDT_UInt16:
2794 19 : return 65535;
2795 :
2796 24 : case GDT_Int16:
2797 : case GDT_CInt16:
2798 24 : return 32767;
2799 :
2800 15 : case GDT_Int32:
2801 : case GDT_CInt32:
2802 15 : return 2147483647.0;
2803 :
2804 13 : case GDT_UInt32:
2805 13 : return 4294967295.0;
2806 :
2807 0 : case GDT_Int64:
2808 0 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2809 :
2810 0 : case GDT_UInt64:
2811 0 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2812 :
2813 32 : case GDT_Float32:
2814 : case GDT_CFloat32:
2815 32 : return 4294967295.0; // Not actually accurate.
2816 :
2817 20 : case GDT_Float64:
2818 : case GDT_CFloat64:
2819 20 : return 4294967295.0; // Not actually accurate.
2820 :
2821 0 : case GDT_Unknown:
2822 : case GDT_TypeCount:
2823 0 : break;
2824 : }
2825 0 : return 4294967295.0; // Not actually accurate.
2826 : }
2827 :
2828 : /************************************************************************/
2829 : /* GDALGetRasterMaximum() */
2830 : /************************************************************************/
2831 :
2832 : /**
2833 : * \brief Fetch the maximum value for this band.
2834 : *
2835 : * @see GDALRasterBand::GetMaximum()
2836 : */
2837 :
2838 216 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2839 :
2840 : {
2841 216 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2842 :
2843 216 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2844 216 : return poBand->GetMaximum(pbSuccess);
2845 : }
2846 :
2847 : /************************************************************************/
2848 : /* GetMinimum() */
2849 : /************************************************************************/
2850 :
2851 : /**
2852 : * \brief Fetch the minimum value for this band.
2853 : *
2854 : * For file formats that don't know this intrinsically, the minimum supported
2855 : * value for the data type will generally be returned.
2856 : *
2857 : * This method is the same as the C function GDALGetRasterMinimum().
2858 : *
2859 : * @param pbSuccess pointer to a boolean to use to indicate if the
2860 : * returned value is a tight minimum or not. May be NULL (default).
2861 : *
2862 : * @return the minimum raster value (excluding no data pixels)
2863 : */
2864 :
2865 468 : double GDALRasterBand::GetMinimum(int *pbSuccess)
2866 :
2867 : {
2868 468 : const char *pszValue = nullptr;
2869 :
2870 468 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
2871 : {
2872 43 : if (pbSuccess != nullptr)
2873 38 : *pbSuccess = TRUE;
2874 :
2875 43 : return CPLAtofM(pszValue);
2876 : }
2877 :
2878 425 : if (pbSuccess != nullptr)
2879 393 : *pbSuccess = FALSE;
2880 :
2881 425 : switch (eDataType)
2882 : {
2883 302 : case GDT_Byte:
2884 : {
2885 302 : EnablePixelTypeSignedByteWarning(false);
2886 : const char *pszPixelType =
2887 302 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2888 302 : EnablePixelTypeSignedByteWarning(true);
2889 302 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2890 0 : return -128;
2891 :
2892 302 : return 0;
2893 : }
2894 :
2895 0 : case GDT_Int8:
2896 0 : return -128;
2897 : break;
2898 :
2899 19 : case GDT_UInt16:
2900 19 : return 0;
2901 :
2902 24 : case GDT_Int16:
2903 : case GDT_CInt16:
2904 24 : return -32768;
2905 :
2906 15 : case GDT_Int32:
2907 : case GDT_CInt32:
2908 15 : return -2147483648.0;
2909 :
2910 13 : case GDT_UInt32:
2911 13 : return 0;
2912 :
2913 0 : case GDT_Int64:
2914 0 : return static_cast<double>(std::numeric_limits<GInt64>::min());
2915 :
2916 0 : case GDT_UInt64:
2917 0 : return 0;
2918 :
2919 32 : case GDT_Float32:
2920 : case GDT_CFloat32:
2921 32 : return -4294967295.0; // Not actually accurate.
2922 :
2923 20 : case GDT_Float64:
2924 : case GDT_CFloat64:
2925 20 : return -4294967295.0; // Not actually accurate.
2926 :
2927 0 : case GDT_Unknown:
2928 : case GDT_TypeCount:
2929 0 : break;
2930 : }
2931 0 : return -4294967295.0; // Not actually accurate.
2932 : }
2933 :
2934 : /************************************************************************/
2935 : /* GDALGetRasterMinimum() */
2936 : /************************************************************************/
2937 :
2938 : /**
2939 : * \brief Fetch the minimum value for this band.
2940 : *
2941 : * @see GDALRasterBand::GetMinimum()
2942 : */
2943 :
2944 226 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
2945 :
2946 : {
2947 226 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
2948 :
2949 226 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2950 226 : return poBand->GetMinimum(pbSuccess);
2951 : }
2952 :
2953 : /************************************************************************/
2954 : /* GetColorInterpretation() */
2955 : /************************************************************************/
2956 :
2957 : /**
2958 : * \brief How should this band be interpreted as color?
2959 : *
2960 : * GCI_Undefined is returned when the format doesn't know anything
2961 : * about the color interpretation.
2962 : *
2963 : * This method is the same as the C function
2964 : * GDALGetRasterColorInterpretation().
2965 : *
2966 : * @return color interpretation value for band.
2967 : */
2968 :
2969 114 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
2970 :
2971 : {
2972 114 : return GCI_Undefined;
2973 : }
2974 :
2975 : /************************************************************************/
2976 : /* GDALGetRasterColorInterpretation() */
2977 : /************************************************************************/
2978 :
2979 : /**
2980 : * \brief How should this band be interpreted as color?
2981 : *
2982 : * @see GDALRasterBand::GetColorInterpretation()
2983 : */
2984 :
2985 : GDALColorInterp CPL_STDCALL
2986 4894 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
2987 :
2988 : {
2989 4894 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
2990 :
2991 4894 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2992 4894 : return poBand->GetColorInterpretation();
2993 : }
2994 :
2995 : /************************************************************************/
2996 : /* SetColorInterpretation() */
2997 : /************************************************************************/
2998 :
2999 : /**
3000 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3001 : * \brief Set color interpretation of a band.
3002 : *
3003 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3004 : *
3005 : * @param eColorInterp the new color interpretation to apply to this band.
3006 : *
3007 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3008 : */
3009 :
3010 : /**/
3011 : /**/
3012 :
3013 3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3014 :
3015 : {
3016 3 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3017 3 : ReportError(CE_Failure, CPLE_NotSupported,
3018 : "SetColorInterpretation() not supported for this dataset.");
3019 3 : return CE_Failure;
3020 : }
3021 :
3022 : /************************************************************************/
3023 : /* GDALSetRasterColorInterpretation() */
3024 : /************************************************************************/
3025 :
3026 : /**
3027 : * \brief Set color interpretation of a band.
3028 : *
3029 : * @see GDALRasterBand::SetColorInterpretation()
3030 : */
3031 :
3032 1755 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3033 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3034 :
3035 : {
3036 1755 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3037 :
3038 1755 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3039 1755 : return poBand->SetColorInterpretation(eColorInterp);
3040 : }
3041 :
3042 : /************************************************************************/
3043 : /* GetColorTable() */
3044 : /************************************************************************/
3045 :
3046 : /**
3047 : * \brief Fetch the color table associated with band.
3048 : *
3049 : * If there is no associated color table, the return result is NULL. The
3050 : * returned color table remains owned by the GDALRasterBand, and can't
3051 : * be depended on for long, nor should it ever be modified by the caller.
3052 : *
3053 : * This method is the same as the C function GDALGetRasterColorTable().
3054 : *
3055 : * @return internal color table, or NULL.
3056 : */
3057 :
3058 212 : GDALColorTable *GDALRasterBand::GetColorTable()
3059 :
3060 : {
3061 212 : return nullptr;
3062 : }
3063 :
3064 : /************************************************************************/
3065 : /* GDALGetRasterColorTable() */
3066 : /************************************************************************/
3067 :
3068 : /**
3069 : * \brief Fetch the color table associated with band.
3070 : *
3071 : * @see GDALRasterBand::GetColorTable()
3072 : */
3073 :
3074 1791 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3075 :
3076 : {
3077 1791 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3078 :
3079 1791 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3080 1791 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3081 : }
3082 :
3083 : /************************************************************************/
3084 : /* SetColorTable() */
3085 : /************************************************************************/
3086 :
3087 : /**
3088 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3089 : * \brief Set the raster color table.
3090 : *
3091 : * The driver will make a copy of all desired data in the colortable. It
3092 : * remains owned by the caller after the call.
3093 : *
3094 : * This method is the same as the C function GDALSetRasterColorTable().
3095 : *
3096 : * @param poCT the color table to apply. This may be NULL to clear the color
3097 : * table (where supported).
3098 : *
3099 : * @return CE_None on success, or CE_Failure on failure. If the action is
3100 : * unsupported by the driver, a value of CE_Failure is returned, but no
3101 : * error is issued.
3102 : */
3103 :
3104 : /**/
3105 : /**/
3106 :
3107 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3108 :
3109 : {
3110 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3111 0 : ReportError(CE_Failure, CPLE_NotSupported,
3112 : "SetColorTable() not supported for this dataset.");
3113 0 : return CE_Failure;
3114 : }
3115 :
3116 : /************************************************************************/
3117 : /* GDALSetRasterColorTable() */
3118 : /************************************************************************/
3119 :
3120 : /**
3121 : * \brief Set the raster color table.
3122 : *
3123 : * @see GDALRasterBand::SetColorTable()
3124 : */
3125 :
3126 76 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3127 : GDALColorTableH hCT)
3128 :
3129 : {
3130 76 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3131 :
3132 76 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3133 76 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3134 : }
3135 :
3136 : /************************************************************************/
3137 : /* HasArbitraryOverviews() */
3138 : /************************************************************************/
3139 :
3140 : /**
3141 : * \brief Check for arbitrary overviews.
3142 : *
3143 : * This returns TRUE if the underlying datastore can compute arbitrary
3144 : * overviews efficiently, such as is the case with OGDI over a network.
3145 : * Datastores with arbitrary overviews don't generally have any fixed
3146 : * overviews, but the RasterIO() method can be used in downsampling mode
3147 : * to get overview data efficiently.
3148 : *
3149 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3150 : *
3151 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3152 : * FALSE.
3153 : */
3154 :
3155 216 : int GDALRasterBand::HasArbitraryOverviews()
3156 :
3157 : {
3158 216 : return FALSE;
3159 : }
3160 :
3161 : /************************************************************************/
3162 : /* GDALHasArbitraryOverviews() */
3163 : /************************************************************************/
3164 :
3165 : /**
3166 : * \brief Check for arbitrary overviews.
3167 : *
3168 : * @see GDALRasterBand::HasArbitraryOverviews()
3169 : */
3170 :
3171 151 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3172 :
3173 : {
3174 151 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3175 :
3176 151 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3177 151 : return poBand->HasArbitraryOverviews();
3178 : }
3179 :
3180 : /************************************************************************/
3181 : /* GetOverviewCount() */
3182 : /************************************************************************/
3183 :
3184 : /**
3185 : * \brief Return the number of overview layers available.
3186 : *
3187 : * This method is the same as the C function GDALGetOverviewCount().
3188 : *
3189 : * @return overview count, zero if none.
3190 : */
3191 :
3192 660127 : int GDALRasterBand::GetOverviewCount()
3193 :
3194 : {
3195 1315410 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3196 655284 : poDS->AreOverviewsEnabled())
3197 655284 : return poDS->oOvManager.GetOverviewCount(nBand);
3198 :
3199 4843 : return 0;
3200 : }
3201 :
3202 : /************************************************************************/
3203 : /* GDALGetOverviewCount() */
3204 : /************************************************************************/
3205 :
3206 : /**
3207 : * \brief Return the number of overview layers available.
3208 : *
3209 : * @see GDALRasterBand::GetOverviewCount()
3210 : */
3211 :
3212 3140 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3213 :
3214 : {
3215 3140 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3216 :
3217 3140 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3218 3140 : return poBand->GetOverviewCount();
3219 : }
3220 :
3221 : /************************************************************************/
3222 : /* GetOverview() */
3223 : /************************************************************************/
3224 :
3225 : /**
3226 : * \brief Fetch overview raster band object.
3227 : *
3228 : * This method is the same as the C function GDALGetOverview().
3229 : *
3230 : * @param i overview index between 0 and GetOverviewCount()-1.
3231 : *
3232 : * @return overview GDALRasterBand.
3233 : */
3234 :
3235 789 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3236 :
3237 : {
3238 1523 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3239 734 : poDS->AreOverviewsEnabled())
3240 734 : return poDS->oOvManager.GetOverview(nBand, i);
3241 :
3242 55 : return nullptr;
3243 : }
3244 :
3245 : /************************************************************************/
3246 : /* GDALGetOverview() */
3247 : /************************************************************************/
3248 :
3249 : /**
3250 : * \brief Fetch overview raster band object.
3251 : *
3252 : * @see GDALRasterBand::GetOverview()
3253 : */
3254 :
3255 5472 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3256 :
3257 : {
3258 5472 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3259 :
3260 5472 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3261 5472 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3262 : }
3263 :
3264 : /************************************************************************/
3265 : /* GetRasterSampleOverview() */
3266 : /************************************************************************/
3267 :
3268 : /**
3269 : * \brief Fetch best sampling overview.
3270 : *
3271 : * Returns the most reduced overview of the given band that still satisfies
3272 : * the desired number of samples. This function can be used with zero
3273 : * as the number of desired samples to fetch the most reduced overview.
3274 : * The same band as was passed in will be returned if it has not overviews,
3275 : * or if none of the overviews have enough samples.
3276 : *
3277 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3278 : * and GDALGetRasterSampleOverviewEx().
3279 : *
3280 : * @param nDesiredSamples the returned band will have at least this many
3281 : * pixels.
3282 : *
3283 : * @return optimal overview or the band itself.
3284 : */
3285 :
3286 : GDALRasterBand *
3287 2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3288 :
3289 : {
3290 2006 : GDALRasterBand *poBestBand = this;
3291 :
3292 2006 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3293 :
3294 4023 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3295 : {
3296 2017 : GDALRasterBand *poOBand = GetOverview(iOverview);
3297 :
3298 2017 : if (poOBand == nullptr)
3299 0 : continue;
3300 :
3301 : const double dfOSamples =
3302 2017 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3303 :
3304 2017 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3305 : {
3306 2014 : dfBestSamples = dfOSamples;
3307 2014 : poBestBand = poOBand;
3308 : }
3309 : }
3310 :
3311 2006 : return poBestBand;
3312 : }
3313 :
3314 : /************************************************************************/
3315 : /* GDALGetRasterSampleOverview() */
3316 : /************************************************************************/
3317 :
3318 : /**
3319 : * \brief Fetch best sampling overview.
3320 : *
3321 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3322 : * billion samples.
3323 : *
3324 : * @see GDALRasterBand::GetRasterSampleOverview()
3325 : * @see GDALGetRasterSampleOverviewEx()
3326 : */
3327 :
3328 2000 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3329 : int nDesiredSamples)
3330 :
3331 : {
3332 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3333 :
3334 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3335 2000 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3336 4000 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3337 : }
3338 :
3339 : /************************************************************************/
3340 : /* GDALGetRasterSampleOverviewEx() */
3341 : /************************************************************************/
3342 :
3343 : /**
3344 : * \brief Fetch best sampling overview.
3345 : *
3346 : * @see GDALRasterBand::GetRasterSampleOverview()
3347 : * @since GDAL 2.0
3348 : */
3349 :
3350 : GDALRasterBandH CPL_STDCALL
3351 0 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3352 :
3353 : {
3354 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3355 :
3356 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3357 0 : return GDALRasterBand::ToHandle(
3358 0 : poBand->GetRasterSampleOverview(nDesiredSamples));
3359 : }
3360 :
3361 : /************************************************************************/
3362 : /* BuildOverviews() */
3363 : /************************************************************************/
3364 :
3365 : /**
3366 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3367 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3368 : *
3369 : * If the operation is unsupported for the indicated dataset, then
3370 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3371 : * CPLE_NotSupported.
3372 : *
3373 : * WARNING: Most formats don't support per-band overview computation, but
3374 : * require that overviews are computed for all bands of a dataset, using
3375 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3376 : * is the HFA driver which supports this method.
3377 : *
3378 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3379 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3380 : * applied.
3381 : * @param nOverviews number of overviews to build.
3382 : * @param panOverviewList the list of overview decimation factors to build.
3383 : * @param pfnProgress a function to call to report progress, or NULL.
3384 : * @param pProgressData application data to pass to the progress function.
3385 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3386 : * key=value pairs, or NULL
3387 : *
3388 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3389 : */
3390 :
3391 : /**/
3392 : /**/
3393 :
3394 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3395 : int /*nOverviews*/,
3396 : const int * /*panOverviewList*/,
3397 : GDALProgressFunc /*pfnProgress*/,
3398 : void * /*pProgressData*/,
3399 : CSLConstList /* papszOptions */)
3400 :
3401 : {
3402 0 : ReportError(CE_Failure, CPLE_NotSupported,
3403 : "BuildOverviews() not supported for this dataset.");
3404 :
3405 0 : return (CE_Failure);
3406 : }
3407 :
3408 : /************************************************************************/
3409 : /* GetOffset() */
3410 : /************************************************************************/
3411 :
3412 : /**
3413 : * \brief Fetch the raster value offset.
3414 : *
3415 : * This value (in combination with the GetScale() value) can be used to
3416 : * transform raw pixel values into the units returned by GetUnitType().
3417 : * For example this might be used to store elevations in GUInt16 bands
3418 : * with a precision of 0.1, and starting from -100.
3419 : *
3420 : * Units value = (raw value * scale) + offset
3421 : *
3422 : * Note that applying scale and offset is of the responsibility of the user,
3423 : * and is not done by methods such as RasterIO() or ReadBlock().
3424 : *
3425 : * For file formats that don't know this intrinsically a value of zero
3426 : * is returned.
3427 : *
3428 : * This method is the same as the C function GDALGetRasterOffset().
3429 : *
3430 : * @param pbSuccess pointer to a boolean to use to indicate if the
3431 : * returned value is meaningful or not. May be NULL (default).
3432 : *
3433 : * @return the raster offset.
3434 : */
3435 :
3436 389 : double GDALRasterBand::GetOffset(int *pbSuccess)
3437 :
3438 : {
3439 389 : if (pbSuccess != nullptr)
3440 321 : *pbSuccess = FALSE;
3441 :
3442 389 : return 0.0;
3443 : }
3444 :
3445 : /************************************************************************/
3446 : /* GDALGetRasterOffset() */
3447 : /************************************************************************/
3448 :
3449 : /**
3450 : * \brief Fetch the raster value offset.
3451 : *
3452 : * @see GDALRasterBand::GetOffset()
3453 : */
3454 :
3455 299 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3456 :
3457 : {
3458 299 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3459 :
3460 299 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3461 299 : return poBand->GetOffset(pbSuccess);
3462 : }
3463 :
3464 : /************************************************************************/
3465 : /* SetOffset() */
3466 : /************************************************************************/
3467 :
3468 : /**
3469 : * \fn GDALRasterBand::SetOffset(double)
3470 : * \brief Set scaling offset.
3471 : *
3472 : * Very few formats implement this method. When not implemented it will
3473 : * issue a CPLE_NotSupported error and return CE_Failure.
3474 : *
3475 : * This method is the same as the C function GDALSetRasterOffset().
3476 : *
3477 : * @param dfNewOffset the new offset.
3478 : *
3479 : * @return CE_None or success or CE_Failure on failure.
3480 : */
3481 :
3482 : /**/
3483 : /**/
3484 :
3485 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3486 : {
3487 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3488 0 : ReportError(CE_Failure, CPLE_NotSupported,
3489 : "SetOffset() not supported on this raster band.");
3490 :
3491 0 : return CE_Failure;
3492 : }
3493 :
3494 : /************************************************************************/
3495 : /* GDALSetRasterOffset() */
3496 : /************************************************************************/
3497 :
3498 : /**
3499 : * \brief Set scaling offset.
3500 : *
3501 : * @see GDALRasterBand::SetOffset()
3502 : */
3503 :
3504 41 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3505 : double dfNewOffset)
3506 :
3507 : {
3508 41 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3509 :
3510 41 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3511 41 : return poBand->SetOffset(dfNewOffset);
3512 : }
3513 :
3514 : /************************************************************************/
3515 : /* GetScale() */
3516 : /************************************************************************/
3517 :
3518 : /**
3519 : * \brief Fetch the raster value scale.
3520 : *
3521 : * This value (in combination with the GetOffset() value) can be used to
3522 : * transform raw pixel values into the units returned by GetUnitType().
3523 : * For example this might be used to store elevations in GUInt16 bands
3524 : * with a precision of 0.1, and starting from -100.
3525 : *
3526 : * Units value = (raw value * scale) + offset
3527 : *
3528 : * Note that applying scale and offset is of the responsibility of the user,
3529 : * and is not done by methods such as RasterIO() or ReadBlock().
3530 : *
3531 : * For file formats that don't know this intrinsically a value of one
3532 : * is returned.
3533 : *
3534 : * This method is the same as the C function GDALGetRasterScale().
3535 : *
3536 : * @param pbSuccess pointer to a boolean to use to indicate if the
3537 : * returned value is meaningful or not. May be NULL (default).
3538 : *
3539 : * @return the raster scale.
3540 : */
3541 :
3542 389 : double GDALRasterBand::GetScale(int *pbSuccess)
3543 :
3544 : {
3545 389 : if (pbSuccess != nullptr)
3546 321 : *pbSuccess = FALSE;
3547 :
3548 389 : return 1.0;
3549 : }
3550 :
3551 : /************************************************************************/
3552 : /* GDALGetRasterScale() */
3553 : /************************************************************************/
3554 :
3555 : /**
3556 : * \brief Fetch the raster value scale.
3557 : *
3558 : * @see GDALRasterBand::GetScale()
3559 : */
3560 :
3561 297 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3562 :
3563 : {
3564 297 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3565 :
3566 297 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3567 297 : return poBand->GetScale(pbSuccess);
3568 : }
3569 :
3570 : /************************************************************************/
3571 : /* SetScale() */
3572 : /************************************************************************/
3573 :
3574 : /**
3575 : * \fn GDALRasterBand::SetScale(double)
3576 : * \brief Set scaling ratio.
3577 : *
3578 : * Very few formats implement this method. When not implemented it will
3579 : * issue a CPLE_NotSupported error and return CE_Failure.
3580 : *
3581 : * This method is the same as the C function GDALSetRasterScale().
3582 : *
3583 : * @param dfNewScale the new scale.
3584 : *
3585 : * @return CE_None or success or CE_Failure on failure.
3586 : */
3587 :
3588 : /**/
3589 : /**/
3590 :
3591 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3592 :
3593 : {
3594 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3595 0 : ReportError(CE_Failure, CPLE_NotSupported,
3596 : "SetScale() not supported on this raster band.");
3597 :
3598 0 : return CE_Failure;
3599 : }
3600 :
3601 : /************************************************************************/
3602 : /* GDALSetRasterScale() */
3603 : /************************************************************************/
3604 :
3605 : /**
3606 : * \brief Set scaling ratio.
3607 : *
3608 : * @see GDALRasterBand::SetScale()
3609 : */
3610 :
3611 42 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3612 :
3613 : {
3614 42 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3615 :
3616 42 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3617 42 : return poBand->SetScale(dfNewOffset);
3618 : }
3619 :
3620 : /************************************************************************/
3621 : /* GetUnitType() */
3622 : /************************************************************************/
3623 :
3624 : /**
3625 : * \brief Return raster unit type.
3626 : *
3627 : * Return a name for the units of this raster's values. For instance, it
3628 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3629 : * units are available, a value of "" will be returned. The returned string
3630 : * should not be modified, nor freed by the calling application.
3631 : *
3632 : * This method is the same as the C function GDALGetRasterUnitType().
3633 : *
3634 : * @return unit name string.
3635 : */
3636 :
3637 155 : const char *GDALRasterBand::GetUnitType()
3638 :
3639 : {
3640 155 : return "";
3641 : }
3642 :
3643 : /************************************************************************/
3644 : /* GDALGetRasterUnitType() */
3645 : /************************************************************************/
3646 :
3647 : /**
3648 : * \brief Return raster unit type.
3649 : *
3650 : * @see GDALRasterBand::GetUnitType()
3651 : */
3652 :
3653 1284 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3654 :
3655 : {
3656 1284 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3657 :
3658 1284 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3659 1284 : return poBand->GetUnitType();
3660 : }
3661 :
3662 : /************************************************************************/
3663 : /* SetUnitType() */
3664 : /************************************************************************/
3665 :
3666 : /**
3667 : * \fn GDALRasterBand::SetUnitType(const char*)
3668 : * \brief Set unit type.
3669 : *
3670 : * Set the unit type for a raster band. Values should be one of
3671 : * "" (the default indicating it is unknown), "m" indicating meters,
3672 : * or "ft" indicating feet, though other nonstandard values are allowed.
3673 : *
3674 : * This method is the same as the C function GDALSetRasterUnitType().
3675 : *
3676 : * @param pszNewValue the new unit type value.
3677 : *
3678 : * @return CE_None on success or CE_Failure if not successful, or
3679 : * unsupported.
3680 : */
3681 :
3682 : /**/
3683 : /**/
3684 :
3685 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3686 :
3687 : {
3688 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3689 0 : ReportError(CE_Failure, CPLE_NotSupported,
3690 : "SetUnitType() not supported on this raster band.");
3691 0 : return CE_Failure;
3692 : }
3693 :
3694 : /************************************************************************/
3695 : /* GDALSetRasterUnitType() */
3696 : /************************************************************************/
3697 :
3698 : /**
3699 : * \brief Set unit type.
3700 : *
3701 : * @see GDALRasterBand::SetUnitType()
3702 : *
3703 : * @since GDAL 1.8.0
3704 : */
3705 :
3706 60 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3707 : const char *pszNewValue)
3708 :
3709 : {
3710 60 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3711 :
3712 60 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3713 60 : return poBand->SetUnitType(pszNewValue);
3714 : }
3715 :
3716 : /************************************************************************/
3717 : /* GetXSize() */
3718 : /************************************************************************/
3719 :
3720 : /**
3721 : * \brief Fetch XSize of raster.
3722 : *
3723 : * This method is the same as the C function GDALGetRasterBandXSize().
3724 : *
3725 : * @return the width in pixels of this band.
3726 : */
3727 :
3728 6677230 : int GDALRasterBand::GetXSize() const
3729 :
3730 : {
3731 6677230 : return nRasterXSize;
3732 : }
3733 :
3734 : /************************************************************************/
3735 : /* GDALGetRasterBandXSize() */
3736 : /************************************************************************/
3737 :
3738 : /**
3739 : * \brief Fetch XSize of raster.
3740 : *
3741 : * @see GDALRasterBand::GetXSize()
3742 : */
3743 :
3744 51913 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3745 :
3746 : {
3747 51913 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3748 :
3749 51913 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3750 51913 : return poBand->GetXSize();
3751 : }
3752 :
3753 : /************************************************************************/
3754 : /* GetYSize() */
3755 : /************************************************************************/
3756 :
3757 : /**
3758 : * \brief Fetch YSize of raster.
3759 : *
3760 : * This method is the same as the C function GDALGetRasterBandYSize().
3761 : *
3762 : * @return the height in pixels of this band.
3763 : */
3764 :
3765 3231310 : int GDALRasterBand::GetYSize() const
3766 :
3767 : {
3768 3231310 : return nRasterYSize;
3769 : }
3770 :
3771 : /************************************************************************/
3772 : /* GDALGetRasterBandYSize() */
3773 : /************************************************************************/
3774 :
3775 : /**
3776 : * \brief Fetch YSize of raster.
3777 : *
3778 : * @see GDALRasterBand::GetYSize()
3779 : */
3780 :
3781 51290 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3782 :
3783 : {
3784 51290 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3785 :
3786 51290 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3787 51290 : return poBand->GetYSize();
3788 : }
3789 :
3790 : /************************************************************************/
3791 : /* GetBand() */
3792 : /************************************************************************/
3793 :
3794 : /**
3795 : * \brief Fetch the band number.
3796 : *
3797 : * This method returns the band that this GDALRasterBand objects represents
3798 : * within its dataset. This method may return a value of 0 to indicate
3799 : * GDALRasterBand objects without an apparently relationship to a dataset,
3800 : * such as GDALRasterBands serving as overviews.
3801 : *
3802 : * This method is the same as the C function GDALGetBandNumber().
3803 : *
3804 : * @return band number (1+) or 0 if the band number isn't known.
3805 : */
3806 :
3807 19101 : int GDALRasterBand::GetBand() const
3808 :
3809 : {
3810 19101 : return nBand;
3811 : }
3812 :
3813 : /************************************************************************/
3814 : /* GDALGetBandNumber() */
3815 : /************************************************************************/
3816 :
3817 : /**
3818 : * \brief Fetch the band number.
3819 : *
3820 : * @see GDALRasterBand::GetBand()
3821 : */
3822 :
3823 147 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3824 :
3825 : {
3826 147 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3827 :
3828 147 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3829 147 : return poBand->GetBand();
3830 : }
3831 :
3832 : /************************************************************************/
3833 : /* GetDataset() */
3834 : /************************************************************************/
3835 :
3836 : /**
3837 : * \brief Fetch the owning dataset handle.
3838 : *
3839 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3840 : * such as overviews or other "freestanding" bands.
3841 : *
3842 : * This method is the same as the C function GDALGetBandDataset().
3843 : *
3844 : * @return the pointer to the GDALDataset to which this band belongs, or
3845 : * NULL if this cannot be determined.
3846 : */
3847 :
3848 3792690 : GDALDataset *GDALRasterBand::GetDataset() const
3849 :
3850 : {
3851 3792690 : return poDS;
3852 : }
3853 :
3854 : /************************************************************************/
3855 : /* GDALGetBandDataset() */
3856 : /************************************************************************/
3857 :
3858 : /**
3859 : * \brief Fetch the owning dataset handle.
3860 : *
3861 : * @see GDALRasterBand::GetDataset()
3862 : */
3863 :
3864 300 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
3865 :
3866 : {
3867 300 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
3868 :
3869 300 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3870 300 : return GDALDataset::ToHandle(poBand->GetDataset());
3871 : }
3872 :
3873 : /************************************************************************/
3874 : /* ComputeFloatNoDataValue() */
3875 : /************************************************************************/
3876 :
3877 2017 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
3878 : double dfNoDataValue,
3879 : int &bGotNoDataValue,
3880 : float &fNoDataValue,
3881 : bool &bGotFloatNoDataValue)
3882 : {
3883 2017 : if (eDataType == GDT_Float32 && bGotNoDataValue)
3884 : {
3885 81 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
3886 81 : if (GDALIsValueInRange<float>(dfNoDataValue))
3887 : {
3888 81 : fNoDataValue = static_cast<float>(dfNoDataValue);
3889 81 : bGotFloatNoDataValue = true;
3890 81 : bGotNoDataValue = false;
3891 : }
3892 : }
3893 2017 : }
3894 :
3895 : /************************************************************************/
3896 : /* GetHistogram() */
3897 : /************************************************************************/
3898 :
3899 : /**
3900 : * \brief Compute raster histogram.
3901 : *
3902 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
3903 : *
3904 : * For example to compute a simple 256 entry histogram of eight bit data,
3905 : * the following would be suitable. The unusual bounds are to ensure that
3906 : * bucket boundaries don't fall right on integer values causing possible errors
3907 : * due to rounding after scaling.
3908 : \code{.cpp}
3909 : GUIntBig anHistogram[256];
3910 :
3911 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
3912 : GDALDummyProgress, nullptr );
3913 : \endcode
3914 : *
3915 : * Note that setting bApproxOK will generally result in a subsampling of the
3916 : * file, and will utilize overviews if available. It should generally
3917 : * produce a representative histogram for the data that is suitable for use
3918 : * in generating histogram based luts for instance. Generally bApproxOK is
3919 : * much faster than an exactly computed histogram.
3920 : *
3921 : * This method is the same as the C functions GDALGetRasterHistogram() and
3922 : * GDALGetRasterHistogramEx().
3923 : *
3924 : * @param dfMin the lower bound of the histogram.
3925 : * @param dfMax the upper bound of the histogram.
3926 : * @param nBuckets the number of buckets in panHistogram.
3927 : * @param panHistogram array into which the histogram totals are placed.
3928 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
3929 : * mapped into panHistogram[0], and values above will be mapped into
3930 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
3931 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
3932 : * @param pfnProgress function to report progress to completion.
3933 : * @param pProgressData application data to pass to pfnProgress.
3934 : *
3935 : * @return CE_None on success, or CE_Failure if something goes wrong.
3936 : */
3937 :
3938 38 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
3939 : GUIntBig *panHistogram,
3940 : int bIncludeOutOfRange, int bApproxOK,
3941 : GDALProgressFunc pfnProgress,
3942 : void *pProgressData)
3943 :
3944 : {
3945 38 : CPLAssert(nullptr != panHistogram);
3946 :
3947 38 : if (pfnProgress == nullptr)
3948 26 : pfnProgress = GDALDummyProgress;
3949 :
3950 : /* -------------------------------------------------------------------- */
3951 : /* If we have overviews, use them for the histogram. */
3952 : /* -------------------------------------------------------------------- */
3953 38 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
3954 : {
3955 : // FIXME: should we use the most reduced overview here or use some
3956 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
3957 : // does?
3958 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
3959 :
3960 0 : if (poBestOverview != this)
3961 : {
3962 0 : return poBestOverview->GetHistogram(
3963 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
3964 0 : bApproxOK, pfnProgress, pProgressData);
3965 : }
3966 : }
3967 :
3968 : /* -------------------------------------------------------------------- */
3969 : /* Read actual data and build histogram. */
3970 : /* -------------------------------------------------------------------- */
3971 38 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
3972 : {
3973 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3974 0 : return CE_Failure;
3975 : }
3976 :
3977 : // Written this way to deal with NaN
3978 38 : if (!(dfMax > dfMin))
3979 : {
3980 5 : ReportError(CE_Failure, CPLE_IllegalArg,
3981 : "dfMax should be strictly greater than dfMin");
3982 5 : return CE_Failure;
3983 : }
3984 :
3985 : GDALRasterIOExtraArg sExtraArg;
3986 33 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3987 :
3988 33 : const double dfScale = nBuckets / (dfMax - dfMin);
3989 33 : if (dfScale == 0 || !std::isfinite(dfScale))
3990 : {
3991 5 : ReportError(CE_Failure, CPLE_IllegalArg,
3992 : "dfMin and dfMax should be finite values such that "
3993 : "nBuckets / (dfMax - dfMin) is non-zero");
3994 5 : return CE_Failure;
3995 : }
3996 28 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
3997 :
3998 28 : int bGotNoDataValue = FALSE;
3999 28 : const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
4000 28 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4001 28 : bool bGotFloatNoDataValue = false;
4002 28 : float fNoDataValue = 0.0f;
4003 28 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4004 : fNoDataValue, bGotFloatNoDataValue);
4005 28 : GDALRasterBand *poMaskBand = nullptr;
4006 28 : if (!bGotNoDataValue)
4007 : {
4008 27 : const int l_nMaskFlags = GetMaskFlags();
4009 28 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
4010 1 : GetColorInterpretation() != GCI_AlphaBand)
4011 : {
4012 1 : poMaskBand = GetMaskBand();
4013 : }
4014 : }
4015 :
4016 28 : bool bSignedByte = false;
4017 28 : if (eDataType == GDT_Byte)
4018 : {
4019 21 : EnablePixelTypeSignedByteWarning(false);
4020 : const char *pszPixelType =
4021 21 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4022 21 : EnablePixelTypeSignedByteWarning(true);
4023 21 : bSignedByte =
4024 21 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4025 : }
4026 :
4027 28 : if (bApproxOK && HasArbitraryOverviews())
4028 : {
4029 : /* --------------------------------------------------------------------
4030 : */
4031 : /* Figure out how much the image should be reduced to get an */
4032 : /* approximate value. */
4033 : /* --------------------------------------------------------------------
4034 : */
4035 : const double dfReduction =
4036 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4037 : GDALSTAT_APPROX_NUMSAMPLES);
4038 :
4039 0 : int nXReduced = nRasterXSize;
4040 0 : int nYReduced = nRasterYSize;
4041 0 : if (dfReduction > 1.0)
4042 : {
4043 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4044 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4045 :
4046 : // Catch the case of huge resizing ratios here
4047 0 : if (nXReduced == 0)
4048 0 : nXReduced = 1;
4049 0 : if (nYReduced == 0)
4050 0 : nYReduced = 1;
4051 : }
4052 :
4053 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4054 : nXReduced, nYReduced);
4055 0 : if (!pData)
4056 0 : return CE_Failure;
4057 :
4058 : const CPLErr eErr =
4059 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4060 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4061 0 : if (eErr != CE_None)
4062 : {
4063 0 : CPLFree(pData);
4064 0 : return eErr;
4065 : }
4066 :
4067 0 : GByte *pabyMaskData = nullptr;
4068 0 : if (poMaskBand)
4069 : {
4070 : pabyMaskData =
4071 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4072 0 : if (!pabyMaskData)
4073 : {
4074 0 : CPLFree(pData);
4075 0 : return CE_Failure;
4076 : }
4077 :
4078 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4079 : pabyMaskData, nXReduced, nYReduced,
4080 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
4081 : {
4082 0 : CPLFree(pData);
4083 0 : CPLFree(pabyMaskData);
4084 0 : return CE_Failure;
4085 : }
4086 : }
4087 :
4088 : // This isn't the fastest way to do this, but is easier for now.
4089 0 : for (int iY = 0; iY < nYReduced; iY++)
4090 : {
4091 0 : for (int iX = 0; iX < nXReduced; iX++)
4092 : {
4093 0 : const int iOffset = iX + iY * nXReduced;
4094 0 : double dfValue = 0.0;
4095 :
4096 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4097 0 : continue;
4098 :
4099 0 : switch (eDataType)
4100 : {
4101 0 : case GDT_Byte:
4102 : {
4103 0 : if (bSignedByte)
4104 0 : dfValue =
4105 0 : static_cast<signed char *>(pData)[iOffset];
4106 : else
4107 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4108 0 : break;
4109 : }
4110 0 : case GDT_Int8:
4111 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4112 0 : break;
4113 0 : case GDT_UInt16:
4114 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4115 0 : break;
4116 0 : case GDT_Int16:
4117 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4118 0 : break;
4119 0 : case GDT_UInt32:
4120 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4121 0 : break;
4122 0 : case GDT_Int32:
4123 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4124 0 : break;
4125 0 : case GDT_UInt64:
4126 0 : dfValue = static_cast<double>(
4127 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4128 0 : break;
4129 0 : case GDT_Int64:
4130 0 : dfValue = static_cast<double>(
4131 0 : static_cast<GInt64 *>(pData)[iOffset]);
4132 0 : break;
4133 0 : case GDT_Float32:
4134 : {
4135 0 : const float fValue =
4136 0 : static_cast<float *>(pData)[iOffset];
4137 0 : if (std::isnan(fValue) ||
4138 0 : (bGotFloatNoDataValue &&
4139 0 : ARE_REAL_EQUAL(fValue, fNoDataValue)))
4140 0 : continue;
4141 0 : dfValue = fValue;
4142 0 : break;
4143 : }
4144 0 : case GDT_Float64:
4145 0 : dfValue = static_cast<double *>(pData)[iOffset];
4146 0 : if (std::isnan(dfValue))
4147 0 : continue;
4148 0 : break;
4149 0 : case GDT_CInt16:
4150 : {
4151 0 : const double dfReal =
4152 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4153 0 : const double dfImag =
4154 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4155 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4156 0 : continue;
4157 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4158 : }
4159 0 : break;
4160 0 : case GDT_CInt32:
4161 : {
4162 0 : const double dfReal =
4163 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4164 0 : const double dfImag =
4165 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4166 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4167 0 : continue;
4168 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4169 : }
4170 0 : break;
4171 0 : case GDT_CFloat32:
4172 : {
4173 0 : const double dfReal =
4174 0 : static_cast<float *>(pData)[iOffset * 2];
4175 0 : const double dfImag =
4176 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
4177 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4178 0 : continue;
4179 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4180 : }
4181 0 : break;
4182 0 : case GDT_CFloat64:
4183 : {
4184 0 : const double dfReal =
4185 0 : static_cast<double *>(pData)[iOffset * 2];
4186 0 : const double dfImag =
4187 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4188 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4189 0 : continue;
4190 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4191 : }
4192 0 : break;
4193 0 : case GDT_Unknown:
4194 : case GDT_TypeCount:
4195 0 : CPLAssert(false);
4196 : }
4197 :
4198 0 : if (eDataType != GDT_Float32 && bGotNoDataValue &&
4199 0 : ARE_REAL_EQUAL(dfValue, dfNoDataValue))
4200 0 : continue;
4201 :
4202 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4203 : // finite, the result of the multiplication cannot be NaN
4204 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4205 :
4206 0 : if (dfIndex < 0)
4207 : {
4208 0 : if (bIncludeOutOfRange)
4209 0 : panHistogram[0]++;
4210 : }
4211 0 : else if (dfIndex >= nBuckets)
4212 : {
4213 0 : if (bIncludeOutOfRange)
4214 0 : ++panHistogram[nBuckets - 1];
4215 : }
4216 : else
4217 : {
4218 0 : ++panHistogram[static_cast<int>(dfIndex)];
4219 : }
4220 : }
4221 : }
4222 :
4223 0 : CPLFree(pData);
4224 0 : CPLFree(pabyMaskData);
4225 : }
4226 : else // No arbitrary overviews.
4227 : {
4228 28 : if (!InitBlockInfo())
4229 0 : return CE_Failure;
4230 :
4231 : /* --------------------------------------------------------------------
4232 : */
4233 : /* Figure out the ratio of blocks we will read to get an */
4234 : /* approximate value. */
4235 : /* --------------------------------------------------------------------
4236 : */
4237 :
4238 28 : int nSampleRate = 1;
4239 28 : if (bApproxOK)
4240 : {
4241 8 : nSampleRate = static_cast<int>(std::max(
4242 16 : 1.0,
4243 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4244 : // We want to avoid probing only the first column of blocks for
4245 : // a square shaped raster, because it is not unlikely that it may
4246 : // be padding only (#6378).
4247 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4248 2 : nSampleRate += 1;
4249 : }
4250 :
4251 28 : GByte *pabyMaskData = nullptr;
4252 28 : if (poMaskBand)
4253 : {
4254 : pabyMaskData = static_cast<GByte *>(
4255 1 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4256 1 : if (!pabyMaskData)
4257 : {
4258 0 : return CE_Failure;
4259 : }
4260 : }
4261 :
4262 : /* --------------------------------------------------------------------
4263 : */
4264 : /* Read the blocks, and add to histogram. */
4265 : /* --------------------------------------------------------------------
4266 : */
4267 28 : for (GIntBig iSampleBlock = 0;
4268 115 : iSampleBlock <
4269 115 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4270 87 : iSampleBlock += nSampleRate)
4271 : {
4272 87 : if (!pfnProgress(
4273 87 : static_cast<double>(iSampleBlock) /
4274 87 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4275 : "Compute Histogram", pProgressData))
4276 : {
4277 0 : CPLFree(pabyMaskData);
4278 0 : return CE_Failure;
4279 : }
4280 :
4281 87 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4282 87 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4283 :
4284 87 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4285 87 : if (poBlock == nullptr)
4286 : {
4287 0 : CPLFree(pabyMaskData);
4288 0 : return CE_Failure;
4289 : }
4290 :
4291 87 : void *pData = poBlock->GetDataRef();
4292 :
4293 87 : int nXCheck = 0, nYCheck = 0;
4294 87 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4295 :
4296 88 : if (poMaskBand &&
4297 1 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4298 1 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4299 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4300 1 : 0, nBlockXSize, nullptr) != CE_None)
4301 : {
4302 0 : CPLFree(pabyMaskData);
4303 0 : poBlock->DropLock();
4304 0 : return CE_Failure;
4305 : }
4306 :
4307 : // this is a special case for a common situation.
4308 87 : if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4309 65 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4310 62 : nXCheck == nBlockXSize && nBuckets == 256)
4311 : {
4312 62 : const GPtrDiff_t nPixels =
4313 62 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4314 62 : GByte *pabyData = static_cast<GByte *>(pData);
4315 :
4316 71714 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4317 : {
4318 71652 : if (pabyMaskData && pabyMaskData[i] == 0)
4319 0 : continue;
4320 72164 : if (!(bGotNoDataValue &&
4321 71652 : (pabyData[i] == static_cast<GByte>(dfNoDataValue))))
4322 : {
4323 71396 : panHistogram[pabyData[i]]++;
4324 : }
4325 : }
4326 :
4327 62 : poBlock->DropLock();
4328 62 : continue; // To next sample block.
4329 : }
4330 :
4331 : // This isn't the fastest way to do this, but is easier for now.
4332 721 : for (int iY = 0; iY < nYCheck; iY++)
4333 : {
4334 86017 : for (int iX = 0; iX < nXCheck; iX++)
4335 : {
4336 85321 : const GPtrDiff_t iOffset =
4337 85321 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4338 :
4339 85321 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4340 1 : continue;
4341 :
4342 85320 : double dfValue = 0.0;
4343 :
4344 85320 : switch (eDataType)
4345 : {
4346 19716 : case GDT_Byte:
4347 : {
4348 19716 : if (bSignedByte)
4349 0 : dfValue =
4350 0 : static_cast<signed char *>(pData)[iOffset];
4351 : else
4352 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4353 19716 : break;
4354 : }
4355 0 : case GDT_Int8:
4356 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4357 0 : break;
4358 65536 : case GDT_UInt16:
4359 65536 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4360 65536 : break;
4361 2 : case GDT_Int16:
4362 2 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4363 2 : break;
4364 0 : case GDT_UInt32:
4365 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4366 0 : break;
4367 60 : case GDT_Int32:
4368 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4369 60 : break;
4370 0 : case GDT_UInt64:
4371 0 : dfValue = static_cast<double>(
4372 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4373 0 : break;
4374 0 : case GDT_Int64:
4375 0 : dfValue = static_cast<double>(
4376 0 : static_cast<GInt64 *>(pData)[iOffset]);
4377 0 : break;
4378 4 : case GDT_Float32:
4379 : {
4380 4 : const float fValue =
4381 4 : static_cast<float *>(pData)[iOffset];
4382 8 : if (std::isnan(fValue) ||
4383 4 : (bGotFloatNoDataValue &&
4384 4 : ARE_REAL_EQUAL(fValue, fNoDataValue)))
4385 1 : continue;
4386 3 : dfValue = fValue;
4387 3 : break;
4388 : }
4389 2 : case GDT_Float64:
4390 2 : dfValue = static_cast<double *>(pData)[iOffset];
4391 2 : if (std::isnan(dfValue))
4392 0 : continue;
4393 2 : break;
4394 0 : case GDT_CInt16:
4395 : {
4396 0 : double dfReal =
4397 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4398 0 : double dfImag =
4399 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4400 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4401 : }
4402 0 : break;
4403 0 : case GDT_CInt32:
4404 : {
4405 0 : double dfReal =
4406 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4407 0 : double dfImag =
4408 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4409 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4410 : }
4411 0 : break;
4412 0 : case GDT_CFloat32:
4413 : {
4414 0 : double dfReal =
4415 0 : static_cast<float *>(pData)[iOffset * 2];
4416 0 : double dfImag =
4417 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
4418 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4419 0 : continue;
4420 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4421 : }
4422 0 : break;
4423 0 : case GDT_CFloat64:
4424 : {
4425 0 : double dfReal =
4426 0 : static_cast<double *>(pData)[iOffset * 2];
4427 0 : double dfImag =
4428 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4429 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4430 0 : continue;
4431 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4432 : }
4433 0 : break;
4434 0 : case GDT_Unknown:
4435 : case GDT_TypeCount:
4436 0 : CPLAssert(false);
4437 : CPLFree(pabyMaskData);
4438 : return CE_Failure;
4439 : }
4440 :
4441 85319 : if (eDataType != GDT_Float32 && bGotNoDataValue &&
4442 0 : ARE_REAL_EQUAL(dfValue, dfNoDataValue))
4443 0 : continue;
4444 :
4445 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4446 : // and finite, the result of the multiplication cannot be
4447 : // NaN
4448 85319 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4449 :
4450 85319 : if (dfIndex < 0)
4451 : {
4452 1 : if (bIncludeOutOfRange)
4453 1 : panHistogram[0]++;
4454 : }
4455 85318 : else if (dfIndex >= nBuckets)
4456 : {
4457 7 : if (bIncludeOutOfRange)
4458 4 : ++panHistogram[nBuckets - 1];
4459 : }
4460 : else
4461 : {
4462 85311 : ++panHistogram[static_cast<int>(dfIndex)];
4463 : }
4464 : }
4465 : }
4466 :
4467 25 : poBlock->DropLock();
4468 : }
4469 :
4470 28 : CPLFree(pabyMaskData);
4471 : }
4472 :
4473 28 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4474 :
4475 28 : return CE_None;
4476 : }
4477 :
4478 : /************************************************************************/
4479 : /* GDALGetRasterHistogram() */
4480 : /************************************************************************/
4481 :
4482 : /**
4483 : * \brief Compute raster histogram.
4484 : *
4485 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4486 : * exceeding 2 billion.
4487 : *
4488 : * @see GDALRasterBand::GetHistogram()
4489 : * @see GDALGetRasterHistogramEx()
4490 : */
4491 :
4492 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4493 : double dfMax, int nBuckets,
4494 : int *panHistogram,
4495 : int bIncludeOutOfRange, int bApproxOK,
4496 : GDALProgressFunc pfnProgress,
4497 : void *pProgressData)
4498 :
4499 : {
4500 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4501 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4502 :
4503 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4504 :
4505 : GUIntBig *panHistogramTemp =
4506 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4507 0 : if (panHistogramTemp == nullptr)
4508 : {
4509 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4510 : "Out of memory in GDALGetRasterHistogram().");
4511 0 : return CE_Failure;
4512 : }
4513 :
4514 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4515 : bIncludeOutOfRange, bApproxOK,
4516 0 : pfnProgress, pProgressData);
4517 :
4518 0 : if (eErr == CE_None)
4519 : {
4520 0 : for (int i = 0; i < nBuckets; i++)
4521 : {
4522 0 : if (panHistogramTemp[i] > INT_MAX)
4523 : {
4524 0 : CPLError(CE_Warning, CPLE_AppDefined,
4525 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4526 : " exceeds maximum 32 bit value",
4527 0 : i, panHistogramTemp[i]);
4528 0 : panHistogram[i] = INT_MAX;
4529 : }
4530 : else
4531 : {
4532 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4533 : }
4534 : }
4535 : }
4536 :
4537 0 : CPLFree(panHistogramTemp);
4538 :
4539 0 : return eErr;
4540 : }
4541 :
4542 : /************************************************************************/
4543 : /* GDALGetRasterHistogramEx() */
4544 : /************************************************************************/
4545 :
4546 : /**
4547 : * \brief Compute raster histogram.
4548 : *
4549 : * @see GDALRasterBand::GetHistogram()
4550 : *
4551 : * @since GDAL 2.0
4552 : */
4553 :
4554 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4555 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4556 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4557 : GDALProgressFunc pfnProgress, void *pProgressData)
4558 :
4559 : {
4560 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4561 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4562 :
4563 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4564 :
4565 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4566 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4567 26 : pProgressData);
4568 : }
4569 :
4570 : /************************************************************************/
4571 : /* GetDefaultHistogram() */
4572 : /************************************************************************/
4573 :
4574 : /**
4575 : * \brief Fetch default raster histogram.
4576 : *
4577 : * The default method in GDALRasterBand will compute a default histogram. This
4578 : * method is overridden by derived classes (such as GDALPamRasterBand,
4579 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4580 : * stored histogram.
4581 : *
4582 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4583 : * GDALGetDefaultHistogramEx().
4584 : *
4585 : * @param pdfMin pointer to double value that will contain the lower bound of
4586 : * the histogram.
4587 : * @param pdfMax pointer to double value that will contain the upper bound of
4588 : * the histogram.
4589 : * @param pnBuckets pointer to int value that will contain the number of buckets
4590 : * in *ppanHistogram.
4591 : * @param ppanHistogram pointer to array into which the histogram totals are
4592 : * placed. To be freed with VSIFree
4593 : * @param bForce TRUE to force the computation. If FALSE and no default
4594 : * histogram is available, the method will return CE_Warning
4595 : * @param pfnProgress function to report progress to completion.
4596 : * @param pProgressData application data to pass to pfnProgress.
4597 : *
4598 : * @return CE_None on success, CE_Failure if something goes wrong, or
4599 : * CE_Warning if no default histogram is available.
4600 : */
4601 :
4602 21 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4603 : int *pnBuckets,
4604 : GUIntBig **ppanHistogram, int bForce,
4605 : GDALProgressFunc pfnProgress,
4606 : void *pProgressData)
4607 :
4608 : {
4609 21 : CPLAssert(nullptr != pnBuckets);
4610 21 : CPLAssert(nullptr != ppanHistogram);
4611 21 : CPLAssert(nullptr != pdfMin);
4612 21 : CPLAssert(nullptr != pdfMax);
4613 :
4614 21 : *pnBuckets = 0;
4615 21 : *ppanHistogram = nullptr;
4616 :
4617 21 : if (!bForce)
4618 6 : return CE_Warning;
4619 :
4620 15 : const int nBuckets = 256;
4621 :
4622 15 : bool bSignedByte = false;
4623 15 : if (eDataType == GDT_Byte)
4624 : {
4625 15 : EnablePixelTypeSignedByteWarning(false);
4626 : const char *pszPixelType =
4627 15 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4628 15 : EnablePixelTypeSignedByteWarning(true);
4629 15 : bSignedByte =
4630 15 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4631 : }
4632 :
4633 15 : if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4634 : {
4635 15 : *pdfMin = -0.5;
4636 15 : *pdfMax = 255.5;
4637 : }
4638 : else
4639 : {
4640 :
4641 : const CPLErr eErr =
4642 0 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4643 0 : const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4644 0 : *pdfMin -= dfHalfBucket;
4645 0 : *pdfMax += dfHalfBucket;
4646 :
4647 0 : if (eErr != CE_None)
4648 0 : return eErr;
4649 : }
4650 :
4651 15 : *ppanHistogram =
4652 15 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4653 15 : if (*ppanHistogram == nullptr)
4654 : {
4655 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4656 : "Out of memory in InitBlockInfo().");
4657 0 : return CE_Failure;
4658 : }
4659 :
4660 15 : *pnBuckets = nBuckets;
4661 30 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4662 15 : TRUE, FALSE, pfnProgress, pProgressData);
4663 15 : if (eErr != CE_None)
4664 : {
4665 0 : *pnBuckets = 0;
4666 : }
4667 15 : return eErr;
4668 : }
4669 :
4670 : /************************************************************************/
4671 : /* GDALGetDefaultHistogram() */
4672 : /************************************************************************/
4673 :
4674 : /**
4675 : * \brief Fetch default raster histogram.
4676 : *
4677 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4678 : * exceeding 2 billion.
4679 : *
4680 : * @see GDALRasterBand::GDALGetDefaultHistogram()
4681 : * @see GDALGetRasterHistogramEx()
4682 : */
4683 :
4684 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4685 : double *pdfMin, double *pdfMax,
4686 : int *pnBuckets, int **ppanHistogram,
4687 : int bForce,
4688 : GDALProgressFunc pfnProgress,
4689 : void *pProgressData)
4690 :
4691 : {
4692 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4693 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4694 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4695 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4696 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4697 :
4698 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4699 0 : GUIntBig *panHistogramTemp = nullptr;
4700 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
4701 : &panHistogramTemp, bForce,
4702 0 : pfnProgress, pProgressData);
4703 0 : if (eErr == CE_None)
4704 : {
4705 0 : const int nBuckets = *pnBuckets;
4706 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
4707 0 : if (*ppanHistogram == nullptr)
4708 : {
4709 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4710 : "Out of memory in GDALGetDefaultHistogram().");
4711 0 : VSIFree(panHistogramTemp);
4712 0 : return CE_Failure;
4713 : }
4714 :
4715 0 : for (int i = 0; i < nBuckets; ++i)
4716 : {
4717 0 : if (panHistogramTemp[i] > INT_MAX)
4718 : {
4719 0 : CPLError(CE_Warning, CPLE_AppDefined,
4720 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4721 : " exceeds maximum 32 bit value",
4722 0 : i, panHistogramTemp[i]);
4723 0 : (*ppanHistogram)[i] = INT_MAX;
4724 : }
4725 : else
4726 : {
4727 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
4728 : }
4729 : }
4730 :
4731 0 : CPLFree(panHistogramTemp);
4732 : }
4733 : else
4734 : {
4735 0 : *ppanHistogram = nullptr;
4736 : }
4737 :
4738 0 : return eErr;
4739 : }
4740 :
4741 : /************************************************************************/
4742 : /* GDALGetDefaultHistogramEx() */
4743 : /************************************************************************/
4744 :
4745 : /**
4746 : * \brief Fetch default raster histogram.
4747 : *
4748 : * @see GDALRasterBand::GetDefaultHistogram()
4749 : *
4750 : * @since GDAL 2.0
4751 : */
4752 :
4753 : CPLErr CPL_STDCALL
4754 27 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
4755 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
4756 : GDALProgressFunc pfnProgress, void *pProgressData)
4757 :
4758 : {
4759 27 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4760 27 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4761 27 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4762 27 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4763 27 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4764 :
4765 27 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4766 27 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
4767 27 : bForce, pfnProgress, pProgressData);
4768 : }
4769 :
4770 : /************************************************************************/
4771 : /* AdviseRead() */
4772 : /************************************************************************/
4773 :
4774 : /**
4775 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
4776 : * \brief Advise driver of upcoming read requests.
4777 : *
4778 : * Some GDAL drivers operate more efficiently if they know in advance what
4779 : * set of upcoming read requests will be made. The AdviseRead() method allows
4780 : * an application to notify the driver of the region of interest,
4781 : * and at what resolution the region will be read.
4782 : *
4783 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
4784 : * accelerate access via some drivers.
4785 : *
4786 : * Depending on call paths, drivers might receive several calls to
4787 : * AdviseRead() with the same parameters.
4788 : *
4789 : * @param nXOff The pixel offset to the top left corner of the region
4790 : * of the band to be accessed. This would be zero to start from the left side.
4791 : *
4792 : * @param nYOff The line offset to the top left corner of the region
4793 : * of the band to be accessed. This would be zero to start from the top.
4794 : *
4795 : * @param nXSize The width of the region of the band to be accessed in pixels.
4796 : *
4797 : * @param nYSize The height of the region of the band to be accessed in lines.
4798 : *
4799 : * @param nBufXSize the width of the buffer image into which the desired region
4800 : * is to be read, or from which it is to be written.
4801 : *
4802 : * @param nBufYSize the height of the buffer image into which the desired
4803 : * region is to be read, or from which it is to be written.
4804 : *
4805 : * @param eBufType the type of the pixel values in the pData data buffer. The
4806 : * pixel values will automatically be translated to/from the GDALRasterBand
4807 : * data type as needed.
4808 : *
4809 : * @param papszOptions a list of name=value strings with special control
4810 : * options. Normally this is NULL.
4811 : *
4812 : * @return CE_Failure if the request is invalid and CE_None if it works or
4813 : * is ignored.
4814 : */
4815 :
4816 : /**/
4817 : /**/
4818 :
4819 42000 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
4820 : int /*nYSize*/, int /*nBufXSize*/,
4821 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
4822 : char ** /*papszOptions*/)
4823 : {
4824 42000 : return CE_None;
4825 : }
4826 :
4827 : /************************************************************************/
4828 : /* GDALRasterAdviseRead() */
4829 : /************************************************************************/
4830 :
4831 : /**
4832 : * \brief Advise driver of upcoming read requests.
4833 : *
4834 : * @see GDALRasterBand::AdviseRead()
4835 : */
4836 :
4837 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
4838 : int nYOff, int nXSize, int nYSize,
4839 : int nBufXSize, int nBufYSize,
4840 : GDALDataType eDT,
4841 : CSLConstList papszOptions)
4842 :
4843 : {
4844 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
4845 :
4846 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4847 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
4848 : nBufYSize, eDT,
4849 2 : const_cast<char **>(papszOptions));
4850 : }
4851 :
4852 : /************************************************************************/
4853 : /* GetStatistics() */
4854 : /************************************************************************/
4855 :
4856 : /**
4857 : * \brief Fetch image statistics.
4858 : *
4859 : * Returns the minimum, maximum, mean and standard deviation of all
4860 : * pixel values in this band. If approximate statistics are sufficient,
4861 : * the bApproxOK flag can be set to true in which case overviews, or a
4862 : * subset of image tiles may be used in computing the statistics.
4863 : *
4864 : * If bForce is FALSE results will only be returned if it can be done
4865 : * quickly (i.e. without scanning the image, typically by using pre-existing
4866 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
4867 : * returned efficiently, the method will return CE_Warning but no warning will
4868 : * be issued. This is a non-standard use of the CE_Warning return value
4869 : * to indicate "nothing done".
4870 : *
4871 : * If bForce is TRUE, and results are quickly available without scanning the
4872 : * image, they will be used. If bForce is TRUE and results are not quickly
4873 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
4874 : * which will scan the image.
4875 : *
4876 : * To always force recomputation of statistics, use ComputeStatistics() instead
4877 : * of this method.
4878 : *
4879 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
4880 : * will generally cache statistics in the .pam file allowing fast fetch
4881 : * after the first request.
4882 : *
4883 : * This method is the same as the C function GDALGetRasterStatistics().
4884 : *
4885 : * @param bApproxOK If TRUE statistics may be computed based on overviews
4886 : * or a subset of all tiles.
4887 : *
4888 : * @param bForce If FALSE statistics will only be returned if it can
4889 : * be done without rescanning the image. If TRUE, statistics computation will
4890 : * be forced if pre-existing values are not quickly available.
4891 : *
4892 : * @param pdfMin Location into which to load image minimum (may be NULL).
4893 : *
4894 : * @param pdfMax Location into which to load image maximum (may be NULL).-
4895 : *
4896 : * @param pdfMean Location into which to load image mean (may be NULL).
4897 : *
4898 : * @param pdfStdDev Location into which to load image standard deviation
4899 : * (may be NULL).
4900 : *
4901 : * @return CE_None on success, CE_Warning if no values returned,
4902 : * CE_Failure if an error occurs.
4903 : */
4904 :
4905 597 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
4906 : double *pdfMax, double *pdfMean,
4907 : double *pdfStdDev)
4908 :
4909 : {
4910 : /* -------------------------------------------------------------------- */
4911 : /* Do we already have metadata items for the requested values? */
4912 : /* -------------------------------------------------------------------- */
4913 1194 : if ((pdfMin == nullptr ||
4914 597 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
4915 196 : (pdfMax == nullptr ||
4916 196 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
4917 1390 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
4918 196 : (pdfStdDev == nullptr ||
4919 196 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
4920 : {
4921 196 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
4922 : {
4923 189 : if (pdfMin != nullptr)
4924 189 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
4925 189 : if (pdfMax != nullptr)
4926 189 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
4927 189 : if (pdfMean != nullptr)
4928 189 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
4929 189 : if (pdfStdDev != nullptr)
4930 189 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
4931 :
4932 189 : return CE_None;
4933 : }
4934 : }
4935 :
4936 : /* -------------------------------------------------------------------- */
4937 : /* Does the driver already know the min/max? */
4938 : /* -------------------------------------------------------------------- */
4939 408 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
4940 : {
4941 0 : int bSuccessMin = FALSE;
4942 0 : int bSuccessMax = FALSE;
4943 :
4944 0 : const double dfMin = GetMinimum(&bSuccessMin);
4945 0 : const double dfMax = GetMaximum(&bSuccessMax);
4946 :
4947 0 : if (bSuccessMin && bSuccessMax)
4948 : {
4949 0 : if (pdfMin != nullptr)
4950 0 : *pdfMin = dfMin;
4951 0 : if (pdfMax != nullptr)
4952 0 : *pdfMax = dfMax;
4953 0 : return CE_None;
4954 : }
4955 : }
4956 :
4957 : /* -------------------------------------------------------------------- */
4958 : /* Either return without results, or force computation. */
4959 : /* -------------------------------------------------------------------- */
4960 408 : if (!bForce)
4961 155 : return CE_Warning;
4962 : else
4963 253 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
4964 253 : GDALDummyProgress, nullptr);
4965 : }
4966 :
4967 : /************************************************************************/
4968 : /* GDALGetRasterStatistics() */
4969 : /************************************************************************/
4970 :
4971 : /**
4972 : * \brief Fetch image statistics.
4973 : *
4974 : * @see GDALRasterBand::GetStatistics()
4975 : */
4976 :
4977 246 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
4978 : int bForce, double *pdfMin,
4979 : double *pdfMax, double *pdfMean,
4980 : double *pdfStdDev)
4981 :
4982 : {
4983 246 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
4984 :
4985 246 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4986 246 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
4987 246 : pdfStdDev);
4988 : }
4989 :
4990 : #ifdef CPL_HAS_GINT64
4991 :
4992 : /************************************************************************/
4993 : /* GDALUInt128 */
4994 : /************************************************************************/
4995 :
4996 : #ifdef HAVE_UINT128_T
4997 : class GDALUInt128
4998 : {
4999 : __uint128_t val;
5000 :
5001 621 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5002 : {
5003 621 : }
5004 :
5005 : public:
5006 414 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5007 : {
5008 : // Evaluates to just a single mul on x86_64
5009 414 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5010 : }
5011 :
5012 207 : GDALUInt128 operator-(const GDALUInt128 &other) const
5013 : {
5014 207 : return GDALUInt128(val - other.val);
5015 : }
5016 :
5017 198 : operator double() const
5018 : {
5019 198 : return static_cast<double>(val);
5020 : }
5021 : };
5022 : #else
5023 :
5024 : #if defined(_MSC_VER) && defined(_M_X64)
5025 : #include <intrin.h>
5026 : #endif
5027 :
5028 : class GDALUInt128
5029 : {
5030 : GUIntBig low, high;
5031 :
5032 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5033 : {
5034 : }
5035 :
5036 : public:
5037 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5038 : {
5039 : #if defined(_MSC_VER) && defined(_M_X64)
5040 : GUIntBig highRes;
5041 : GUIntBig lowRes = _umul128(first, second, &highRes);
5042 : return GDALUInt128(lowRes, highRes);
5043 : #else
5044 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5045 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5046 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5047 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5048 : GUIntBig highRes = 0;
5049 : const GUIntBig firstLowSecondHigh =
5050 : static_cast<GUIntBig>(firstLow) * secondHigh;
5051 : const GUIntBig firstHighSecondLow =
5052 : static_cast<GUIntBig>(firstHigh) * secondLow;
5053 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5054 : if (middleTerm < firstLowSecondHigh) // check for overflow
5055 : highRes += static_cast<GUIntBig>(1) << 32;
5056 : const GUIntBig firstLowSecondLow =
5057 : static_cast<GUIntBig>(firstLow) * secondLow;
5058 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5059 : if (lowRes < firstLowSecondLow) // check for overflow
5060 : highRes++;
5061 : highRes +=
5062 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5063 : return GDALUInt128(lowRes, highRes);
5064 : #endif
5065 : }
5066 :
5067 : GDALUInt128 operator-(const GDALUInt128 &other) const
5068 : {
5069 : GUIntBig highRes = high - other.high;
5070 : GUIntBig lowRes = low - other.low;
5071 : if (lowRes > low) // check for underflow
5072 : --highRes;
5073 : return GDALUInt128(lowRes, highRes);
5074 : }
5075 :
5076 : operator double() const
5077 : {
5078 : const double twoPow64 = 18446744073709551616.0;
5079 : return high * twoPow64 + low;
5080 : }
5081 : };
5082 : #endif
5083 :
5084 : /************************************************************************/
5085 : /* ComputeStatisticsInternal() */
5086 : /************************************************************************/
5087 :
5088 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5089 : // not needed.
5090 : #define static_cast_for_coverity_scan static_cast
5091 :
5092 : // The rationale for below optimizations is detailed in statistics.txt
5093 :
5094 : // Use with T = GByte or GUInt16 only !
5095 : template <class T, bool COMPUTE_OTHER_STATS>
5096 : struct ComputeStatisticsInternalGeneric
5097 : {
5098 182 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5099 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5100 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5101 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5102 : {
5103 : static_assert(std::is_same<T, GByte>::value ||
5104 : std::is_same<T, GUInt16>::value,
5105 : "bad type for T");
5106 182 : if (bHasNoData)
5107 : {
5108 : // General case
5109 386 : for (int iY = 0; iY < nYCheck; iY++)
5110 : {
5111 81751 : for (int iX = 0; iX < nXCheck; iX++)
5112 : {
5113 81468 : const GPtrDiff_t iOffset =
5114 81468 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5115 81468 : const GUInt32 nValue = pData[iOffset];
5116 81468 : if (nValue == nNoDataValue)
5117 175 : continue;
5118 81293 : if (nValue < nMin)
5119 26 : nMin = nValue;
5120 81293 : if (nValue > nMax)
5121 57 : nMax = nValue;
5122 : if constexpr (COMPUTE_OTHER_STATS)
5123 : {
5124 79657 : nValidCount++;
5125 79657 : nSum += nValue;
5126 79657 : nSumSquare +=
5127 79657 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5128 79657 : nValue;
5129 : }
5130 : }
5131 : }
5132 : if constexpr (COMPUTE_OTHER_STATS)
5133 : {
5134 20 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5135 : }
5136 : }
5137 88 : else if (nMin == std::numeric_limits<T>::min() &&
5138 9 : nMax == std::numeric_limits<T>::max())
5139 : {
5140 : if constexpr (COMPUTE_OTHER_STATS)
5141 : {
5142 : // Optimization when there is no nodata and we know we have already
5143 : // reached the min and max
5144 208 : for (int iY = 0; iY < nYCheck; iY++)
5145 : {
5146 : int iX;
5147 1002 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5148 : {
5149 800 : const GPtrDiff_t iOffset =
5150 800 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5151 800 : const GUIntBig nValue = pData[iOffset];
5152 800 : const GUIntBig nValue2 = pData[iOffset + 1];
5153 800 : const GUIntBig nValue3 = pData[iOffset + 2];
5154 800 : const GUIntBig nValue4 = pData[iOffset + 3];
5155 800 : nSum += nValue;
5156 800 : nSumSquare += nValue * nValue;
5157 800 : nSum += nValue2;
5158 800 : nSumSquare += nValue2 * nValue2;
5159 800 : nSum += nValue3;
5160 800 : nSumSquare += nValue3 * nValue3;
5161 800 : nSum += nValue4;
5162 800 : nSumSquare += nValue4 * nValue4;
5163 : }
5164 207 : for (; iX < nXCheck; ++iX)
5165 : {
5166 5 : const GPtrDiff_t iOffset =
5167 5 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5168 5 : const GUIntBig nValue = pData[iOffset];
5169 5 : nSum += nValue;
5170 5 : nSumSquare += nValue * nValue;
5171 : }
5172 : }
5173 6 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5174 6 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5175 : }
5176 : }
5177 : else
5178 : {
5179 3366 : for (int iY = 0; iY < nYCheck; iY++)
5180 : {
5181 : int iX;
5182 635062 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5183 : {
5184 631769 : const GPtrDiff_t iOffset =
5185 631769 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5186 631769 : const GUInt32 nValue = pData[iOffset];
5187 631769 : const GUInt32 nValue2 = pData[iOffset + 1];
5188 631769 : if (nValue < nValue2)
5189 : {
5190 2160 : if (nValue < nMin)
5191 48 : nMin = nValue;
5192 2160 : if (nValue2 > nMax)
5193 108 : nMax = nValue2;
5194 : }
5195 : else
5196 : {
5197 629609 : if (nValue2 < nMin)
5198 61 : nMin = nValue2;
5199 629609 : if (nValue > nMax)
5200 212 : nMax = nValue;
5201 : }
5202 : if constexpr (COMPUTE_OTHER_STATS)
5203 : {
5204 624719 : nSum += nValue;
5205 624719 : nSumSquare +=
5206 624719 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5207 624719 : nValue;
5208 624719 : nSum += nValue2;
5209 624719 : nSumSquare +=
5210 624719 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5211 624719 : nValue2;
5212 : }
5213 : }
5214 3293 : if (iX < nXCheck)
5215 : {
5216 9 : const GPtrDiff_t iOffset =
5217 9 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5218 9 : const GUInt32 nValue = pData[iOffset];
5219 9 : if (nValue < nMin)
5220 6 : nMin = nValue;
5221 9 : if (nValue > nMax)
5222 6 : nMax = nValue;
5223 : if (COMPUTE_OTHER_STATS)
5224 : {
5225 9 : nSum += nValue;
5226 9 : nSumSquare +=
5227 9 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5228 9 : nValue;
5229 : }
5230 : }
5231 : }
5232 : if constexpr (COMPUTE_OTHER_STATS)
5233 : {
5234 28 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5235 28 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5236 : }
5237 : }
5238 182 : }
5239 : };
5240 :
5241 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5242 : // using 64bit accumulators in internal loops. This also slightly helps in
5243 : // 64bit mode.
5244 : template <bool COMPUTE_OTHER_STATS>
5245 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5246 : {
5247 11746 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5248 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5249 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5250 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5251 : {
5252 11746 : int nOuterLoops = nXCheck / 65536;
5253 11746 : if (nXCheck % 65536)
5254 11746 : nOuterLoops++;
5255 :
5256 11746 : if (bHasNoData)
5257 : {
5258 : // General case
5259 19544 : for (int iY = 0; iY < nYCheck; iY++)
5260 : {
5261 10936 : int iX = 0;
5262 21872 : for (int k = 0; k < nOuterLoops; k++)
5263 : {
5264 10936 : int iMax = iX + 65536;
5265 10936 : if (iMax > nXCheck)
5266 10936 : iMax = nXCheck;
5267 10936 : GUInt32 nSum32bit = 0;
5268 10936 : GUInt32 nSumSquare32bit = 0;
5269 10936 : GUInt32 nValidCount32bit = 0;
5270 10936 : GUInt32 nSampleCount32bit = 0;
5271 16705717 : for (; iX < iMax; iX++)
5272 : {
5273 16694869 : const GPtrDiff_t iOffset =
5274 16694869 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5275 16694869 : const GUInt32 nValue = pData[iOffset];
5276 :
5277 16694869 : nSampleCount32bit++;
5278 16694869 : if (nValue == nNoDataValue)
5279 16353423 : continue;
5280 341391 : if (nValue < nMin)
5281 343 : nMin = nValue;
5282 341391 : if (nValue > nMax)
5283 828 : nMax = nValue;
5284 : if constexpr (COMPUTE_OTHER_STATS)
5285 : {
5286 16946 : nValidCount32bit++;
5287 16946 : nSum32bit += nValue;
5288 16946 : nSumSquare32bit += nValue * nValue;
5289 : }
5290 : }
5291 : if constexpr (COMPUTE_OTHER_STATS)
5292 : {
5293 648 : nSampleCount += nSampleCount32bit;
5294 648 : nValidCount += nValidCount32bit;
5295 648 : nSum += nSum32bit;
5296 648 : nSumSquare += nSumSquare32bit;
5297 : }
5298 : }
5299 : }
5300 : }
5301 3138 : else if (nMin == 0 && nMax == 255)
5302 : {
5303 : if constexpr (COMPUTE_OTHER_STATS)
5304 : {
5305 : // Optimization when there is no nodata and we know we have already
5306 : // reached the min and max
5307 2644 : for (int iY = 0; iY < nYCheck; iY++)
5308 : {
5309 2617 : int iX = 0;
5310 5234 : for (int k = 0; k < nOuterLoops; k++)
5311 : {
5312 2617 : int iMax = iX + 65536;
5313 2617 : if (iMax > nXCheck)
5314 2617 : iMax = nXCheck;
5315 2617 : GUInt32 nSum32bit = 0;
5316 2617 : GUInt32 nSumSquare32bit = 0;
5317 176297 : for (; iX + 3 < iMax; iX += 4)
5318 : {
5319 173680 : const GPtrDiff_t iOffset =
5320 173680 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5321 173680 : const GUInt32 nValue = pData[iOffset];
5322 173680 : const GUInt32 nValue2 = pData[iOffset + 1];
5323 173680 : const GUInt32 nValue3 = pData[iOffset + 2];
5324 173680 : const GUInt32 nValue4 = pData[iOffset + 3];
5325 173680 : nSum32bit += nValue;
5326 173680 : nSumSquare32bit += nValue * nValue;
5327 173680 : nSum32bit += nValue2;
5328 173680 : nSumSquare32bit += nValue2 * nValue2;
5329 173680 : nSum32bit += nValue3;
5330 173680 : nSumSquare32bit += nValue3 * nValue3;
5331 173680 : nSum32bit += nValue4;
5332 173680 : nSumSquare32bit += nValue4 * nValue4;
5333 : }
5334 2617 : nSum += nSum32bit;
5335 2617 : nSumSquare += nSumSquare32bit;
5336 : }
5337 2620 : for (; iX < nXCheck; ++iX)
5338 : {
5339 3 : const GPtrDiff_t iOffset =
5340 3 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5341 3 : const GUIntBig nValue = pData[iOffset];
5342 3 : nSum += nValue;
5343 3 : nSumSquare += nValue * nValue;
5344 : }
5345 : }
5346 27 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5347 27 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5348 27 : }
5349 : }
5350 : else
5351 : {
5352 7877 : for (int iY = 0; iY < nYCheck; iY++)
5353 : {
5354 4766 : int iX = 0;
5355 9531 : for (int k = 0; k < nOuterLoops; k++)
5356 : {
5357 4765 : int iMax = iX + 65536;
5358 4765 : if (iMax > nXCheck)
5359 4763 : iMax = nXCheck;
5360 4765 : GUInt32 nSum32bit = 0;
5361 4765 : GUInt32 nSumSquare32bit = 0;
5362 161526 : for (; iX + 1 < iMax; iX += 2)
5363 : {
5364 156761 : const GPtrDiff_t iOffset =
5365 156761 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5366 156761 : const GUInt32 nValue = pData[iOffset];
5367 156761 : const GUInt32 nValue2 = pData[iOffset + 1];
5368 156761 : if (nValue < nValue2)
5369 : {
5370 8915 : if (nValue < nMin)
5371 250 : nMin = nValue;
5372 8915 : if (nValue2 > nMax)
5373 237 : nMax = nValue2;
5374 : }
5375 : else
5376 : {
5377 147846 : if (nValue2 < nMin)
5378 298 : nMin = nValue2;
5379 147846 : if (nValue > nMax)
5380 850 : nMax = nValue;
5381 : }
5382 : if constexpr (COMPUTE_OTHER_STATS)
5383 : {
5384 132349 : nSum32bit += nValue;
5385 132349 : nSumSquare32bit += nValue * nValue;
5386 132349 : nSum32bit += nValue2;
5387 132349 : nSumSquare32bit += nValue2 * nValue2;
5388 : }
5389 : }
5390 : if constexpr (COMPUTE_OTHER_STATS)
5391 : {
5392 1600 : nSum += nSum32bit;
5393 1600 : nSumSquare += nSumSquare32bit;
5394 : }
5395 : }
5396 4766 : if (iX < nXCheck)
5397 : {
5398 1383 : const GPtrDiff_t iOffset =
5399 1383 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5400 1383 : const GUInt32 nValue = pData[iOffset];
5401 1383 : if (nValue < nMin)
5402 38 : nMin = nValue;
5403 1383 : if (nValue > nMax)
5404 48 : nMax = nValue;
5405 : if constexpr (COMPUTE_OTHER_STATS)
5406 : {
5407 312 : nSum += nValue;
5408 312 : nSumSquare +=
5409 312 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5410 312 : nValue;
5411 : }
5412 : }
5413 : }
5414 : if constexpr (COMPUTE_OTHER_STATS)
5415 : {
5416 901 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5417 901 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5418 : }
5419 : }
5420 11746 : }
5421 : };
5422 :
5423 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5424 : {
5425 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5426 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5427 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5428 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5429 : {
5430 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5431 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5432 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5433 : }
5434 : };
5435 :
5436 : #if (defined(__x86_64__) || defined(_M_X64)) && \
5437 : (defined(__GNUC__) || defined(_MSC_VER))
5438 :
5439 : #include "gdal_avx2_emulation.hpp"
5440 :
5441 : #define ZERO256 GDALmm256_setzero_si256()
5442 :
5443 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5444 : static void
5445 19004 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5446 : // assumed to be aligned on 256 bits
5447 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5448 : GUIntBig &nSum, GUIntBig &nSumSquare,
5449 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5450 : {
5451 : // 32-byte alignment may not be enforced by linker, so do it at hand
5452 : GByte
5453 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5454 19004 : GByte *paby32ByteAligned =
5455 : aby32ByteUnaligned +
5456 19004 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5457 19004 : GByte *pabyMin = paby32ByteAligned;
5458 19004 : GByte *pabyMax = paby32ByteAligned + 32;
5459 19004 : GUInt32 *panSum =
5460 : COMPUTE_OTHER_STATS
5461 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5462 : : nullptr;
5463 19004 : GUInt32 *panSumSquare =
5464 : COMPUTE_OTHER_STATS
5465 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5466 : : nullptr;
5467 :
5468 19004 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5469 :
5470 19004 : GPtrDiff_t i = 0;
5471 : // Make sure that sumSquare can fit on uint32
5472 : // * 8 since we can hold 8 sums per vector register
5473 19004 : const int nMaxIterationsPerInnerLoop =
5474 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5475 19004 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5476 19004 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5477 19004 : nOuterLoops++;
5478 :
5479 : GDALm256i ymm_min =
5480 19004 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5481 19004 : GDALm256i ymm_max = ymm_min;
5482 19004 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5483 :
5484 38008 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5485 : {
5486 19004 : const auto iMax =
5487 19004 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5488 :
5489 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5490 19004 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5491 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5492 19004 : ZERO256; // holds 8 uint32 sums
5493 635923 : for (; i + 31 < iMax; i += 32)
5494 : {
5495 616919 : const GDALm256i ymm = GDALmm256_load_si256(
5496 616919 : reinterpret_cast<const GDALm256i *>(pData + i));
5497 : if (COMPUTE_MIN)
5498 : {
5499 159529 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5500 : }
5501 : if (COMPUTE_MAX)
5502 : {
5503 526037 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5504 : }
5505 :
5506 : if constexpr (COMPUTE_OTHER_STATS)
5507 : {
5508 : // Extract even-8bit values
5509 : const GDALm256i ymm_even =
5510 493495 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5511 : // Compute square of those 16 values as 32 bit result
5512 : // and add adjacent pairs
5513 : const GDALm256i ymm_even_square =
5514 493495 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5515 : // Add to the sumsquare accumulator
5516 : ymm_sumsquare =
5517 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5518 :
5519 : // Extract odd-8bit values
5520 493495 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5521 : const GDALm256i ymm_odd_square =
5522 493495 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5523 : ymm_sumsquare =
5524 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5525 :
5526 : // Now compute the sums
5527 493495 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5528 : GDALmm256_sad_epu8(ymm, ZERO256));
5529 : }
5530 : }
5531 :
5532 : if constexpr (COMPUTE_OTHER_STATS)
5533 : {
5534 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5535 : ymm_sum);
5536 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5537 : ymm_sumsquare);
5538 :
5539 10649 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5540 10649 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5541 10649 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5542 10649 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5543 : panSumSquare[7];
5544 : }
5545 : }
5546 :
5547 : if constexpr (COMPUTE_MIN)
5548 : {
5549 6035 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5550 : }
5551 : if constexpr (COMPUTE_MAX)
5552 : {
5553 15008 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5554 : }
5555 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5556 : {
5557 512721 : for (int j = 0; j < 32; j++)
5558 : {
5559 : if constexpr (COMPUTE_MIN)
5560 : {
5561 193120 : if (pabyMin[j] < nMin)
5562 1259 : nMin = pabyMin[j];
5563 : }
5564 : if constexpr (COMPUTE_MAX)
5565 : {
5566 480256 : if (pabyMax[j] > nMax)
5567 1801 : nMax = pabyMax[j];
5568 : }
5569 : }
5570 : }
5571 :
5572 211554 : for (; i < nBlockPixels; i++)
5573 : {
5574 192550 : const GUInt32 nValue = pData[i];
5575 : if constexpr (COMPUTE_MIN)
5576 : {
5577 66110 : if (nValue < nMin)
5578 1 : nMin = nValue;
5579 : }
5580 : if constexpr (COMPUTE_MAX)
5581 : {
5582 189787 : if (nValue > nMax)
5583 1167 : nMax = nValue;
5584 : }
5585 : if constexpr (COMPUTE_OTHER_STATS)
5586 : {
5587 77195 : nSum += nValue;
5588 77195 : nSumSquare +=
5589 77195 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5590 : }
5591 : }
5592 :
5593 : if constexpr (COMPUTE_OTHER_STATS)
5594 : {
5595 10649 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5596 10649 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5597 : }
5598 19004 : }
5599 :
5600 : // SSE2/AVX2 optimization for GByte case
5601 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5602 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5603 : // there are strictly equivalent to 2 parallel SSE2 streams.
5604 : template <bool COMPUTE_OTHER_STATS>
5605 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5606 : {
5607 28060 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5608 : // assumed to be aligned on 256 bits
5609 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5610 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5611 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5612 : GUIntBig &nValidCount)
5613 : {
5614 28060 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5615 28060 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5616 9352 : nMin <= nMax)
5617 : {
5618 : // 32-byte alignment may not be enforced by linker, so do it at hand
5619 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5620 1240 : GByte *paby32ByteAligned =
5621 : aby32ByteUnaligned +
5622 1240 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5623 1240 : GByte *pabyMin = paby32ByteAligned;
5624 1240 : GByte *pabyMax = paby32ByteAligned + 32;
5625 1240 : GUInt32 *panSum =
5626 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5627 1240 : GUInt32 *panSumSquare =
5628 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5629 :
5630 1240 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5631 :
5632 1240 : GPtrDiff_t i = 0;
5633 : // Make sure that sumSquare can fit on uint32
5634 : // * 8 since we can hold 8 sums per vector register
5635 1240 : const int nMaxIterationsPerInnerLoop =
5636 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5637 1240 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5638 1240 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5639 1240 : nOuterLoops++;
5640 :
5641 : const GDALm256i ymm_nodata =
5642 1240 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5643 : // any non noData value in [min,max] would do.
5644 : const GDALm256i ymm_neutral =
5645 1240 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5646 1240 : GDALm256i ymm_min = ymm_neutral;
5647 1240 : GDALm256i ymm_max = ymm_neutral;
5648 : [[maybe_unused]] const auto ymm_mask_8bits =
5649 1240 : GDALmm256_set1_epi16(0xFF);
5650 :
5651 1240 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5652 1240 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5653 1240 : const bool bComputeMinMax =
5654 1240 : nMin > nMinThreshold || nMax < nMaxThreshold;
5655 :
5656 2480 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5657 : {
5658 1240 : const auto iMax =
5659 1240 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5660 :
5661 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5662 1240 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5663 : // holds 8 uint32 sums
5664 1240 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5665 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5666 1240 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5667 1240 : const auto iInit = i;
5668 13799 : for (; i + 31 < iMax; i += 32)
5669 : {
5670 12559 : const GDALm256i ymm = GDALmm256_load_si256(
5671 12559 : reinterpret_cast<const GDALm256i *>(pData + i));
5672 :
5673 : // Check which values are nodata
5674 : const GDALm256i ymm_eq_nodata =
5675 12559 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5676 : if constexpr (COMPUTE_OTHER_STATS)
5677 : {
5678 : // Count how many values are nodata (due to cmpeq
5679 : // putting 255 when condition is met, this will actually
5680 : // be 255 times the number of nodata value, spread in 4
5681 : // 64 bits words). We can use add_epi32 as the counter
5682 : // will not overflow uint32
5683 4514 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5684 : ymm_count_nodata_mul_255,
5685 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5686 : }
5687 : // Replace all nodata values by zero for the purpose of sum
5688 : // and sumquare.
5689 : const GDALm256i ymm_nodata_by_zero =
5690 12559 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5691 12559 : if (bComputeMinMax)
5692 : {
5693 : // Replace all nodata values by a neutral value for the
5694 : // purpose of min and max.
5695 : const GDALm256i ymm_nodata_by_neutral =
5696 8174 : GDALmm256_or_si256(
5697 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5698 : ymm_nodata_by_zero);
5699 :
5700 : ymm_min =
5701 8174 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5702 : ymm_max =
5703 8174 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
5704 : }
5705 :
5706 : if constexpr (COMPUTE_OTHER_STATS)
5707 : {
5708 : // Extract even-8bit values
5709 4514 : const GDALm256i ymm_even = GDALmm256_and_si256(
5710 : ymm_nodata_by_zero, ymm_mask_8bits);
5711 : // Compute square of those 16 values as 32 bit result
5712 : // and add adjacent pairs
5713 : const GDALm256i ymm_even_square =
5714 4514 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5715 : // Add to the sumsquare accumulator
5716 : ymm_sumsquare =
5717 4514 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5718 :
5719 : // Extract odd-8bit values
5720 : const GDALm256i ymm_odd =
5721 4514 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
5722 : const GDALm256i ymm_odd_square =
5723 4514 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5724 : ymm_sumsquare =
5725 4514 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5726 :
5727 : // Now compute the sums
5728 4514 : ymm_sum = GDALmm256_add_epi32(
5729 : ymm_sum,
5730 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
5731 : }
5732 : }
5733 :
5734 : if constexpr (COMPUTE_OTHER_STATS)
5735 : {
5736 33 : GUInt32 *panCoutNoDataMul255 = panSum;
5737 33 : GDALmm256_store_si256(
5738 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
5739 : ymm_count_nodata_mul_255);
5740 :
5741 33 : nSampleCount += (i - iInit);
5742 :
5743 33 : nValidCount +=
5744 33 : (i - iInit) -
5745 33 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
5746 33 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
5747 : 255;
5748 :
5749 33 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5750 : ymm_sum);
5751 33 : GDALmm256_store_si256(
5752 : reinterpret_cast<GDALm256i *>(panSumSquare),
5753 : ymm_sumsquare);
5754 33 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5755 33 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5756 33 : panSumSquare[1] + panSumSquare[2] +
5757 33 : panSumSquare[3] + panSumSquare[4] +
5758 33 : panSumSquare[5] + panSumSquare[6] +
5759 : panSumSquare[7];
5760 : }
5761 : }
5762 :
5763 1240 : if (bComputeMinMax)
5764 : {
5765 1209 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
5766 : ymm_min);
5767 1209 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
5768 : ymm_max);
5769 39897 : for (int j = 0; j < 32; j++)
5770 : {
5771 38688 : if (pabyMin[j] < nMin)
5772 32 : nMin = pabyMin[j];
5773 38688 : if (pabyMax[j] > nMax)
5774 157 : nMax = pabyMax[j];
5775 : }
5776 : }
5777 :
5778 : if constexpr (COMPUTE_OTHER_STATS)
5779 : {
5780 33 : nSampleCount += nBlockPixels - i;
5781 : }
5782 29810 : for (; i < nBlockPixels; i++)
5783 : {
5784 28570 : const GUInt32 nValue = pData[i];
5785 28570 : if (nValue == nNoDataValue)
5786 24923 : continue;
5787 3647 : if (nValue < nMin)
5788 1 : nMin = nValue;
5789 3647 : if (nValue > nMax)
5790 13 : nMax = nValue;
5791 : if constexpr (COMPUTE_OTHER_STATS)
5792 : {
5793 110 : nValidCount++;
5794 110 : nSum += nValue;
5795 110 : nSumSquare +=
5796 110 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5797 110 : nValue;
5798 : }
5799 1240 : }
5800 : }
5801 26820 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
5802 : {
5803 15048 : if (nMin > 0)
5804 : {
5805 2079 : if (nMax < 255)
5806 : {
5807 : ComputeStatisticsByteNoNodata<true, true,
5808 1550 : COMPUTE_OTHER_STATS>(
5809 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5810 : nSampleCount, nValidCount);
5811 : }
5812 : else
5813 : {
5814 : ComputeStatisticsByteNoNodata<true, false,
5815 529 : COMPUTE_OTHER_STATS>(
5816 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5817 : nSampleCount, nValidCount);
5818 : }
5819 : }
5820 : else
5821 : {
5822 12969 : if (nMax < 255)
5823 : {
5824 : ComputeStatisticsByteNoNodata<false, true,
5825 9502 : COMPUTE_OTHER_STATS>(
5826 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5827 : nSampleCount, nValidCount);
5828 : }
5829 : else
5830 : {
5831 : ComputeStatisticsByteNoNodata<false, false,
5832 3467 : COMPUTE_OTHER_STATS>(
5833 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5834 : nSampleCount, nValidCount);
5835 : }
5836 : }
5837 : }
5838 10531 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
5839 27 : (nBlockXSize % 32) == 0)
5840 : {
5841 3983 : for (int iY = 0; iY < nYCheck; iY++)
5842 : {
5843 3956 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
5844 3956 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
5845 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5846 27 : }
5847 : }
5848 : else
5849 : {
5850 11745 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
5851 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5852 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5853 : }
5854 28061 : }
5855 : };
5856 :
5857 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
5858 403 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
5859 : GUIntBig i)
5860 : {
5861 403 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
5862 403 : }
5863 :
5864 : // AVX2/SSE2 optimization for GUInt16 case
5865 : template <bool COMPUTE_OTHER_STATS>
5866 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
5867 : {
5868 1347 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5869 : // assumed to be aligned on 128 bits
5870 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
5871 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5872 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5873 : GUIntBig &nValidCount)
5874 : {
5875 1347 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5876 1347 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
5877 : {
5878 1165 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
5879 :
5880 1165 : GPtrDiff_t i = 0;
5881 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
5882 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
5883 : // Furthermore the shift is also needed to use madd_epi16
5884 1165 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
5885 1165 : GDALm256i ymm_min = GDALmm256_load_si256(
5886 1165 : reinterpret_cast<const GDALm256i *>(pData + i));
5887 1165 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
5888 1165 : GDALm256i ymm_max = ymm_min;
5889 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5890 1165 : ZERO256; // holds 4 uint64 sums
5891 :
5892 : // Make sure that sum can fit on uint32
5893 : // * 8 since we can hold 8 sums per vector register
5894 1165 : const int nMaxIterationsPerInnerLoop =
5895 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
5896 1165 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5897 1165 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5898 1165 : nOuterLoops++;
5899 :
5900 1165 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
5901 : [[maybe_unused]] const auto ymm_mask_16bits =
5902 1165 : GDALmm256_set1_epi32(0xFFFF);
5903 : [[maybe_unused]] const auto ymm_mask_32bits =
5904 1165 : GDALmm256_set1_epi64x(0xFFFFFFFF);
5905 :
5906 1165 : GUIntBig nSumThis = 0;
5907 2354 : for (int k = 0; k < nOuterLoops; k++)
5908 : {
5909 1189 : const auto iMax =
5910 1189 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5911 :
5912 : [[maybe_unused]] GDALm256i ymm_sum =
5913 1189 : ZERO256; // holds 8 uint32 sums
5914 959265 : for (; i + 15 < iMax; i += 16)
5915 : {
5916 958076 : const GDALm256i ymm = GDALmm256_load_si256(
5917 958076 : reinterpret_cast<const GDALm256i *>(pData + i));
5918 : const GDALm256i ymm_shifted =
5919 958076 : GDALmm256_add_epi16(ymm, ymm_m32768);
5920 958076 : if (bComputeMinMax)
5921 : {
5922 949057 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
5923 949057 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
5924 : }
5925 :
5926 : if constexpr (COMPUTE_OTHER_STATS)
5927 : {
5928 : // Note: the int32 range can overflow for (0-32768)^2 +
5929 : // (0-32768)^2 = 0x80000000, but as we know the result
5930 : // is positive, this is OK as we interpret is a uint32.
5931 : const GDALm256i ymm_square =
5932 99250 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
5933 99250 : ymm_sumsquare = GDALmm256_add_epi64(
5934 : ymm_sumsquare,
5935 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
5936 99250 : ymm_sumsquare = GDALmm256_add_epi64(
5937 : ymm_sumsquare,
5938 : GDALmm256_srli_epi64(ymm_square, 32));
5939 :
5940 : // Now compute the sums
5941 99250 : ymm_sum = GDALmm256_add_epi32(
5942 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
5943 99250 : ymm_sum = GDALmm256_add_epi32(
5944 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
5945 : }
5946 : }
5947 :
5948 : if constexpr (COMPUTE_OTHER_STATS)
5949 : {
5950 : GUInt32 anSum[8];
5951 403 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
5952 : ymm_sum);
5953 403 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
5954 403 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
5955 403 : anSum[6] + anSum[7];
5956 : }
5957 : }
5958 :
5959 1165 : if (bComputeMinMax)
5960 : {
5961 : GUInt16 anMin[16];
5962 : GUInt16 anMax[16];
5963 :
5964 : // Unshift the result
5965 1124 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
5966 1124 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
5967 1124 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
5968 : ymm_min);
5969 1124 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
5970 : ymm_max);
5971 19108 : for (int j = 0; j < 16; j++)
5972 : {
5973 17984 : if (anMin[j] < nMin)
5974 342 : nMin = anMin[j];
5975 17984 : if (anMax[j] > nMax)
5976 481 : nMax = anMax[j];
5977 : }
5978 : }
5979 :
5980 : if constexpr (COMPUTE_OTHER_STATS)
5981 : {
5982 : GUIntBig anSumSquare[4];
5983 403 : GDALmm256_storeu_si256(
5984 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
5985 403 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
5986 : anSumSquare[3];
5987 :
5988 : // Unshift the sum of squares
5989 403 : UnshiftSumSquare(nSumSquare, nSumThis,
5990 : static_cast<GUIntBig>(i));
5991 :
5992 403 : nSum += nSumThis;
5993 :
5994 725 : for (; i < nBlockPixels; i++)
5995 : {
5996 322 : const GUInt32 nValue = pData[i];
5997 322 : if (nValue < nMin)
5998 1 : nMin = nValue;
5999 322 : if (nValue > nMax)
6000 1 : nMax = nValue;
6001 322 : nSum += nValue;
6002 322 : nSumSquare +=
6003 322 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6004 322 : nValue;
6005 : }
6006 :
6007 403 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6008 403 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6009 1165 : }
6010 : }
6011 : else
6012 : {
6013 182 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6014 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6015 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6016 : }
6017 1347 : }
6018 : };
6019 :
6020 : #endif
6021 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6022 : // defined(_MSC_VER))
6023 :
6024 : #endif // CPL_HAS_GINT64
6025 :
6026 : /************************************************************************/
6027 : /* GetPixelValue() */
6028 : /************************************************************************/
6029 :
6030 23163800 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6031 : const void *pData, GPtrDiff_t iOffset,
6032 : bool bGotNoDataValue, double dfNoDataValue,
6033 : bool bGotFloatNoDataValue,
6034 : float fNoDataValue, bool &bValid)
6035 : {
6036 23163800 : bValid = true;
6037 23163800 : double dfValue = 0;
6038 23163800 : switch (eDataType)
6039 : {
6040 1413680 : case GDT_Byte:
6041 : {
6042 1413680 : if (bSignedByte)
6043 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6044 : else
6045 1413490 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6046 1413680 : break;
6047 : }
6048 10405 : case GDT_Int8:
6049 10405 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6050 10405 : break;
6051 4000 : case GDT_UInt16:
6052 4000 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6053 4000 : break;
6054 60192 : case GDT_Int16:
6055 60192 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6056 60192 : break;
6057 27596 : case GDT_UInt32:
6058 27596 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6059 27596 : break;
6060 460162 : case GDT_Int32:
6061 460162 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6062 460162 : break;
6063 2598 : case GDT_UInt64:
6064 2598 : dfValue = static_cast<double>(
6065 2598 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6066 2598 : break;
6067 7398 : case GDT_Int64:
6068 7398 : dfValue = static_cast<double>(
6069 7398 : static_cast<const std::int64_t *>(pData)[iOffset]);
6070 7398 : break;
6071 17483000 : case GDT_Float32:
6072 : {
6073 17483000 : const float fValue = static_cast<const float *>(pData)[iOffset];
6074 30693000 : if (std::isnan(fValue) ||
6075 13210000 : (bGotFloatNoDataValue && ARE_REAL_EQUAL(fValue, fNoDataValue)))
6076 : {
6077 119863 : bValid = false;
6078 119863 : return 0.0;
6079 : }
6080 17363100 : dfValue = fValue;
6081 17363100 : return dfValue;
6082 : }
6083 3677660 : case GDT_Float64:
6084 3677660 : dfValue = static_cast<const double *>(pData)[iOffset];
6085 3677660 : if (std::isnan(dfValue))
6086 : {
6087 52 : bValid = false;
6088 52 : return 0.0;
6089 : }
6090 3677600 : break;
6091 2692 : case GDT_CInt16:
6092 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6093 2692 : break;
6094 2692 : case GDT_CInt32:
6095 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6096 2692 : break;
6097 5812 : case GDT_CFloat32:
6098 5812 : dfValue = static_cast<const float *>(pData)[iOffset * 2];
6099 5812 : if (std::isnan(dfValue))
6100 : {
6101 0 : bValid = false;
6102 0 : return 0.0;
6103 : }
6104 5812 : break;
6105 5892 : case GDT_CFloat64:
6106 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6107 5892 : if (std::isnan(dfValue))
6108 : {
6109 0 : bValid = false;
6110 0 : return 0.0;
6111 : }
6112 5892 : break;
6113 0 : case GDT_Unknown:
6114 : case GDT_TypeCount:
6115 0 : CPLAssert(false);
6116 : break;
6117 : }
6118 :
6119 5680730 : if (bGotNoDataValue && ARE_REAL_EQUAL(dfValue, dfNoDataValue))
6120 : {
6121 3346220 : bValid = false;
6122 3346220 : return 0.0;
6123 : }
6124 2334500 : return dfValue;
6125 : }
6126 :
6127 : /************************************************************************/
6128 : /* SetValidPercent() */
6129 : /************************************************************************/
6130 :
6131 : //! @cond Doxygen_Suppress
6132 : /**
6133 : * \brief Set percentage of valid (not nodata) pixels.
6134 : *
6135 : * Stores the percentage of valid pixels in the metadata item
6136 : * STATISTICS_VALID_PERCENT
6137 : *
6138 : * @param nSampleCount Number of sampled pixels.
6139 : *
6140 : * @param nValidCount Number of valid pixels.
6141 : */
6142 :
6143 465 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6144 : GUIntBig nValidCount)
6145 : {
6146 465 : if (nValidCount == 0)
6147 : {
6148 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6149 : }
6150 453 : else if (nValidCount == nSampleCount)
6151 : {
6152 410 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6153 : }
6154 : else /* nValidCount < nSampleCount */
6155 : {
6156 43 : char szValue[128] = {0};
6157 :
6158 : /* percentage is only an indicator: limit precision */
6159 43 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6160 43 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6161 :
6162 43 : if (EQUAL(szValue, "100"))
6163 : {
6164 : /* don't set 100 percent valid
6165 : * because some of the sampled pixels were nodata */
6166 0 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6167 : }
6168 : else
6169 : {
6170 43 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6171 : }
6172 : }
6173 464 : }
6174 :
6175 : //! @endcond
6176 :
6177 : /************************************************************************/
6178 : /* ComputeStatistics() */
6179 : /************************************************************************/
6180 :
6181 : /**
6182 : * \brief Compute image statistics.
6183 : *
6184 : * Returns the minimum, maximum, mean and standard deviation of all
6185 : * pixel values in this band. If approximate statistics are sufficient,
6186 : * the bApproxOK flag can be set to true in which case overviews, or a
6187 : * subset of image tiles may be used in computing the statistics.
6188 : *
6189 : * Once computed, the statistics will generally be "set" back on the
6190 : * raster band using SetStatistics().
6191 : *
6192 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6193 : *
6194 : * This method is the same as the C function GDALComputeRasterStatistics().
6195 : *
6196 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6197 : * or a subset of all tiles.
6198 : *
6199 : * @param pdfMin Location into which to load image minimum (may be NULL).
6200 : *
6201 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6202 : *
6203 : * @param pdfMean Location into which to load image mean (may be NULL).
6204 : *
6205 : * @param pdfStdDev Location into which to load image standard deviation
6206 : * (may be NULL).
6207 : *
6208 : * @param pfnProgress a function to call to report progress, or NULL.
6209 : *
6210 : * @param pProgressData application data to pass to the progress function.
6211 : *
6212 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6213 : * is terminated by the user.
6214 : */
6215 :
6216 448 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6217 : double *pdfMax, double *pdfMean,
6218 : double *pdfStdDev,
6219 : GDALProgressFunc pfnProgress,
6220 : void *pProgressData)
6221 :
6222 : {
6223 448 : if (pfnProgress == nullptr)
6224 154 : pfnProgress = GDALDummyProgress;
6225 :
6226 : /* -------------------------------------------------------------------- */
6227 : /* If we have overview bands, use them for statistics. */
6228 : /* -------------------------------------------------------------------- */
6229 448 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6230 : {
6231 : GDALRasterBand *poBand =
6232 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6233 :
6234 3 : if (poBand != this)
6235 : {
6236 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6237 : pdfMean, pdfStdDev,
6238 3 : pfnProgress, pProgressData);
6239 3 : if (eErr == CE_None)
6240 : {
6241 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6242 : {
6243 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6244 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6245 : }
6246 :
6247 : /* transfer metadata from overview band to this */
6248 : const char *pszPercentValid =
6249 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6250 :
6251 3 : if (pszPercentValid != nullptr)
6252 : {
6253 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6254 3 : pszPercentValid);
6255 : }
6256 : }
6257 3 : return eErr;
6258 : }
6259 : }
6260 :
6261 445 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6262 : {
6263 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6264 0 : return CE_Failure;
6265 : }
6266 :
6267 : /* -------------------------------------------------------------------- */
6268 : /* Read actual data and compute statistics. */
6269 : /* -------------------------------------------------------------------- */
6270 : // Using Welford algorithm:
6271 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6272 : // to compute standard deviation in a more numerically robust way than
6273 : // the difference of the sum of square values with the square of the sum.
6274 : // dfMean and dfM2 are updated at each sample.
6275 : // dfM2 is the sum of square of differences to the current mean.
6276 445 : double dfMin = std::numeric_limits<double>::max();
6277 445 : double dfMax = -std::numeric_limits<double>::max();
6278 445 : double dfMean = 0.0;
6279 445 : double dfM2 = 0.0;
6280 :
6281 : GDALRasterIOExtraArg sExtraArg;
6282 445 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6283 :
6284 445 : int bGotNoDataValue = FALSE;
6285 445 : const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
6286 445 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
6287 445 : bool bGotFloatNoDataValue = false;
6288 445 : float fNoDataValue = 0.0f;
6289 445 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
6290 : fNoDataValue, bGotFloatNoDataValue);
6291 :
6292 445 : GDALRasterBand *poMaskBand = nullptr;
6293 445 : if (!bGotNoDataValue)
6294 : {
6295 420 : const int l_nMaskFlags = GetMaskFlags();
6296 436 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
6297 16 : GetColorInterpretation() != GCI_AlphaBand)
6298 : {
6299 16 : poMaskBand = GetMaskBand();
6300 : }
6301 : }
6302 :
6303 445 : bool bSignedByte = false;
6304 445 : if (eDataType == GDT_Byte)
6305 : {
6306 194 : EnablePixelTypeSignedByteWarning(false);
6307 : const char *pszPixelType =
6308 194 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6309 194 : EnablePixelTypeSignedByteWarning(true);
6310 194 : bSignedByte =
6311 194 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6312 : }
6313 :
6314 445 : GUIntBig nSampleCount = 0;
6315 445 : GUIntBig nValidCount = 0;
6316 :
6317 445 : if (bApproxOK && HasArbitraryOverviews())
6318 : {
6319 : /* --------------------------------------------------------------------
6320 : */
6321 : /* Figure out how much the image should be reduced to get an */
6322 : /* approximate value. */
6323 : /* --------------------------------------------------------------------
6324 : */
6325 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6326 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6327 :
6328 0 : int nXReduced = nRasterXSize;
6329 0 : int nYReduced = nRasterYSize;
6330 0 : if (dfReduction > 1.0)
6331 : {
6332 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6333 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6334 :
6335 : // Catch the case of huge resizing ratios here
6336 0 : if (nXReduced == 0)
6337 0 : nXReduced = 1;
6338 0 : if (nYReduced == 0)
6339 0 : nYReduced = 1;
6340 : }
6341 :
6342 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
6343 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6344 :
6345 : const CPLErr eErr =
6346 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6347 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6348 0 : if (eErr != CE_None)
6349 : {
6350 0 : CPLFree(pData);
6351 0 : return eErr;
6352 : }
6353 :
6354 0 : GByte *pabyMaskData = nullptr;
6355 0 : if (poMaskBand)
6356 : {
6357 : pabyMaskData =
6358 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6359 0 : if (!pabyMaskData)
6360 : {
6361 0 : CPLFree(pData);
6362 0 : return CE_Failure;
6363 : }
6364 :
6365 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6366 : pabyMaskData, nXReduced, nYReduced,
6367 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
6368 : {
6369 0 : CPLFree(pData);
6370 0 : CPLFree(pabyMaskData);
6371 0 : return CE_Failure;
6372 : }
6373 : }
6374 :
6375 : /* this isn't the fastest way to do this, but is easier for now */
6376 0 : for (int iY = 0; iY < nYReduced; iY++)
6377 : {
6378 0 : for (int iX = 0; iX < nXReduced; iX++)
6379 : {
6380 0 : const int iOffset = iX + iY * nXReduced;
6381 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6382 0 : continue;
6383 :
6384 0 : bool bValid = true;
6385 : double dfValue =
6386 0 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6387 0 : CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
6388 0 : bGotFloatNoDataValue, fNoDataValue, bValid);
6389 0 : if (!bValid)
6390 0 : continue;
6391 :
6392 0 : dfMin = std::min(dfMin, dfValue);
6393 0 : dfMax = std::max(dfMax, dfValue);
6394 :
6395 0 : nValidCount++;
6396 0 : const double dfDelta = dfValue - dfMean;
6397 0 : dfMean += dfDelta / nValidCount;
6398 0 : dfM2 += dfDelta * (dfValue - dfMean);
6399 : }
6400 : }
6401 :
6402 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6403 :
6404 0 : CPLFree(pData);
6405 0 : CPLFree(pabyMaskData);
6406 : }
6407 :
6408 : else // No arbitrary overviews.
6409 : {
6410 445 : if (!InitBlockInfo())
6411 0 : return CE_Failure;
6412 :
6413 : /* --------------------------------------------------------------------
6414 : */
6415 : /* Figure out the ratio of blocks we will read to get an */
6416 : /* approximate value. */
6417 : /* --------------------------------------------------------------------
6418 : */
6419 444 : int nSampleRate = 1;
6420 444 : if (bApproxOK)
6421 : {
6422 40 : nSampleRate = static_cast<int>(std::max(
6423 80 : 1.0,
6424 40 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6425 : // We want to avoid probing only the first column of blocks for
6426 : // a square shaped raster, because it is not unlikely that it may
6427 : // be padding only (#6378)
6428 40 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6429 2 : nSampleRate += 1;
6430 : }
6431 444 : if (nSampleRate == 1)
6432 412 : bApproxOK = false;
6433 :
6434 : #ifdef CPL_HAS_GINT64
6435 : // Particular case for GDT_Byte that only use integral types for all
6436 : // intermediate computations. Only possible if the number of pixels
6437 : // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6438 : // can fit on a uint64. Should be 99.99999% of cases.
6439 : // For GUInt16, this limits to raster of 4 giga pixels
6440 444 : if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6441 178 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6442 178 : nSampleRate <
6443 178 : GUINTBIG_MAX / (255U * 255U) /
6444 178 : (static_cast<GUInt64>(nBlockXSize) *
6445 178 : static_cast<GUInt64>(nBlockYSize))) ||
6446 266 : (eDataType == GDT_UInt16 &&
6447 28 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6448 28 : nSampleRate <
6449 28 : GUINTBIG_MAX / (65535U * 65535U) /
6450 28 : (static_cast<GUInt64>(nBlockXSize) *
6451 28 : static_cast<GUInt64>(nBlockYSize))))
6452 : {
6453 206 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6454 206 : GUInt32 nMin = nMaxValueType;
6455 206 : GUInt32 nMax = 0;
6456 206 : GUIntBig nSum = 0;
6457 206 : GUIntBig nSumSquare = 0;
6458 : // If no valid nodata, map to invalid value (256 for Byte)
6459 206 : const GUInt32 nNoDataValue =
6460 20 : (bGotNoDataValue && dfNoDataValue >= 0 &&
6461 20 : dfNoDataValue <= nMaxValueType &&
6462 20 : fabs(dfNoDataValue -
6463 20 : static_cast<GUInt32>(dfNoDataValue + 1e-10)) < 1e-10)
6464 226 : ? static_cast<GUInt32>(dfNoDataValue + 1e-10)
6465 : : nMaxValueType + 1;
6466 :
6467 206 : for (GIntBig iSampleBlock = 0;
6468 12589 : iSampleBlock <
6469 12589 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6470 12383 : iSampleBlock += nSampleRate)
6471 : {
6472 12382 : const int iYBlock =
6473 12382 : static_cast<int>(iSampleBlock / nBlocksPerRow);
6474 12382 : const int iXBlock =
6475 12382 : static_cast<int>(iSampleBlock % nBlocksPerRow);
6476 :
6477 : GDALRasterBlock *const poBlock =
6478 12382 : GetLockedBlockRef(iXBlock, iYBlock);
6479 12381 : if (poBlock == nullptr)
6480 0 : return CE_Failure;
6481 :
6482 12381 : void *const pData = poBlock->GetDataRef();
6483 :
6484 12381 : int nXCheck = 0, nYCheck = 0;
6485 12381 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6486 :
6487 12381 : if (eDataType == GDT_Byte)
6488 : {
6489 : ComputeStatisticsInternal<
6490 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
6491 11924 : f(nXCheck, nBlockXSize, nYCheck,
6492 : static_cast<const GByte *>(pData),
6493 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6494 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6495 : }
6496 : else
6497 : {
6498 : ComputeStatisticsInternal<
6499 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6500 457 : f(nXCheck, nBlockXSize, nYCheck,
6501 : static_cast<const GUInt16 *>(pData),
6502 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6503 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6504 : }
6505 :
6506 12379 : poBlock->DropLock();
6507 :
6508 12380 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
6509 12383 : (static_cast<double>(nBlocksPerRow) *
6510 12383 : nBlocksPerColumn),
6511 : "Compute Statistics", pProgressData))
6512 : {
6513 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
6514 : "User terminated");
6515 0 : return CE_Failure;
6516 : }
6517 : }
6518 :
6519 207 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6520 : {
6521 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6522 0 : return CE_Failure;
6523 : }
6524 :
6525 : /* --------------------------------------------------------------------
6526 : */
6527 : /* Save computed information. */
6528 : /* --------------------------------------------------------------------
6529 : */
6530 207 : if (nValidCount)
6531 198 : dfMean = static_cast<double>(nSum) / nValidCount;
6532 :
6533 : // To avoid potential precision issues when doing the difference,
6534 : // we need to do that computation on 128 bit rather than casting
6535 : // to double
6536 : const GDALUInt128 nTmpForStdDev(
6537 207 : GDALUInt128::Mul(nSumSquare, nValidCount) -
6538 414 : GDALUInt128::Mul(nSum, nSum));
6539 : const double dfStdDev =
6540 207 : nValidCount > 0
6541 207 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6542 207 : : 0.0;
6543 :
6544 207 : if (nValidCount > 0)
6545 : {
6546 198 : if (bApproxOK)
6547 : {
6548 23 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6549 : }
6550 175 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6551 : {
6552 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6553 : }
6554 198 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
6555 : }
6556 :
6557 207 : SetValidPercent(nSampleCount, nValidCount);
6558 :
6559 : /* --------------------------------------------------------------------
6560 : */
6561 : /* Record results. */
6562 : /* --------------------------------------------------------------------
6563 : */
6564 206 : if (pdfMin != nullptr)
6565 203 : *pdfMin = nValidCount ? nMin : 0;
6566 206 : if (pdfMax != nullptr)
6567 203 : *pdfMax = nValidCount ? nMax : 0;
6568 :
6569 206 : if (pdfMean != nullptr)
6570 199 : *pdfMean = dfMean;
6571 :
6572 206 : if (pdfStdDev != nullptr)
6573 199 : *pdfStdDev = dfStdDev;
6574 :
6575 206 : if (nValidCount > 0)
6576 198 : return CE_None;
6577 :
6578 8 : ReportError(CE_Failure, CPLE_AppDefined,
6579 : "Failed to compute statistics, no valid pixels found "
6580 : "in sampling.");
6581 9 : return CE_Failure;
6582 : }
6583 : #endif
6584 :
6585 238 : GByte *pabyMaskData = nullptr;
6586 238 : if (poMaskBand)
6587 : {
6588 : pabyMaskData = static_cast<GByte *>(
6589 16 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6590 16 : if (!pabyMaskData)
6591 : {
6592 0 : return CE_Failure;
6593 : }
6594 : }
6595 :
6596 238 : for (GIntBig iSampleBlock = 0;
6597 5489 : iSampleBlock <
6598 5489 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6599 5251 : iSampleBlock += nSampleRate)
6600 : {
6601 5251 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6602 5251 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6603 :
6604 : GDALRasterBlock *const poBlock =
6605 5251 : GetLockedBlockRef(iXBlock, iYBlock);
6606 5251 : if (poBlock == nullptr)
6607 : {
6608 0 : CPLFree(pabyMaskData);
6609 0 : return CE_Failure;
6610 : }
6611 :
6612 5251 : void *const pData = poBlock->GetDataRef();
6613 :
6614 5251 : int nXCheck = 0, nYCheck = 0;
6615 5251 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6616 :
6617 5352 : if (poMaskBand &&
6618 101 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6619 101 : iYBlock * nBlockYSize, nXCheck, nYCheck,
6620 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6621 101 : 0, nBlockXSize, nullptr) != CE_None)
6622 : {
6623 0 : CPLFree(pabyMaskData);
6624 0 : poBlock->DropLock();
6625 0 : return CE_Failure;
6626 : }
6627 :
6628 : // This isn't the fastest way to do this, but is easier for now.
6629 10686 : for (int iY = 0; iY < nYCheck; iY++)
6630 : {
6631 4342140 : for (int iX = 0; iX < nXCheck; iX++)
6632 : {
6633 4336710 : const GPtrDiff_t iOffset =
6634 4336710 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6635 4336710 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6636 109941 : continue;
6637 :
6638 4326840 : bool bValid = true;
6639 4326840 : double dfValue = GetPixelValue(
6640 : eDataType, bSignedByte, pData, iOffset,
6641 4326840 : CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
6642 4326840 : bGotFloatNoDataValue, fNoDataValue, bValid);
6643 :
6644 4326840 : if (!bValid)
6645 100070 : continue;
6646 :
6647 4226770 : dfMin = std::min(dfMin, dfValue);
6648 4226770 : dfMax = std::max(dfMax, dfValue);
6649 :
6650 4226770 : nValidCount++;
6651 4226770 : const double dfDelta = dfValue - dfMean;
6652 4226770 : dfMean += dfDelta / nValidCount;
6653 4226770 : dfM2 += dfDelta * (dfValue - dfMean);
6654 : }
6655 : }
6656 :
6657 5251 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6658 :
6659 5251 : poBlock->DropLock();
6660 :
6661 5251 : if (!pfnProgress(
6662 5251 : static_cast<double>(iSampleBlock) /
6663 5251 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6664 : "Compute Statistics", pProgressData))
6665 : {
6666 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6667 0 : CPLFree(pabyMaskData);
6668 0 : return CE_Failure;
6669 : }
6670 : }
6671 :
6672 238 : CPLFree(pabyMaskData);
6673 : }
6674 :
6675 238 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6676 : {
6677 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6678 0 : return CE_Failure;
6679 : }
6680 :
6681 : /* -------------------------------------------------------------------- */
6682 : /* Save computed information. */
6683 : /* -------------------------------------------------------------------- */
6684 238 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
6685 :
6686 238 : if (nValidCount > 0)
6687 : {
6688 237 : if (bApproxOK)
6689 : {
6690 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6691 : }
6692 229 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6693 : {
6694 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6695 : }
6696 237 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6697 : }
6698 : else
6699 : {
6700 1 : dfMin = 0.0;
6701 1 : dfMax = 0.0;
6702 : }
6703 :
6704 238 : SetValidPercent(nSampleCount, nValidCount);
6705 :
6706 : /* -------------------------------------------------------------------- */
6707 : /* Record results. */
6708 : /* -------------------------------------------------------------------- */
6709 238 : if (pdfMin != nullptr)
6710 235 : *pdfMin = dfMin;
6711 238 : if (pdfMax != nullptr)
6712 235 : *pdfMax = dfMax;
6713 :
6714 238 : if (pdfMean != nullptr)
6715 233 : *pdfMean = dfMean;
6716 :
6717 238 : if (pdfStdDev != nullptr)
6718 233 : *pdfStdDev = dfStdDev;
6719 :
6720 238 : if (nValidCount > 0)
6721 237 : return CE_None;
6722 :
6723 1 : ReportError(
6724 : CE_Failure, CPLE_AppDefined,
6725 : "Failed to compute statistics, no valid pixels found in sampling.");
6726 1 : return CE_Failure;
6727 : }
6728 :
6729 : /************************************************************************/
6730 : /* GDALComputeRasterStatistics() */
6731 : /************************************************************************/
6732 :
6733 : /**
6734 : * \brief Compute image statistics.
6735 : *
6736 : * @see GDALRasterBand::ComputeStatistics()
6737 : */
6738 :
6739 141 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
6740 : int bApproxOK, double *pdfMin,
6741 : double *pdfMax, double *pdfMean,
6742 : double *pdfStdDev,
6743 : GDALProgressFunc pfnProgress,
6744 : void *pProgressData)
6745 :
6746 : {
6747 141 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
6748 :
6749 141 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6750 :
6751 141 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
6752 141 : pdfStdDev, pfnProgress, pProgressData);
6753 : }
6754 :
6755 : /************************************************************************/
6756 : /* SetStatistics() */
6757 : /************************************************************************/
6758 :
6759 : /**
6760 : * \brief Set statistics on band.
6761 : *
6762 : * This method can be used to store min/max/mean/standard deviation
6763 : * statistics on a raster band.
6764 : *
6765 : * The default implementation stores them as metadata, and will only work
6766 : * on formats that can save arbitrary metadata. This method cannot detect
6767 : * whether metadata will be properly saved and so may return CE_None even
6768 : * if the statistics will never be saved.
6769 : *
6770 : * This method is the same as the C function GDALSetRasterStatistics().
6771 : *
6772 : * @param dfMin minimum pixel value.
6773 : *
6774 : * @param dfMax maximum pixel value.
6775 : *
6776 : * @param dfMean mean (average) of all pixel values.
6777 : *
6778 : * @param dfStdDev Standard deviation of all pixel values.
6779 : *
6780 : * @return CE_None on success or CE_Failure on failure.
6781 : */
6782 :
6783 463 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
6784 : double dfStdDev)
6785 :
6786 : {
6787 463 : char szValue[128] = {0};
6788 :
6789 463 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
6790 463 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
6791 :
6792 463 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
6793 463 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
6794 :
6795 463 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
6796 463 : SetMetadataItem("STATISTICS_MEAN", szValue);
6797 :
6798 463 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
6799 462 : SetMetadataItem("STATISTICS_STDDEV", szValue);
6800 :
6801 463 : return CE_None;
6802 : }
6803 :
6804 : /************************************************************************/
6805 : /* GDALSetRasterStatistics() */
6806 : /************************************************************************/
6807 :
6808 : /**
6809 : * \brief Set statistics on band.
6810 : *
6811 : * @see GDALRasterBand::SetStatistics()
6812 : */
6813 :
6814 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
6815 : double dfMax, double dfMean,
6816 : double dfStdDev)
6817 :
6818 : {
6819 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
6820 :
6821 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6822 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6823 : }
6824 :
6825 : /************************************************************************/
6826 : /* ComputeRasterMinMax() */
6827 : /************************************************************************/
6828 :
6829 : template <class T, bool HAS_NODATA>
6830 134689 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
6831 : T *pMax)
6832 : {
6833 134689 : T min0 = *pMin;
6834 134689 : T max0 = *pMax;
6835 134689 : T min1 = *pMin;
6836 134689 : T max1 = *pMax;
6837 : size_t i;
6838 1017014 : for (i = 0; i + 1 < nElts; i += 2)
6839 : {
6840 869734 : if (!HAS_NODATA || buffer[i] != nodataValue)
6841 : {
6842 881141 : min0 = std::min(min0, buffer[i]);
6843 881141 : max0 = std::max(max0, buffer[i]);
6844 : }
6845 869734 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
6846 : {
6847 881354 : min1 = std::min(min1, buffer[i + 1]);
6848 881354 : max1 = std::max(max1, buffer[i + 1]);
6849 : }
6850 : }
6851 134689 : T min = std::min(min0, min1);
6852 134689 : T max = std::max(max0, max1);
6853 134689 : if (i < nElts)
6854 : {
6855 119260 : if (!HAS_NODATA || buffer[i] != nodataValue)
6856 : {
6857 119276 : min = std::min(min, buffer[i]);
6858 119276 : max = std::max(max, buffer[i]);
6859 : }
6860 : }
6861 134689 : *pMin = min;
6862 134689 : *pMax = max;
6863 134689 : }
6864 :
6865 : template <GDALDataType eDataType, bool bSignedByte>
6866 11502 : static void ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
6867 : int nBlockXSize, bool bGotNoDataValue,
6868 : double dfNoDataValue,
6869 : bool bGotFloatNoDataValue, float fNoDataValue,
6870 : const GByte *pabyMaskData, double &dfMin,
6871 : double &dfMax)
6872 : {
6873 11502 : double dfLocalMin = dfMin;
6874 11502 : double dfLocalMax = dfMax;
6875 :
6876 43357 : for (int iY = 0; iY < nYCheck; iY++)
6877 : {
6878 18963015 : for (int iX = 0; iX < nXCheck; iX++)
6879 : {
6880 18931157 : const GPtrDiff_t iOffset =
6881 18931157 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6882 18931157 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6883 3460307 : continue;
6884 18836916 : bool bValid = true;
6885 18836916 : double dfValue = GetPixelValue(
6886 : eDataType, bSignedByte, pData, iOffset, bGotNoDataValue,
6887 : dfNoDataValue, bGotFloatNoDataValue, fNoDataValue, bValid);
6888 18836916 : if (!bValid)
6889 3366066 : continue;
6890 :
6891 15470809 : dfLocalMin = std::min(dfLocalMin, dfValue);
6892 15470809 : dfLocalMax = std::max(dfLocalMax, dfValue);
6893 : }
6894 : }
6895 :
6896 11502 : dfMin = dfLocalMin;
6897 11502 : dfMax = dfLocalMax;
6898 11502 : }
6899 :
6900 11502 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
6901 : bool bSignedByte, int nXCheck, int nYCheck,
6902 : int nBlockXSize, bool bGotNoDataValue,
6903 : double dfNoDataValue,
6904 : bool bGotFloatNoDataValue, float fNoDataValue,
6905 : const GByte *pabyMaskData, double &dfMin,
6906 : double &dfMax)
6907 : {
6908 11502 : switch (eDataType)
6909 : {
6910 0 : case GDT_Unknown:
6911 0 : CPLAssert(false);
6912 : break;
6913 672 : case GDT_Byte:
6914 672 : if (bSignedByte)
6915 : {
6916 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
6917 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6918 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6919 : }
6920 : else
6921 : {
6922 669 : ComputeMinMaxGeneric<GDT_Byte, false>(
6923 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6924 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6925 : }
6926 672 : break;
6927 102 : case GDT_Int8:
6928 102 : ComputeMinMaxGeneric<GDT_Int8, false>(
6929 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6930 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6931 102 : break;
6932 200 : case GDT_UInt16:
6933 200 : ComputeMinMaxGeneric<GDT_UInt16, false>(
6934 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6935 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6936 200 : break;
6937 1 : case GDT_Int16:
6938 1 : ComputeMinMaxGeneric<GDT_Int16, false>(
6939 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6940 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6941 1 : break;
6942 197 : case GDT_UInt32:
6943 197 : ComputeMinMaxGeneric<GDT_UInt32, false>(
6944 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6945 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6946 197 : break;
6947 1107 : case GDT_Int32:
6948 1107 : ComputeMinMaxGeneric<GDT_Int32, false>(
6949 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6950 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6951 1107 : break;
6952 12 : case GDT_UInt64:
6953 12 : ComputeMinMaxGeneric<GDT_UInt64, false>(
6954 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6955 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6956 12 : break;
6957 24 : case GDT_Int64:
6958 24 : ComputeMinMaxGeneric<GDT_Int64, false>(
6959 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6960 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6961 24 : break;
6962 5674 : case GDT_Float32:
6963 5674 : ComputeMinMaxGeneric<GDT_Float32, false>(
6964 : pData, nXCheck, nYCheck, nBlockXSize, false, 0,
6965 : bGotFloatNoDataValue, fNoDataValue, pabyMaskData, dfMin, dfMax);
6966 5674 : break;
6967 3403 : case GDT_Float64:
6968 3403 : ComputeMinMaxGeneric<GDT_Float64, false>(
6969 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6970 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6971 3403 : break;
6972 9 : case GDT_CInt16:
6973 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(
6974 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6975 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6976 9 : break;
6977 9 : case GDT_CInt32:
6978 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(
6979 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6980 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6981 9 : break;
6982 75 : case GDT_CFloat32:
6983 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
6984 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6985 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6986 75 : break;
6987 17 : case GDT_CFloat64:
6988 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
6989 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6990 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6991 17 : break;
6992 0 : case GDT_TypeCount:
6993 0 : CPLAssert(false);
6994 : break;
6995 : }
6996 11502 : }
6997 :
6998 696 : static bool ComputeMinMaxGenericIterBlocks(
6999 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
7000 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
7001 : bool bGotNoDataValue, double dfNoDataValue, bool bGotFloatNoDataValue,
7002 : float fNoDataValue, GDALRasterBand *poMaskBand, double &dfMin,
7003 : double &dfMax)
7004 :
7005 : {
7006 696 : GByte *pabyMaskData = nullptr;
7007 : int nBlockXSize, nBlockYSize;
7008 696 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7009 :
7010 696 : if (poMaskBand)
7011 : {
7012 : pabyMaskData =
7013 40 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7014 40 : if (!pabyMaskData)
7015 : {
7016 0 : return false;
7017 : }
7018 : }
7019 :
7020 12198 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7021 11502 : iSampleBlock += nSampleRate)
7022 : {
7023 11502 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7024 11502 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7025 :
7026 11502 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7027 11502 : if (poBlock == nullptr)
7028 : {
7029 0 : CPLFree(pabyMaskData);
7030 0 : return false;
7031 : }
7032 :
7033 11502 : void *const pData = poBlock->GetDataRef();
7034 :
7035 11502 : int nXCheck = 0, nYCheck = 0;
7036 11502 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7037 :
7038 12373 : if (poMaskBand &&
7039 871 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7040 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7041 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7042 : nBlockXSize, nullptr) != CE_None)
7043 : {
7044 0 : poBlock->DropLock();
7045 0 : CPLFree(pabyMaskData);
7046 0 : return false;
7047 : }
7048 :
7049 11502 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7050 11502 : nBlockXSize, CPL_TO_BOOL(bGotNoDataValue),
7051 : dfNoDataValue, bGotFloatNoDataValue, fNoDataValue,
7052 : pabyMaskData, dfMin, dfMax);
7053 :
7054 11502 : poBlock->DropLock();
7055 : }
7056 :
7057 696 : CPLFree(pabyMaskData);
7058 696 : return true;
7059 : }
7060 :
7061 : /**
7062 : * \brief Compute the min/max values for a band.
7063 : *
7064 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7065 : * be trusted. If it doesn't work, a subsample of blocks will be read to
7066 : * get an approximate min/max. If the band has a nodata value it will
7067 : * be excluded from the minimum and maximum.
7068 : *
7069 : * If bApprox is FALSE, then all pixels will be read and used to compute
7070 : * an exact range.
7071 : *
7072 : * This method is the same as the C function GDALComputeRasterMinMax().
7073 : *
7074 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7075 : * FALSE.
7076 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7077 : * maximum (adfMinMax[1]) are returned.
7078 : *
7079 : * @return CE_None on success or CE_Failure on failure.
7080 : */
7081 :
7082 1537 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7083 : {
7084 : /* -------------------------------------------------------------------- */
7085 : /* Does the driver already know the min/max? */
7086 : /* -------------------------------------------------------------------- */
7087 1537 : if (bApproxOK)
7088 : {
7089 12 : int bSuccessMin = FALSE;
7090 12 : int bSuccessMax = FALSE;
7091 :
7092 12 : double dfMin = GetMinimum(&bSuccessMin);
7093 12 : double dfMax = GetMaximum(&bSuccessMax);
7094 :
7095 12 : if (bSuccessMin && bSuccessMax)
7096 : {
7097 1 : adfMinMax[0] = dfMin;
7098 1 : adfMinMax[1] = dfMax;
7099 1 : return CE_None;
7100 : }
7101 : }
7102 :
7103 : /* -------------------------------------------------------------------- */
7104 : /* If we have overview bands, use them for min/max. */
7105 : /* -------------------------------------------------------------------- */
7106 : // cppcheck-suppress knownConditionTrueFalse
7107 1536 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7108 : {
7109 : GDALRasterBand *poBand =
7110 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7111 :
7112 0 : if (poBand != this)
7113 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7114 : }
7115 :
7116 : /* -------------------------------------------------------------------- */
7117 : /* Read actual data and compute minimum and maximum. */
7118 : /* -------------------------------------------------------------------- */
7119 1536 : int bGotNoDataValue = FALSE;
7120 1536 : const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
7121 1536 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
7122 1536 : bool bGotFloatNoDataValue = false;
7123 1536 : float fNoDataValue = 0.0f;
7124 1536 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
7125 : fNoDataValue, bGotFloatNoDataValue);
7126 :
7127 1536 : GDALRasterBand *poMaskBand = nullptr;
7128 1536 : if (!bGotNoDataValue)
7129 : {
7130 1272 : const int l_nMaskFlags = GetMaskFlags();
7131 1312 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7132 40 : GetColorInterpretation() != GCI_AlphaBand)
7133 : {
7134 40 : poMaskBand = GetMaskBand();
7135 : }
7136 : }
7137 :
7138 1536 : bool bSignedByte = false;
7139 1536 : if (eDataType == GDT_Byte)
7140 : {
7141 629 : EnablePixelTypeSignedByteWarning(false);
7142 : const char *pszPixelType =
7143 629 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7144 629 : EnablePixelTypeSignedByteWarning(true);
7145 629 : bSignedByte =
7146 629 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7147 : }
7148 :
7149 : GDALRasterIOExtraArg sExtraArg;
7150 1536 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7151 :
7152 3072 : GUInt32 nMin = (eDataType == GDT_Byte)
7153 1536 : ? 255
7154 : : 65535; // used for GByte & GUInt16 cases
7155 1536 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
7156 1536 : GInt16 nMinInt16 =
7157 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
7158 1536 : GInt16 nMaxInt16 =
7159 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
7160 1536 : double dfMin =
7161 : std::numeric_limits<double>::max(); // used for generic code path
7162 1536 : double dfMax =
7163 : -std::numeric_limits<double>::max(); // used for generic code path
7164 1536 : const bool bUseOptimizedPath =
7165 2434 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7166 898 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7167 :
7168 : const auto ComputeMinMaxForBlock =
7169 18551 : [this, bSignedByte, bGotNoDataValue, dfNoDataValue, &nMin, &nMax,
7170 : &nMinInt16, &nMaxInt16](const void *pData, int nXCheck,
7171 241704 : int nBufferWidth, int nYCheck)
7172 : {
7173 18551 : if (eDataType == GDT_Byte && !bSignedByte)
7174 : {
7175 : const bool bHasNoData =
7176 25638 : bGotNoDataValue && GDALIsValueInRange<GByte>(dfNoDataValue) &&
7177 9501 : static_cast<GByte>(dfNoDataValue) == dfNoDataValue;
7178 16137 : const GUInt32 nNoDataValue =
7179 16137 : bHasNoData ? static_cast<GByte>(dfNoDataValue) : 0;
7180 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7181 : ComputeStatisticsInternal<GByte,
7182 : /* COMPUTE_OTHER_STATS = */ false>::
7183 16137 : f(nXCheck, nBufferWidth, nYCheck,
7184 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7185 16137 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7186 : }
7187 2414 : else if (eDataType == GDT_UInt16)
7188 : {
7189 : const bool bHasNoData =
7190 973 : bGotNoDataValue && GDALIsValueInRange<GUInt16>(dfNoDataValue) &&
7191 83 : static_cast<GUInt16>(dfNoDataValue) == dfNoDataValue;
7192 890 : const GUInt32 nNoDataValue =
7193 890 : bHasNoData ? static_cast<GUInt16>(dfNoDataValue) : 0;
7194 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7195 : ComputeStatisticsInternal<GUInt16,
7196 : /* COMPUTE_OTHER_STATS = */ false>::
7197 890 : f(nXCheck, nBufferWidth, nYCheck,
7198 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7199 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7200 : }
7201 1524 : else if (eDataType == GDT_Int16)
7202 : {
7203 : const bool bHasNoData =
7204 2877 : bGotNoDataValue && GDALIsValueInRange<int16_t>(dfNoDataValue) &&
7205 1353 : static_cast<int16_t>(dfNoDataValue) == dfNoDataValue;
7206 1524 : if (bHasNoData)
7207 : {
7208 1353 : const int16_t nNoDataValue =
7209 : static_cast<int16_t>(dfNoDataValue);
7210 134754 : for (int iY = 0; iY < nYCheck; iY++)
7211 : {
7212 133401 : ComputeMinMax<int16_t, true>(
7213 133401 : static_cast<const int16_t *>(pData) +
7214 133401 : static_cast<size_t>(iY) * nBufferWidth,
7215 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7216 : }
7217 : }
7218 : else
7219 : {
7220 1459 : for (int iY = 0; iY < nYCheck; iY++)
7221 : {
7222 1288 : ComputeMinMax<int16_t, false>(
7223 1288 : static_cast<const int16_t *>(pData) +
7224 1288 : static_cast<size_t>(iY) * nBufferWidth,
7225 : nXCheck, 0, &nMinInt16, &nMaxInt16);
7226 : }
7227 : }
7228 : }
7229 18551 : };
7230 :
7231 1536 : if (bApproxOK && HasArbitraryOverviews())
7232 : {
7233 : /* --------------------------------------------------------------------
7234 : */
7235 : /* Figure out how much the image should be reduced to get an */
7236 : /* approximate value. */
7237 : /* --------------------------------------------------------------------
7238 : */
7239 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7240 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7241 :
7242 0 : int nXReduced = nRasterXSize;
7243 0 : int nYReduced = nRasterYSize;
7244 0 : if (dfReduction > 1.0)
7245 : {
7246 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7247 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7248 :
7249 : // Catch the case of huge resizing ratios here
7250 0 : if (nXReduced == 0)
7251 0 : nXReduced = 1;
7252 0 : if (nYReduced == 0)
7253 0 : nYReduced = 1;
7254 : }
7255 :
7256 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
7257 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7258 :
7259 : const CPLErr eErr =
7260 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7261 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7262 0 : if (eErr != CE_None)
7263 : {
7264 0 : CPLFree(pData);
7265 0 : return eErr;
7266 : }
7267 :
7268 0 : GByte *pabyMaskData = nullptr;
7269 0 : if (poMaskBand)
7270 : {
7271 : pabyMaskData =
7272 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7273 0 : if (!pabyMaskData)
7274 : {
7275 0 : CPLFree(pData);
7276 0 : return CE_Failure;
7277 : }
7278 :
7279 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7280 : pabyMaskData, nXReduced, nYReduced,
7281 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
7282 : {
7283 0 : CPLFree(pData);
7284 0 : CPLFree(pabyMaskData);
7285 0 : return CE_Failure;
7286 : }
7287 : }
7288 :
7289 0 : if (bUseOptimizedPath)
7290 : {
7291 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7292 : }
7293 : else
7294 : {
7295 0 : ComputeMinMaxGeneric(
7296 : pData, eDataType, bSignedByte, nXReduced, nYReduced, nXReduced,
7297 0 : CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
7298 : bGotFloatNoDataValue, fNoDataValue, pabyMaskData, dfMin, dfMax);
7299 : }
7300 :
7301 0 : CPLFree(pData);
7302 0 : CPLFree(pabyMaskData);
7303 : }
7304 :
7305 : else // No arbitrary overviews
7306 : {
7307 1536 : if (!InitBlockInfo())
7308 0 : return CE_Failure;
7309 :
7310 : /* --------------------------------------------------------------------
7311 : */
7312 : /* Figure out the ratio of blocks we will read to get an */
7313 : /* approximate value. */
7314 : /* --------------------------------------------------------------------
7315 : */
7316 1536 : int nSampleRate = 1;
7317 :
7318 1536 : if (bApproxOK)
7319 : {
7320 11 : nSampleRate = static_cast<int>(std::max(
7321 22 : 1.0,
7322 11 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7323 : // We want to avoid probing only the first column of blocks for
7324 : // a square shaped raster, because it is not unlikely that it may
7325 : // be padding only (#6378).
7326 11 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7327 0 : nSampleRate += 1;
7328 : }
7329 :
7330 1536 : if (bUseOptimizedPath)
7331 : {
7332 840 : for (GIntBig iSampleBlock = 0;
7333 19318 : iSampleBlock <
7334 19318 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7335 18478 : iSampleBlock += nSampleRate)
7336 : {
7337 18552 : const int iYBlock =
7338 18552 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7339 18552 : const int iXBlock =
7340 18552 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7341 :
7342 18552 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7343 18552 : if (poBlock == nullptr)
7344 1 : return CE_Failure;
7345 :
7346 18551 : void *const pData = poBlock->GetDataRef();
7347 :
7348 18551 : int nXCheck = 0, nYCheck = 0;
7349 18551 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7350 :
7351 18551 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7352 :
7353 18551 : poBlock->DropLock();
7354 :
7355 18551 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7356 4114 : nMax == 255)
7357 73 : break;
7358 : }
7359 : }
7360 : else
7361 : {
7362 696 : const GIntBig nTotalBlocks =
7363 696 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7364 696 : if (!ComputeMinMaxGenericIterBlocks(
7365 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7366 696 : nBlocksPerRow, CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
7367 : bGotFloatNoDataValue, fNoDataValue, poMaskBand, dfMin,
7368 : dfMax))
7369 : {
7370 0 : return CE_Failure;
7371 : }
7372 : }
7373 : }
7374 :
7375 1535 : if (bUseOptimizedPath)
7376 : {
7377 839 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7378 : {
7379 727 : dfMin = nMin;
7380 727 : dfMax = nMax;
7381 : }
7382 112 : else if (eDataType == GDT_Int16)
7383 : {
7384 112 : dfMin = nMinInt16;
7385 112 : dfMax = nMaxInt16;
7386 : }
7387 : }
7388 :
7389 1535 : if (dfMin > dfMax)
7390 : {
7391 4 : adfMinMax[0] = 0;
7392 4 : adfMinMax[1] = 0;
7393 4 : ReportError(
7394 : CE_Failure, CPLE_AppDefined,
7395 : "Failed to compute min/max, no valid pixels found in sampling.");
7396 4 : return CE_Failure;
7397 : }
7398 :
7399 1531 : adfMinMax[0] = dfMin;
7400 1531 : adfMinMax[1] = dfMax;
7401 :
7402 1531 : return CE_None;
7403 : }
7404 :
7405 : /************************************************************************/
7406 : /* GDALComputeRasterMinMax() */
7407 : /************************************************************************/
7408 :
7409 : /**
7410 : * \brief Compute the min/max values for a band.
7411 : *
7412 : * @see GDALRasterBand::ComputeRasterMinMax()
7413 : *
7414 : * @note Prior to GDAL 3.6, this function returned void
7415 : */
7416 :
7417 1459 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7418 : double adfMinMax[2])
7419 :
7420 : {
7421 1459 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7422 :
7423 1459 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7424 1459 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7425 : }
7426 :
7427 : /************************************************************************/
7428 : /* ComputeRasterMinMaxLocation() */
7429 : /************************************************************************/
7430 :
7431 : /**
7432 : * \brief Compute the min/max values for a band, and their location.
7433 : *
7434 : * Pixels whose value matches the nodata value or are masked by the mask
7435 : * band are ignored.
7436 : *
7437 : * If the minimum or maximum value is hit in several locations, it is not
7438 : * specified which one will be returned.
7439 : *
7440 : * @param[out] pdfMin Pointer to the minimum value.
7441 : * @param[out] pdfMax Pointer to the maximum value.
7442 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7443 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7444 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7445 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7446 : *
7447 : * @return CE_None in case of success, CE_Warning if there are no valid values,
7448 : * CE_Failure in case of error.
7449 : *
7450 : * @since GDAL 3.11
7451 : */
7452 :
7453 8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7454 : double *pdfMax, int *pnMinX,
7455 : int *pnMinY, int *pnMaxX,
7456 : int *pnMaxY)
7457 : {
7458 8 : int nMinX = -1;
7459 8 : int nMinY = -1;
7460 8 : int nMaxX = -1;
7461 8 : int nMaxY = -1;
7462 8 : double dfMin = std::numeric_limits<double>::infinity();
7463 8 : double dfMax = -std::numeric_limits<double>::infinity();
7464 8 : if (pdfMin)
7465 5 : *pdfMin = dfMin;
7466 8 : if (pdfMax)
7467 5 : *pdfMax = dfMax;
7468 8 : if (pnMinX)
7469 6 : *pnMinX = nMinX;
7470 8 : if (pnMinY)
7471 6 : *pnMinY = nMinY;
7472 8 : if (pnMaxX)
7473 6 : *pnMaxX = nMaxX;
7474 8 : if (pnMaxY)
7475 6 : *pnMaxY = nMaxY;
7476 :
7477 8 : if (GDALDataTypeIsComplex(eDataType))
7478 : {
7479 0 : CPLError(CE_Failure, CPLE_NotSupported,
7480 : "Complex data type not supported");
7481 0 : return CE_Failure;
7482 : }
7483 :
7484 8 : if (!InitBlockInfo())
7485 0 : return CE_Failure;
7486 :
7487 8 : int bGotNoDataValue = FALSE;
7488 8 : const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
7489 8 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
7490 8 : bool bGotFloatNoDataValue = false;
7491 8 : float fNoDataValue = 0.0f;
7492 8 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
7493 : fNoDataValue, bGotFloatNoDataValue);
7494 :
7495 8 : GDALRasterBand *poMaskBand = nullptr;
7496 8 : if (!bGotNoDataValue)
7497 : {
7498 8 : const int l_nMaskFlags = GetMaskFlags();
7499 9 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7500 1 : GetColorInterpretation() != GCI_AlphaBand)
7501 : {
7502 1 : poMaskBand = GetMaskBand();
7503 : }
7504 : }
7505 :
7506 8 : bool bSignedByte = false;
7507 8 : if (eDataType == GDT_Byte)
7508 : {
7509 7 : EnablePixelTypeSignedByteWarning(false);
7510 : const char *pszPixelType =
7511 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7512 7 : EnablePixelTypeSignedByteWarning(true);
7513 7 : bSignedByte =
7514 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7515 : }
7516 :
7517 8 : GByte *pabyMaskData = nullptr;
7518 8 : if (poMaskBand)
7519 : {
7520 : pabyMaskData =
7521 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7522 1 : if (!pabyMaskData)
7523 : {
7524 0 : return CE_Failure;
7525 : }
7526 : }
7527 :
7528 8 : const GIntBig nTotalBlocks =
7529 8 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7530 8 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7531 8 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7532 16 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7533 : {
7534 11 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7535 11 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7536 :
7537 11 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7538 11 : if (poBlock == nullptr)
7539 : {
7540 0 : CPLFree(pabyMaskData);
7541 0 : return CE_Failure;
7542 : }
7543 :
7544 11 : void *const pData = poBlock->GetDataRef();
7545 :
7546 11 : int nXCheck = 0, nYCheck = 0;
7547 11 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7548 :
7549 13 : if (poMaskBand &&
7550 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7551 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7552 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7553 2 : nBlockXSize, nullptr) != CE_None)
7554 : {
7555 0 : poBlock->DropLock();
7556 0 : CPLFree(pabyMaskData);
7557 0 : return CE_Failure;
7558 : }
7559 :
7560 11 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7561 : {
7562 4 : for (int iY = 0; iY < nYCheck; ++iY)
7563 : {
7564 6 : for (int iX = 0; iX < nXCheck; ++iX)
7565 : {
7566 4 : const GPtrDiff_t iOffset =
7567 4 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7568 4 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7569 2 : continue;
7570 2 : bool bValid = true;
7571 2 : double dfValue = GetPixelValue(
7572 : eDataType, bSignedByte, pData, iOffset, bGotNoDataValue,
7573 : dfNoDataValue, bGotFloatNoDataValue, fNoDataValue,
7574 : bValid);
7575 2 : if (!bValid)
7576 0 : continue;
7577 2 : if (dfValue < dfMin)
7578 : {
7579 2 : dfMin = dfValue;
7580 2 : nMinX = iXBlock * nBlockXSize + iX;
7581 2 : nMinY = iYBlock * nBlockYSize + iY;
7582 : }
7583 2 : if (dfValue > dfMax)
7584 : {
7585 1 : dfMax = dfValue;
7586 1 : nMaxX = iXBlock * nBlockXSize + iX;
7587 1 : nMaxY = iYBlock * nBlockYSize + iY;
7588 : }
7589 : }
7590 2 : }
7591 : }
7592 : else
7593 : {
7594 9 : size_t pos_min = 0;
7595 9 : size_t pos_max = 0;
7596 9 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7597 9 : if (bNeedsMin && bNeedsMax)
7598 : {
7599 10 : std::tie(pos_min, pos_max) = gdal::minmax_element(
7600 5 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7601 10 : eEffectiveDT, bGotNoDataValue, dfNoDataValue);
7602 : }
7603 4 : else if (bNeedsMin)
7604 : {
7605 1 : pos_min = gdal::min_element(
7606 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7607 : eEffectiveDT, bGotNoDataValue, dfNoDataValue);
7608 : }
7609 3 : else if (bNeedsMax)
7610 : {
7611 2 : pos_max = gdal::max_element(
7612 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7613 : eEffectiveDT, bGotNoDataValue, dfNoDataValue);
7614 : }
7615 :
7616 9 : if (bNeedsMin)
7617 : {
7618 6 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7619 6 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7620 6 : bool bValid = true;
7621 6 : const double dfMinValueBlock = GetPixelValue(
7622 : eDataType, bSignedByte, pData, pos_min, bGotNoDataValue,
7623 : dfNoDataValue, bGotFloatNoDataValue, fNoDataValue, bValid);
7624 6 : if (bValid && dfMinValueBlock < dfMin)
7625 : {
7626 5 : dfMin = dfMinValueBlock;
7627 5 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
7628 5 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
7629 : }
7630 : }
7631 :
7632 9 : if (bNeedsMax)
7633 : {
7634 7 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7635 7 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7636 7 : bool bValid = true;
7637 7 : const double dfMaxValueBlock = GetPixelValue(
7638 : eDataType, bSignedByte, pData, pos_max, bGotNoDataValue,
7639 : dfNoDataValue, bGotFloatNoDataValue, fNoDataValue, bValid);
7640 7 : if (bValid && dfMaxValueBlock > dfMax)
7641 : {
7642 5 : dfMax = dfMaxValueBlock;
7643 5 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7644 5 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7645 : }
7646 : }
7647 : }
7648 :
7649 11 : poBlock->DropLock();
7650 :
7651 11 : if (eDataType == GDT_Byte)
7652 : {
7653 10 : if (bNeedsMin && dfMin == 0)
7654 : {
7655 1 : bNeedsMin = false;
7656 : }
7657 10 : if (bNeedsMax && dfMax == 255)
7658 : {
7659 4 : bNeedsMax = false;
7660 : }
7661 10 : if (!bNeedsMin && !bNeedsMax)
7662 : {
7663 3 : break;
7664 : }
7665 : }
7666 : }
7667 :
7668 8 : CPLFree(pabyMaskData);
7669 :
7670 8 : if (pdfMin)
7671 5 : *pdfMin = dfMin;
7672 8 : if (pdfMax)
7673 5 : *pdfMax = dfMax;
7674 8 : if (pnMinX)
7675 6 : *pnMinX = nMinX;
7676 8 : if (pnMinY)
7677 6 : *pnMinY = nMinY;
7678 8 : if (pnMaxX)
7679 6 : *pnMaxX = nMaxX;
7680 8 : if (pnMaxY)
7681 6 : *pnMaxY = nMaxY;
7682 8 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
7683 8 : : CE_None;
7684 : }
7685 :
7686 : /************************************************************************/
7687 : /* GDALComputeRasterMinMaxLocation() */
7688 : /************************************************************************/
7689 :
7690 : /**
7691 : * \brief Compute the min/max values for a band, and their location.
7692 : *
7693 : * @see GDALRasterBand::ComputeRasterMinMax()
7694 : * @since GDAL 3.11
7695 : */
7696 :
7697 6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
7698 : double *pdfMax, int *pnMinX, int *pnMinY,
7699 : int *pnMaxX, int *pnMaxY)
7700 :
7701 : {
7702 6 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
7703 :
7704 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7705 6 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
7706 6 : pnMaxX, pnMaxY);
7707 : }
7708 :
7709 : /************************************************************************/
7710 : /* SetDefaultHistogram() */
7711 : /************************************************************************/
7712 :
7713 : /* FIXME : add proper documentation */
7714 : /**
7715 : * \brief Set default histogram.
7716 : *
7717 : * This method is the same as the C function GDALSetDefaultHistogram() and
7718 : * GDALSetDefaultHistogramEx()
7719 : */
7720 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
7721 : double /* dfMax */,
7722 : int /* nBuckets */,
7723 : GUIntBig * /* panHistogram */)
7724 :
7725 : {
7726 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
7727 0 : ReportError(CE_Failure, CPLE_NotSupported,
7728 : "SetDefaultHistogram() not implemented for this format.");
7729 :
7730 0 : return CE_Failure;
7731 : }
7732 :
7733 : /************************************************************************/
7734 : /* GDALSetDefaultHistogram() */
7735 : /************************************************************************/
7736 :
7737 : /**
7738 : * \brief Set default histogram.
7739 : *
7740 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
7741 : * 2 billion.
7742 : *
7743 : * @see GDALRasterBand::SetDefaultHistogram()
7744 : * @see GDALSetRasterHistogramEx()
7745 : */
7746 :
7747 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
7748 : double dfMax, int nBuckets,
7749 : int *panHistogram)
7750 :
7751 : {
7752 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
7753 :
7754 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7755 :
7756 : GUIntBig *panHistogramTemp =
7757 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
7758 0 : if (panHistogramTemp == nullptr)
7759 : {
7760 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
7761 : "Out of memory in GDALSetDefaultHistogram().");
7762 0 : return CE_Failure;
7763 : }
7764 :
7765 0 : for (int i = 0; i < nBuckets; ++i)
7766 : {
7767 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
7768 : }
7769 :
7770 : const CPLErr eErr =
7771 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
7772 :
7773 0 : CPLFree(panHistogramTemp);
7774 :
7775 0 : return eErr;
7776 : }
7777 :
7778 : /************************************************************************/
7779 : /* GDALSetDefaultHistogramEx() */
7780 : /************************************************************************/
7781 :
7782 : /**
7783 : * \brief Set default histogram.
7784 : *
7785 : * @see GDALRasterBand::SetDefaultHistogram()
7786 : *
7787 : * @since GDAL 2.0
7788 : */
7789 :
7790 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
7791 : double dfMin, double dfMax,
7792 : int nBuckets,
7793 : GUIntBig *panHistogram)
7794 :
7795 : {
7796 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
7797 :
7798 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7799 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
7800 : }
7801 :
7802 : /************************************************************************/
7803 : /* GetDefaultRAT() */
7804 : /************************************************************************/
7805 :
7806 : /**
7807 : * \brief Fetch default Raster Attribute Table.
7808 : *
7809 : * A RAT will be returned if there is a default one associated with the
7810 : * band, otherwise NULL is returned. The returned RAT is owned by the
7811 : * band and should not be deleted by the application.
7812 : *
7813 : * This method is the same as the C function GDALGetDefaultRAT().
7814 : *
7815 : * @return NULL, or a pointer to an internal RAT owned by the band.
7816 : */
7817 :
7818 112 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
7819 :
7820 : {
7821 112 : return nullptr;
7822 : }
7823 :
7824 : /************************************************************************/
7825 : /* GDALGetDefaultRAT() */
7826 : /************************************************************************/
7827 :
7828 : /**
7829 : * \brief Fetch default Raster Attribute Table.
7830 : *
7831 : * @see GDALRasterBand::GetDefaultRAT()
7832 : */
7833 :
7834 935 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
7835 :
7836 : {
7837 935 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
7838 :
7839 935 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7840 935 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
7841 : }
7842 :
7843 : /************************************************************************/
7844 : /* SetDefaultRAT() */
7845 : /************************************************************************/
7846 :
7847 : /**
7848 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
7849 : * \brief Set default Raster Attribute Table.
7850 : *
7851 : * Associates a default RAT with the band. If not implemented for the
7852 : * format a CPLE_NotSupported error will be issued. If successful a copy
7853 : * of the RAT is made, the original remains owned by the caller.
7854 : *
7855 : * This method is the same as the C function GDALSetDefaultRAT().
7856 : *
7857 : * @param poRAT the RAT to assign to the band.
7858 : *
7859 : * @return CE_None on success or CE_Failure if unsupported or otherwise
7860 : * failing.
7861 : */
7862 :
7863 : /**/
7864 : /**/
7865 :
7866 : CPLErr
7867 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
7868 : {
7869 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
7870 : {
7871 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
7872 0 : ReportError(CE_Failure, CPLE_NotSupported,
7873 : "SetDefaultRAT() not implemented for this format.");
7874 0 : CPLPopErrorHandler();
7875 : }
7876 0 : return CE_Failure;
7877 : }
7878 :
7879 : /************************************************************************/
7880 : /* GDALSetDefaultRAT() */
7881 : /************************************************************************/
7882 :
7883 : /**
7884 : * \brief Set default Raster Attribute Table.
7885 : *
7886 : * @see GDALRasterBand::GDALSetDefaultRAT()
7887 : */
7888 :
7889 18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
7890 : GDALRasterAttributeTableH hRAT)
7891 :
7892 : {
7893 18 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
7894 :
7895 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7896 :
7897 18 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
7898 : }
7899 :
7900 : /************************************************************************/
7901 : /* GetMaskBand() */
7902 : /************************************************************************/
7903 :
7904 : /**
7905 : * \brief Return the mask band associated with the band.
7906 : *
7907 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
7908 : * that returns one of four default implementations :
7909 : * <ul>
7910 : * <li>If a corresponding .msk file exists it will be used for the mask band.
7911 : * </li>
7912 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
7913 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
7914 : * GMF_NODATA | GMF_PER_DATASET.
7915 : * </li>
7916 : * <li>If the band has a nodata value set, an instance of the new
7917 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
7918 : * GMF_NODATA.
7919 : * </li>
7920 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
7921 : * to apply to this band (specific rules yet to be determined) and that is of
7922 : * type GDT_Byte then that alpha band will be returned, and the flags
7923 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
7924 : * </li>
7925 : * <li>If neither of the above apply, an instance of the new
7926 : * GDALAllValidRasterBand class will be returned that has 255 values for all
7927 : * pixels. The null flags will return GMF_ALL_VALID.
7928 : * </li>
7929 : * </ul>
7930 : *
7931 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
7932 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
7933 : *
7934 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
7935 : * dataset, with the same name as the main dataset and suffixed with .msk,
7936 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
7937 : * main dataset.
7938 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
7939 : * level, where xx matches the band number of a band of the main dataset. The
7940 : * value of those items is a combination of the flags GMF_ALL_VALID,
7941 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
7942 : * a band, then the other rules explained above will be used to generate a
7943 : * on-the-fly mask band.
7944 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
7945 : *
7946 : * This method is the same as the C function GDALGetMaskBand().
7947 : *
7948 : * @return a valid mask band.
7949 : *
7950 : * @since GDAL 1.5.0
7951 : *
7952 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
7953 : *
7954 : */
7955 741828 : GDALRasterBand *GDALRasterBand::GetMaskBand()
7956 :
7957 : {
7958 178011 : const auto HasNoData = [this]()
7959 : {
7960 59087 : int bHaveNoDataRaw = FALSE;
7961 59087 : bool bHaveNoData = false;
7962 59087 : if (eDataType == GDT_Int64)
7963 : {
7964 54 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
7965 54 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
7966 : }
7967 59033 : else if (eDataType == GDT_UInt64)
7968 : {
7969 41 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
7970 41 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
7971 : }
7972 : else
7973 : {
7974 58992 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
7975 57814 : if (bHaveNoDataRaw &&
7976 57814 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
7977 : {
7978 775 : bHaveNoData = true;
7979 : }
7980 : }
7981 57196 : return bHaveNoData;
7982 741828 : };
7983 :
7984 741828 : if (poMask != nullptr)
7985 : {
7986 700202 : if (poMask.IsOwned())
7987 : {
7988 330309 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
7989 : {
7990 31810 : if (HasNoData())
7991 : {
7992 9 : InvalidateMaskBand();
7993 : }
7994 : }
7995 300047 : else if (auto poNoDataMaskBand =
7996 298982 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
7997 : {
7998 157 : int bHaveNoDataRaw = FALSE;
7999 157 : bool bIsSame = false;
8000 157 : if (eDataType == GDT_Int64)
8001 9 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
8002 11 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
8003 2 : bHaveNoDataRaw;
8004 148 : else if (eDataType == GDT_UInt64)
8005 9 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8006 11 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8007 2 : bHaveNoDataRaw;
8008 : else
8009 : {
8010 : const double dfNoDataValue =
8011 139 : GetNoDataValue(&bHaveNoDataRaw);
8012 139 : if (bHaveNoDataRaw)
8013 : {
8014 136 : bIsSame =
8015 136 : std::isnan(dfNoDataValue)
8016 136 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8017 128 : : poNoDataMaskBand->m_dfNoDataValue ==
8018 : dfNoDataValue;
8019 : }
8020 : }
8021 157 : if (!bIsSame)
8022 23 : InvalidateMaskBand();
8023 : }
8024 : }
8025 :
8026 702595 : if (poMask)
8027 707080 : return poMask.get();
8028 : }
8029 :
8030 : /* -------------------------------------------------------------------- */
8031 : /* Check for a mask in a .msk file. */
8032 : /* -------------------------------------------------------------------- */
8033 27426 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8034 : {
8035 46 : poMask.reset(poDS->oOvManager.GetMaskBand(nBand), false);
8036 46 : if (poMask != nullptr)
8037 : {
8038 44 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8039 44 : return poMask.get();
8040 : }
8041 : }
8042 :
8043 : /* -------------------------------------------------------------------- */
8044 : /* Check for NODATA_VALUES metadata. */
8045 : /* -------------------------------------------------------------------- */
8046 27382 : if (poDS != nullptr)
8047 : {
8048 27366 : const char *pszNoDataValues = poDS->GetMetadataItem("NODATA_VALUES");
8049 27366 : if (pszNoDataValues != nullptr)
8050 : {
8051 : char **papszNoDataValues =
8052 56 : CSLTokenizeStringComplex(pszNoDataValues, " ", FALSE, FALSE);
8053 :
8054 : // Make sure we have as many values as bands.
8055 112 : if (CSLCount(papszNoDataValues) == poDS->GetRasterCount() &&
8056 56 : poDS->GetRasterCount() != 0)
8057 : {
8058 : // Make sure that all bands have the same data type
8059 : // This is clearly not a fundamental condition, just a
8060 : // condition to make implementation easier.
8061 56 : GDALDataType eDT = GDT_Unknown;
8062 56 : int i = 0; // Used after for.
8063 224 : for (; i < poDS->GetRasterCount(); ++i)
8064 : {
8065 168 : if (i == 0)
8066 56 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8067 112 : else if (eDT !=
8068 112 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
8069 : {
8070 0 : break;
8071 : }
8072 : }
8073 56 : if (i == poDS->GetRasterCount())
8074 : {
8075 56 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8076 : try
8077 : {
8078 56 : poMask.reset(new GDALNoDataValuesMaskBand(poDS), true);
8079 : }
8080 0 : catch (const std::bad_alloc &)
8081 : {
8082 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8083 0 : poMask.reset();
8084 : }
8085 56 : CSLDestroy(papszNoDataValues);
8086 56 : return poMask.get();
8087 : }
8088 : else
8089 : {
8090 0 : ReportError(CE_Warning, CPLE_AppDefined,
8091 : "All bands should have the same type in "
8092 : "order the NODATA_VALUES metadata item "
8093 : "to be used as a mask.");
8094 : }
8095 : }
8096 : else
8097 : {
8098 0 : ReportError(
8099 : CE_Warning, CPLE_AppDefined,
8100 : "NODATA_VALUES metadata item doesn't have the same number "
8101 : "of values as the number of bands. "
8102 : "Ignoring it for mask.");
8103 : }
8104 :
8105 0 : CSLDestroy(papszNoDataValues);
8106 : }
8107 : }
8108 :
8109 : /* -------------------------------------------------------------------- */
8110 : /* Check for nodata case. */
8111 : /* -------------------------------------------------------------------- */
8112 27326 : if (HasNoData())
8113 : {
8114 797 : nMaskFlags = GMF_NODATA;
8115 : try
8116 : {
8117 797 : poMask.reset(new GDALNoDataMaskBand(this), true);
8118 : }
8119 0 : catch (const std::bad_alloc &)
8120 : {
8121 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8122 0 : poMask.reset();
8123 : }
8124 797 : return poMask.get();
8125 : }
8126 :
8127 : /* -------------------------------------------------------------------- */
8128 : /* Check for alpha case. */
8129 : /* -------------------------------------------------------------------- */
8130 26514 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8131 53550 : this == poDS->GetRasterBand(1) &&
8132 507 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8133 : {
8134 186 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8135 : {
8136 142 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8137 142 : poMask.reset(poDS->GetRasterBand(2), false);
8138 142 : return poMask.get();
8139 : }
8140 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8141 : {
8142 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8143 : try
8144 : {
8145 23 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(2)),
8146 : true);
8147 : }
8148 0 : catch (const std::bad_alloc &)
8149 : {
8150 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8151 0 : poMask.reset();
8152 : }
8153 23 : return poMask.get();
8154 : }
8155 : }
8156 :
8157 26349 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8158 2668 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8159 53350 : this == poDS->GetRasterBand(3)) &&
8160 2079 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8161 : {
8162 1197 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8163 : {
8164 1150 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8165 1150 : poMask.reset(poDS->GetRasterBand(4), false);
8166 1150 : return poMask.get();
8167 : }
8168 47 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8169 : {
8170 35 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8171 : try
8172 : {
8173 35 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(4)),
8174 : true);
8175 : }
8176 0 : catch (const std::bad_alloc &)
8177 : {
8178 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8179 0 : poMask.reset();
8180 : }
8181 35 : return poMask.get();
8182 : }
8183 : }
8184 :
8185 : /* -------------------------------------------------------------------- */
8186 : /* Fallback to all valid case. */
8187 : /* -------------------------------------------------------------------- */
8188 25179 : nMaskFlags = GMF_ALL_VALID;
8189 : try
8190 : {
8191 25179 : poMask.reset(new GDALAllValidMaskBand(this), true);
8192 : }
8193 0 : catch (const std::bad_alloc &)
8194 : {
8195 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8196 0 : poMask.reset();
8197 : }
8198 :
8199 25179 : return poMask.get();
8200 : }
8201 :
8202 : /************************************************************************/
8203 : /* GDALGetMaskBand() */
8204 : /************************************************************************/
8205 :
8206 : /**
8207 : * \brief Return the mask band associated with the band.
8208 : *
8209 : * @see GDALRasterBand::GetMaskBand()
8210 : */
8211 :
8212 10879 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8213 :
8214 : {
8215 10879 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8216 :
8217 10879 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8218 10879 : return poBand->GetMaskBand();
8219 : }
8220 :
8221 : /************************************************************************/
8222 : /* GetMaskFlags() */
8223 : /************************************************************************/
8224 :
8225 : /**
8226 : * \brief Return the status flags of the mask band associated with the band.
8227 : *
8228 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8229 : * the following available definitions that may be extended in the future:
8230 : * <ul>
8231 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8232 : * 255. When used this will normally be the only flag set.
8233 : * </li>
8234 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8235 : * dataset.
8236 : * </li>
8237 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8238 : * and may have values other than 0 and 255.
8239 : * </li>
8240 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8241 : * nodata values. (mutually exclusive of GMF_ALPHA)
8242 : * </li>
8243 : * </ul>
8244 : *
8245 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8246 : * that returns one of four default implementations:
8247 : * <ul>
8248 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8249 : * </li>
8250 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8251 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8252 : * GMF_NODATA | GMF_PER_DATASET.
8253 : * </li>
8254 : * <li>If the band has a nodata value set, an instance of the new
8255 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8256 : * GMF_NODATA.
8257 : * </li>
8258 : * <li>If there is no nodata value, but the dataset has an alpha band that
8259 : * seems to apply to this band (specific rules yet to be determined) and that is
8260 : * of type GDT_Byte then that alpha band will be returned, and the flags
8261 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8262 : * </li>
8263 : * <li>If neither of the above apply, an instance of the new
8264 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8265 : * pixels. The null flags will return GMF_ALL_VALID.
8266 : * </li>
8267 : * </ul>
8268 : *
8269 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8270 : * dataset, with the same name as the main dataset and suffixed with .msk,
8271 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8272 : * main dataset.
8273 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8274 : * level, where xx matches the band number of a band of the main dataset. The
8275 : * value of those items is a combination of the flags GMF_ALL_VALID,
8276 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8277 : * a band, then the other rules explained above will be used to generate a
8278 : * on-the-fly mask band.
8279 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8280 : *
8281 : * This method is the same as the C function GDALGetMaskFlags().
8282 : *
8283 : * @since GDAL 1.5.0
8284 : *
8285 : * @return a valid mask band.
8286 : *
8287 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8288 : *
8289 : */
8290 78259 : int GDALRasterBand::GetMaskFlags()
8291 :
8292 : {
8293 : // If we don't have a band yet, force this now so that the masks value
8294 : // will be initialized.
8295 :
8296 78259 : if (poMask == nullptr)
8297 26208 : GetMaskBand();
8298 :
8299 78255 : return nMaskFlags;
8300 : }
8301 :
8302 : /************************************************************************/
8303 : /* GDALGetMaskFlags() */
8304 : /************************************************************************/
8305 :
8306 : /**
8307 : * \brief Return the status flags of the mask band associated with the band.
8308 : *
8309 : * @see GDALRasterBand::GetMaskFlags()
8310 : */
8311 :
8312 6028 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8313 :
8314 : {
8315 6028 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8316 :
8317 6028 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8318 6028 : return poBand->GetMaskFlags();
8319 : }
8320 :
8321 : /************************************************************************/
8322 : /* InvalidateMaskBand() */
8323 : /************************************************************************/
8324 :
8325 : //! @cond Doxygen_Suppress
8326 1063940 : void GDALRasterBand::InvalidateMaskBand()
8327 : {
8328 1063940 : poMask.reset();
8329 1063930 : nMaskFlags = 0;
8330 1063930 : }
8331 :
8332 : //! @endcond
8333 :
8334 : /************************************************************************/
8335 : /* CreateMaskBand() */
8336 : /************************************************************************/
8337 :
8338 : /**
8339 : * \brief Adds a mask band to the current band
8340 : *
8341 : * The default implementation of the CreateMaskBand() method is implemented
8342 : * based on similar rules to the .ovr handling implemented using the
8343 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8344 : * be created with the same basename as the original file, and it will have
8345 : * as many bands as the original image (or just one for GMF_PER_DATASET).
8346 : * The mask images will be deflate compressed tiled images with the same
8347 : * block size as the original image if possible.
8348 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8349 : * level, where xx matches the band number of a band of the main dataset. The
8350 : * value of those items will be the one of the nFlagsIn parameter.
8351 : *
8352 : * Note that if you got a mask band with a previous call to GetMaskBand(),
8353 : * it might be invalidated by CreateMaskBand(). So you have to call
8354 : * GetMaskBand() again.
8355 : *
8356 : * This method is the same as the C function GDALCreateMaskBand().
8357 : *
8358 : * @since GDAL 1.5.0
8359 : *
8360 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8361 : *
8362 : * @return CE_None on success or CE_Failure on an error.
8363 : *
8364 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8365 : * @see GDALDataset::CreateMaskBand()
8366 : *
8367 : */
8368 :
8369 9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8370 :
8371 : {
8372 9 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8373 : {
8374 9 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8375 9 : if (eErr != CE_None)
8376 1 : return eErr;
8377 :
8378 8 : InvalidateMaskBand();
8379 :
8380 8 : return CE_None;
8381 : }
8382 :
8383 0 : ReportError(CE_Failure, CPLE_NotSupported,
8384 : "CreateMaskBand() not supported for this band.");
8385 :
8386 0 : return CE_Failure;
8387 : }
8388 :
8389 : /************************************************************************/
8390 : /* GDALCreateMaskBand() */
8391 : /************************************************************************/
8392 :
8393 : /**
8394 : * \brief Adds a mask band to the current band
8395 : *
8396 : * @see GDALRasterBand::CreateMaskBand()
8397 : */
8398 :
8399 33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8400 :
8401 : {
8402 33 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8403 :
8404 33 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8405 33 : return poBand->CreateMaskBand(nFlags);
8406 : }
8407 :
8408 : /************************************************************************/
8409 : /* IsMaskBand() */
8410 : /************************************************************************/
8411 :
8412 : /**
8413 : * \brief Returns whether a band is a mask band.
8414 : *
8415 : * Mask band must be understood in the broad term: it can be a per-dataset
8416 : * mask band, an alpha band, or an implicit mask band.
8417 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8418 : *
8419 : * This method is the same as the C function GDALIsMaskBand().
8420 : *
8421 : * @return true if the band is a mask band.
8422 : *
8423 : * @see GDALDataset::CreateMaskBand()
8424 : *
8425 : * @since GDAL 3.5.0
8426 : *
8427 : */
8428 :
8429 401 : bool GDALRasterBand::IsMaskBand() const
8430 : {
8431 : // The GeoTIFF driver, among others, override this method to
8432 : // also handle external .msk bands.
8433 401 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8434 401 : GCI_AlphaBand;
8435 : }
8436 :
8437 : /************************************************************************/
8438 : /* GDALIsMaskBand() */
8439 : /************************************************************************/
8440 :
8441 : /**
8442 : * \brief Returns whether a band is a mask band.
8443 : *
8444 : * Mask band must be understood in the broad term: it can be a per-dataset
8445 : * mask band, an alpha band, or an implicit mask band.
8446 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8447 : *
8448 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8449 : *
8450 : * @return true if the band is a mask band.
8451 : *
8452 : * @see GDALRasterBand::IsMaskBand()
8453 : *
8454 : * @since GDAL 3.5.0
8455 : *
8456 : */
8457 :
8458 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
8459 :
8460 : {
8461 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8462 :
8463 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8464 37 : return poBand->IsMaskBand();
8465 : }
8466 :
8467 : /************************************************************************/
8468 : /* GetMaskValueRange() */
8469 : /************************************************************************/
8470 :
8471 : /**
8472 : * \brief Returns the range of values that a mask band can take.
8473 : *
8474 : * @return the range of values that a mask band can take.
8475 : *
8476 : * @since GDAL 3.5.0
8477 : *
8478 : */
8479 :
8480 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8481 : {
8482 0 : return GMVR_UNKNOWN;
8483 : }
8484 :
8485 : /************************************************************************/
8486 : /* GetIndexColorTranslationTo() */
8487 : /************************************************************************/
8488 :
8489 : /**
8490 : * \brief Compute translation table for color tables.
8491 : *
8492 : * When the raster band has a palette index, it may be useful to compute
8493 : * the "translation" of this palette to the palette of another band.
8494 : * The translation tries to do exact matching first, and then approximate
8495 : * matching if no exact matching is possible.
8496 : * This method returns a table such that table[i] = j where i is an index
8497 : * of the 'this' rasterband and j the corresponding index for the reference
8498 : * rasterband.
8499 : *
8500 : * This method is thought as internal to GDAL and is used for drivers
8501 : * like RPFTOC.
8502 : *
8503 : * The implementation only supports 1-byte palette rasterbands.
8504 : *
8505 : * @param poReferenceBand the raster band
8506 : * @param pTranslationTable an already allocated translation table (at least 256
8507 : * bytes), or NULL to let the method allocate it
8508 : * @param pApproximateMatching a pointer to a flag that is set if the matching
8509 : * is approximate. May be NULL.
8510 : *
8511 : * @return a translation table if the two bands are palette index and that they
8512 : * do not match or NULL in other cases. The table must be freed with CPLFree if
8513 : * NULL was passed for pTranslationTable.
8514 : */
8515 :
8516 : unsigned char *
8517 5 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8518 : unsigned char *pTranslationTable,
8519 : int *pApproximateMatching)
8520 : {
8521 5 : if (poReferenceBand == nullptr)
8522 0 : return nullptr;
8523 :
8524 : // cppcheck-suppress knownConditionTrueFalse
8525 5 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8526 : // cppcheck-suppress knownConditionTrueFalse
8527 5 : GetColorInterpretation() == GCI_PaletteIndex &&
8528 15 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
8529 5 : GetRasterDataType() == GDT_Byte)
8530 : {
8531 5 : const GDALColorTable *srcColorTable = GetColorTable();
8532 5 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8533 5 : if (srcColorTable != nullptr && destColorTable != nullptr)
8534 : {
8535 5 : const int nEntries = srcColorTable->GetColorEntryCount();
8536 5 : const int nRefEntries = destColorTable->GetColorEntryCount();
8537 :
8538 5 : int bHasNoDataValueSrc = FALSE;
8539 5 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8540 5 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8541 4 : dfNoDataValueSrc <= 255 &&
8542 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8543 1 : bHasNoDataValueSrc = FALSE;
8544 5 : const int noDataValueSrc =
8545 5 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8546 :
8547 5 : int bHasNoDataValueRef = FALSE;
8548 : const double dfNoDataValueRef =
8549 5 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8550 5 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8551 3 : dfNoDataValueRef <= 255 &&
8552 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8553 2 : bHasNoDataValueRef = FALSE;
8554 5 : const int noDataValueRef =
8555 5 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8556 :
8557 5 : bool samePalette = false;
8558 :
8559 5 : if (pApproximateMatching)
8560 3 : *pApproximateMatching = FALSE;
8561 :
8562 5 : if (nEntries == nRefEntries &&
8563 4 : bHasNoDataValueSrc == bHasNoDataValueRef &&
8564 4 : (bHasNoDataValueSrc == FALSE ||
8565 : noDataValueSrc == noDataValueRef))
8566 : {
8567 4 : samePalette = true;
8568 911 : for (int i = 0; i < nEntries; ++i)
8569 : {
8570 907 : if (noDataValueSrc == i)
8571 4 : continue;
8572 : const GDALColorEntry *entry =
8573 903 : srcColorTable->GetColorEntry(i);
8574 : const GDALColorEntry *entryRef =
8575 903 : destColorTable->GetColorEntry(i);
8576 903 : if (entry->c1 != entryRef->c1 ||
8577 903 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8578 : {
8579 0 : samePalette = false;
8580 : }
8581 : }
8582 : }
8583 :
8584 5 : if (!samePalette)
8585 : {
8586 1 : if (pTranslationTable == nullptr)
8587 : {
8588 : pTranslationTable = static_cast<unsigned char *>(
8589 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8590 1 : if (pTranslationTable == nullptr)
8591 1 : return nullptr;
8592 : }
8593 :
8594 : // Trying to remap the product palette on the subdataset
8595 : // palette.
8596 5 : for (int i = 0; i < nEntries; ++i)
8597 : {
8598 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8599 : noDataValueSrc == i)
8600 0 : continue;
8601 : const GDALColorEntry *entry =
8602 4 : srcColorTable->GetColorEntry(i);
8603 4 : bool bMatchFound = false;
8604 13 : for (int j = 0; j < nRefEntries; ++j)
8605 : {
8606 10 : if (bHasNoDataValueRef && noDataValueRef == j)
8607 0 : continue;
8608 : const GDALColorEntry *entryRef =
8609 10 : destColorTable->GetColorEntry(j);
8610 10 : if (entry->c1 == entryRef->c1 &&
8611 2 : entry->c2 == entryRef->c2 &&
8612 2 : entry->c3 == entryRef->c3)
8613 : {
8614 1 : pTranslationTable[i] =
8615 : static_cast<unsigned char>(j);
8616 1 : bMatchFound = true;
8617 1 : break;
8618 : }
8619 : }
8620 4 : if (!bMatchFound)
8621 : {
8622 : // No exact match. Looking for closest color now.
8623 3 : int best_j = 0;
8624 3 : int best_distance = 0;
8625 3 : if (pApproximateMatching)
8626 0 : *pApproximateMatching = TRUE;
8627 12 : for (int j = 0; j < nRefEntries; ++j)
8628 : {
8629 : const GDALColorEntry *entryRef =
8630 9 : destColorTable->GetColorEntry(j);
8631 9 : int distance = (entry->c1 - entryRef->c1) *
8632 9 : (entry->c1 - entryRef->c1) +
8633 9 : (entry->c2 - entryRef->c2) *
8634 9 : (entry->c2 - entryRef->c2) +
8635 9 : (entry->c3 - entryRef->c3) *
8636 9 : (entry->c3 - entryRef->c3);
8637 9 : if (j == 0 || distance < best_distance)
8638 : {
8639 7 : best_j = j;
8640 7 : best_distance = distance;
8641 : }
8642 : }
8643 3 : pTranslationTable[i] =
8644 : static_cast<unsigned char>(best_j);
8645 : }
8646 : }
8647 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
8648 0 : pTranslationTable[noDataValueSrc] =
8649 : static_cast<unsigned char>(noDataValueRef);
8650 :
8651 1 : return pTranslationTable;
8652 : }
8653 : }
8654 : }
8655 4 : return nullptr;
8656 : }
8657 :
8658 : /************************************************************************/
8659 : /* SetFlushBlockErr() */
8660 : /************************************************************************/
8661 :
8662 : /**
8663 : * \brief Store that an error occurred while writing a dirty block.
8664 : *
8665 : * This function stores the fact that an error occurred while writing a dirty
8666 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8667 : * flushed when the block cache get full, it is not convenient/possible to
8668 : * report that a dirty block could not be written correctly. This function
8669 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8670 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8671 : * places where the user can easily match the error with the relevant dataset.
8672 : */
8673 :
8674 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8675 : {
8676 0 : eFlushBlockErr = eErr;
8677 0 : }
8678 :
8679 : /************************************************************************/
8680 : /* IncDirtyBlocks() */
8681 : /************************************************************************/
8682 :
8683 : /**
8684 : * \brief Increment/decrement the number of dirty blocks
8685 : */
8686 :
8687 494890 : void GDALRasterBand::IncDirtyBlocks(int nInc)
8688 : {
8689 494890 : if (poBandBlockCache)
8690 494889 : poBandBlockCache->IncDirtyBlocks(nInc);
8691 494891 : }
8692 :
8693 : /************************************************************************/
8694 : /* ReportError() */
8695 : /************************************************************************/
8696 :
8697 : #ifndef DOXYGEN_XML
8698 : /**
8699 : * \brief Emits an error related to a raster band.
8700 : *
8701 : * This function is a wrapper for regular CPLError(). The only difference
8702 : * with CPLError() is that it prepends the error message with the dataset
8703 : * name and the band number.
8704 : *
8705 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
8706 : * @param err_no the error number (CPLE_*) from cpl_error.h.
8707 : * @param fmt a printf() style format string. Any additional arguments
8708 : * will be treated as arguments to fill in this format in a manner
8709 : * similar to printf().
8710 : *
8711 : * @since GDAL 1.9.0
8712 : */
8713 :
8714 2443 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
8715 : const char *fmt, ...) const
8716 : {
8717 : va_list args;
8718 :
8719 2443 : va_start(args, fmt);
8720 :
8721 2443 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
8722 2442 : pszDSName = CPLGetFilename(pszDSName);
8723 2441 : if (pszDSName[0] != '\0')
8724 : {
8725 2387 : CPLError(eErrClass, err_no, "%s",
8726 4774 : CPLString()
8727 2387 : .Printf("%s, band %d: ", pszDSName, GetBand())
8728 4774 : .append(CPLString().vPrintf(fmt, args))
8729 : .c_str());
8730 : }
8731 : else
8732 : {
8733 54 : CPLErrorV(eErrClass, err_no, fmt, args);
8734 : }
8735 :
8736 2443 : va_end(args);
8737 2443 : }
8738 : #endif
8739 :
8740 : /************************************************************************/
8741 : /* GetVirtualMemAuto() */
8742 : /************************************************************************/
8743 :
8744 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
8745 : *
8746 : * Only supported on Linux and Unix systems with mmap() for now.
8747 : *
8748 : * This method allows creating a virtual memory object for a GDALRasterBand,
8749 : * that exposes the whole image data as a virtual array.
8750 : *
8751 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
8752 : * specialized implementation, such as for raw files, may also directly use
8753 : * mechanisms of the operating system to create a view of the underlying file
8754 : * into virtual memory ( CPLVirtualMemFileMapNew() )
8755 : *
8756 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
8757 : * offer a specialized implementation with direct file mapping, provided that
8758 : * some requirements are met :
8759 : * - for all drivers, the dataset must be backed by a "real" file in the file
8760 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
8761 : * must match the native ordering of the CPU.
8762 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
8763 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
8764 : * the file in sequential order, and be equally spaced (which is generally the
8765 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
8766 : * GDT_Int16/GDT_UInt16, 32 for GDT_Float32 and 64 for GDT_Float64)
8767 : *
8768 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
8769 : * CPLVirtualMemFree() must be called before the raster band object is
8770 : * destroyed.
8771 : *
8772 : * If p is such a pointer and base_type the type matching
8773 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
8774 : * accessed with
8775 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
8776 : *
8777 : * This method is the same as the C GDALGetVirtualMemAuto() function.
8778 : *
8779 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
8780 : * read/write the band.
8781 : *
8782 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
8783 : * one pixel value in the buffer to the start of the next pixel value within a
8784 : * scanline.
8785 : *
8786 : * @param pnLineSpace Output parameter giving the byte offset from the start of
8787 : * one scanline in the buffer to the start of the next.
8788 : *
8789 : * @param papszOptions NULL terminated list of options.
8790 : * If a specialized implementation exists, defining
8791 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
8792 : * used. On the contrary, starting with GDAL 2.2, defining
8793 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
8794 : * being used (thus only allowing efficient implementations to be used). When
8795 : * requiring or falling back to the default implementation, the following
8796 : * options are available : CACHE_SIZE (in bytes, defaults to
8797 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
8798 : * to FALSE)
8799 : *
8800 : * @return a virtual memory object that must be unreferenced by
8801 : * CPLVirtualMemFree(), or NULL in case of failure.
8802 : *
8803 : * @since GDAL 1.11
8804 : */
8805 :
8806 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
8807 : int *pnPixelSpace,
8808 : GIntBig *pnLineSpace,
8809 : char **papszOptions)
8810 : {
8811 9 : const char *pszImpl = CSLFetchNameValueDef(
8812 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
8813 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
8814 8 : EQUAL(pszImpl, "FALSE"))
8815 : {
8816 1 : return nullptr;
8817 : }
8818 :
8819 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
8820 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
8821 8 : if (pnPixelSpace)
8822 8 : *pnPixelSpace = nPixelSpace;
8823 8 : if (pnLineSpace)
8824 8 : *pnLineSpace = nLineSpace;
8825 : const size_t nCacheSize =
8826 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
8827 : const size_t nPageSizeHint =
8828 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
8829 8 : const bool bSingleThreadUsage = CPLTestBool(
8830 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
8831 8 : return GDALRasterBandGetVirtualMem(
8832 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
8833 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
8834 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
8835 8 : papszOptions);
8836 : }
8837 :
8838 : /************************************************************************/
8839 : /* GDALGetVirtualMemAuto() */
8840 : /************************************************************************/
8841 :
8842 : /**
8843 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
8844 : *
8845 : * @see GDALRasterBand::GetVirtualMemAuto()
8846 : */
8847 :
8848 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
8849 : int *pnPixelSpace, GIntBig *pnLineSpace,
8850 : CSLConstList papszOptions)
8851 : {
8852 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
8853 :
8854 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8855 :
8856 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
8857 31 : const_cast<char **>(papszOptions));
8858 : }
8859 :
8860 : /************************************************************************/
8861 : /* GDALGetDataCoverageStatus() */
8862 : /************************************************************************/
8863 :
8864 : /**
8865 : * \brief Get the coverage status of a sub-window of the raster.
8866 : *
8867 : * Returns whether a sub-window of the raster contains only data, only empty
8868 : * blocks or a mix of both. This function can be used to determine quickly
8869 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
8870 : * be sparse.
8871 : *
8872 : * Empty blocks are blocks that are generally not physically present in the
8873 : * file, and when read through GDAL, contain only pixels whose value is the
8874 : * nodata value when it is set, or whose value is 0 when the nodata value is
8875 : * not set.
8876 : *
8877 : * The query is done in an efficient way without reading the actual pixel
8878 : * values. If not possible, or not implemented at all by the driver,
8879 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
8880 : * be returned.
8881 : *
8882 : * The values that can be returned by the function are the following,
8883 : * potentially combined with the binary or operator :
8884 : * <ul>
8885 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
8886 : * GetDataCoverageStatus(). This flag should be returned together with
8887 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
8888 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
8889 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
8890 : * the queried window. This is typically identified by the concept of missing
8891 : * block in formats that supports it.
8892 : * </li>
8893 : * </ul>
8894 : *
8895 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
8896 : * should be interpreted more as hint of potential presence of data. For example
8897 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
8898 : * nodata value), instead of using the missing block mechanism,
8899 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
8900 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
8901 : *
8902 : * The nMaskFlagStop should be generally set to 0. It can be set to a
8903 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
8904 : * the function as soon as the computed mask matches the nMaskFlagStop. For
8905 : * example, you can issue a request on the whole raster with nMaskFlagStop =
8906 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
8907 : * the function will exit, so that you can potentially refine the requested area
8908 : * to find which particular region(s) have missing blocks.
8909 : *
8910 : * @see GDALRasterBand::GetDataCoverageStatus()
8911 : *
8912 : * @param hBand raster band
8913 : *
8914 : * @param nXOff The pixel offset to the top left corner of the region
8915 : * of the band to be queried. This would be zero to start from the left side.
8916 : *
8917 : * @param nYOff The line offset to the top left corner of the region
8918 : * of the band to be queried. This would be zero to start from the top.
8919 : *
8920 : * @param nXSize The width of the region of the band to be queried in pixels.
8921 : *
8922 : * @param nYSize The height of the region of the band to be queried in lines.
8923 : *
8924 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
8925 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8926 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
8927 : * as the computation of the coverage matches the mask, the computation will be
8928 : * stopped. *pdfDataPct will not be valid in that case.
8929 : *
8930 : * @param pdfDataPct Optional output parameter whose pointed value will be set
8931 : * to the (approximate) percentage in [0,100] of pixels in the queried
8932 : * sub-window that have valid values. The implementation might not always be
8933 : * able to compute it, in which case it will be set to a negative value.
8934 : *
8935 : * @return a binary-or'ed combination of possible values
8936 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8937 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
8938 : *
8939 : * @note Added in GDAL 2.2
8940 : */
8941 :
8942 26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
8943 : int nYOff, int nXSize, int nYSize,
8944 : int nMaskFlagStop, double *pdfDataPct)
8945 : {
8946 26 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
8947 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
8948 :
8949 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8950 :
8951 26 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
8952 26 : nMaskFlagStop, pdfDataPct);
8953 : }
8954 :
8955 : /************************************************************************/
8956 : /* GetDataCoverageStatus() */
8957 : /************************************************************************/
8958 :
8959 : /**
8960 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
8961 : * int nYOff,
8962 : * int nXSize,
8963 : * int nYSize,
8964 : * int nMaskFlagStop,
8965 : * double* pdfDataPct)
8966 : * \brief Get the coverage status of a sub-window of the raster.
8967 : *
8968 : * Returns whether a sub-window of the raster contains only data, only empty
8969 : * blocks or a mix of both. This function can be used to determine quickly
8970 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
8971 : * be sparse.
8972 : *
8973 : * Empty blocks are blocks that contain only pixels whose value is the nodata
8974 : * value when it is set, or whose value is 0 when the nodata value is not set.
8975 : *
8976 : * The query is done in an efficient way without reading the actual pixel
8977 : * values. If not possible, or not implemented at all by the driver,
8978 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
8979 : * be returned.
8980 : *
8981 : * The values that can be returned by the function are the following,
8982 : * potentially combined with the binary or operator :
8983 : * <ul>
8984 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
8985 : * GetDataCoverageStatus(). This flag should be returned together with
8986 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
8987 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
8988 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
8989 : * the queried window. This is typically identified by the concept of missing
8990 : * block in formats that supports it.
8991 : * </li>
8992 : * </ul>
8993 : *
8994 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
8995 : * should be interpreted more as hint of potential presence of data. For example
8996 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
8997 : * nodata value), instead of using the missing block mechanism,
8998 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
8999 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9000 : *
9001 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9002 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9003 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9004 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9005 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9006 : * the function will exit, so that you can potentially refine the requested area
9007 : * to find which particular region(s) have missing blocks.
9008 : *
9009 : * @see GDALGetDataCoverageStatus()
9010 : *
9011 : * @param nXOff The pixel offset to the top left corner of the region
9012 : * of the band to be queried. This would be zero to start from the left side.
9013 : *
9014 : * @param nYOff The line offset to the top left corner of the region
9015 : * of the band to be queried. This would be zero to start from the top.
9016 : *
9017 : * @param nXSize The width of the region of the band to be queried in pixels.
9018 : *
9019 : * @param nYSize The height of the region of the band to be queried in lines.
9020 : *
9021 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9022 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9023 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9024 : * as the computation of the coverage matches the mask, the computation will be
9025 : * stopped. *pdfDataPct will not be valid in that case.
9026 : *
9027 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9028 : * to the (approximate) percentage in [0,100] of pixels in the queried
9029 : * sub-window that have valid values. The implementation might not always be
9030 : * able to compute it, in which case it will be set to a negative value.
9031 : *
9032 : * @return a binary-or'ed combination of possible values
9033 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9034 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9035 : *
9036 : * @note Added in GDAL 2.2
9037 : */
9038 :
9039 : /**
9040 : * \brief Get the coverage status of a sub-window of the raster.
9041 : *
9042 : * Returns whether a sub-window of the raster contains only data, only empty
9043 : * blocks or a mix of both. This function can be used to determine quickly
9044 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9045 : * be sparse.
9046 : *
9047 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9048 : * value when it is set, or whose value is 0 when the nodata value is not set.
9049 : *
9050 : * The query is done in an efficient way without reading the actual pixel
9051 : * values. If not possible, or not implemented at all by the driver,
9052 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9053 : * be returned.
9054 : *
9055 : * The values that can be returned by the function are the following,
9056 : * potentially combined with the binary or operator :
9057 : * <ul>
9058 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9059 : * GetDataCoverageStatus(). This flag should be returned together with
9060 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9061 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9062 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9063 : * the queried window. This is typically identified by the concept of missing
9064 : * block in formats that supports it.
9065 : * </li>
9066 : * </ul>
9067 : *
9068 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9069 : * should be interpreted more as hint of potential presence of data. For example
9070 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9071 : * nodata value), instead of using the missing block mechanism,
9072 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9073 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9074 : *
9075 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9076 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9077 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9078 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9079 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9080 : * the function will exit, so that you can potentially refine the requested area
9081 : * to find which particular region(s) have missing blocks.
9082 : *
9083 : * @see GDALGetDataCoverageStatus()
9084 : *
9085 : * @param nXOff The pixel offset to the top left corner of the region
9086 : * of the band to be queried. This would be zero to start from the left side.
9087 : *
9088 : * @param nYOff The line offset to the top left corner of the region
9089 : * of the band to be queried. This would be zero to start from the top.
9090 : *
9091 : * @param nXSize The width of the region of the band to be queried in pixels.
9092 : *
9093 : * @param nYSize The height of the region of the band to be queried in lines.
9094 : *
9095 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9096 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9097 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9098 : * as the computation of the coverage matches the mask, the computation will be
9099 : * stopped. *pdfDataPct will not be valid in that case.
9100 : *
9101 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9102 : * to the (approximate) percentage in [0,100] of pixels in the queried
9103 : * sub-window that have valid values. The implementation might not always be
9104 : * able to compute it, in which case it will be set to a negative value.
9105 : *
9106 : * @return a binary-or'ed combination of possible values
9107 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9108 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9109 : *
9110 : * @note Added in GDAL 2.2
9111 : */
9112 :
9113 2655 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9114 : int nYSize, int nMaskFlagStop,
9115 : double *pdfDataPct)
9116 : {
9117 2655 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9118 2655 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9119 2655 : nYOff + nYSize > nRasterYSize)
9120 : {
9121 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9122 0 : if (pdfDataPct)
9123 0 : *pdfDataPct = 0.0;
9124 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9125 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
9126 : }
9127 2655 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9128 2655 : pdfDataPct);
9129 : }
9130 :
9131 : /************************************************************************/
9132 : /* IGetDataCoverageStatus() */
9133 : /************************************************************************/
9134 :
9135 497 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9136 : int /*nXSize*/, int /*nYSize*/,
9137 : int /*nMaskFlagStop*/,
9138 : double *pdfDataPct)
9139 : {
9140 497 : if (pdfDataPct != nullptr)
9141 0 : *pdfDataPct = 100.0;
9142 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9143 497 : GDAL_DATA_COVERAGE_STATUS_DATA;
9144 : }
9145 :
9146 : //! @cond Doxygen_Suppress
9147 : /************************************************************************/
9148 : /* EnterReadWrite() */
9149 : /************************************************************************/
9150 :
9151 6795120 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9152 : {
9153 6795120 : if (poDS != nullptr)
9154 6039520 : return poDS->EnterReadWrite(eRWFlag);
9155 755592 : return FALSE;
9156 : }
9157 :
9158 : /************************************************************************/
9159 : /* LeaveReadWrite() */
9160 : /************************************************************************/
9161 :
9162 587291 : void GDALRasterBand::LeaveReadWrite()
9163 : {
9164 587291 : if (poDS != nullptr)
9165 587291 : poDS->LeaveReadWrite();
9166 587289 : }
9167 :
9168 : /************************************************************************/
9169 : /* InitRWLock() */
9170 : /************************************************************************/
9171 :
9172 3633040 : void GDALRasterBand::InitRWLock()
9173 : {
9174 3633040 : if (poDS != nullptr)
9175 3632640 : poDS->InitRWLock();
9176 3633040 : }
9177 :
9178 : //! @endcond
9179 :
9180 : // clang-format off
9181 :
9182 : /**
9183 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9184 : * \brief Set metadata.
9185 : *
9186 : * CAUTION: depending on the format, older values of the updated information
9187 : * might still be found in the file in a "ghost" state, even if no longer
9188 : * accessible through the GDAL API. This is for example the case of the GTiff
9189 : * format (this is not a exhaustive list)
9190 : *
9191 : * The C function GDALSetMetadata() does the same thing as this method.
9192 : *
9193 : * @param papszMetadata the metadata in name=value string list format to
9194 : * apply.
9195 : * @param pszDomain the domain of interest. Use "" or NULL for the default
9196 : * domain.
9197 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9198 : * metadata has been accepted, but is likely not maintained persistently
9199 : * by the underlying object between sessions.
9200 : */
9201 :
9202 : /**
9203 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9204 : * \brief Set single metadata item.
9205 : *
9206 : * CAUTION: depending on the format, older values of the updated information
9207 : * might still be found in the file in a "ghost" state, even if no longer
9208 : * accessible through the GDAL API. This is for example the case of the GTiff
9209 : * format (this is not a exhaustive list)
9210 : *
9211 : * The C function GDALSetMetadataItem() does the same thing as this method.
9212 : *
9213 : * @param pszName the key for the metadata item to fetch.
9214 : * @param pszValue the value to assign to the key.
9215 : * @param pszDomain the domain to set within, use NULL for the default domain.
9216 : *
9217 : * @return CE_None on success, or an error code on failure.
9218 : */
9219 :
9220 : // clang-format on
9221 :
9222 : //! @cond Doxygen_Suppress
9223 : /************************************************************************/
9224 : /* EnablePixelTypeSignedByteWarning() */
9225 : /************************************************************************/
9226 :
9227 25803 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9228 : {
9229 25803 : m_bEnablePixelTypeSignedByteWarning = b;
9230 25803 : }
9231 :
9232 6612 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9233 : {
9234 6612 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9235 6612 : }
9236 :
9237 : //! @endcond
9238 :
9239 : /************************************************************************/
9240 : /* GetMetadataItem() */
9241 : /************************************************************************/
9242 :
9243 59905 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9244 : const char *pszDomain)
9245 : {
9246 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9247 59905 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9248 36574 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9249 27786 : EQUAL(pszName, "PIXELTYPE"))
9250 : {
9251 2 : CPLError(CE_Warning, CPLE_AppDefined,
9252 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9253 : "used to signal signed 8-bit raster. Change your code to "
9254 : "test for the new GDT_Int8 data type instead.");
9255 : }
9256 59905 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9257 : }
9258 :
9259 : /************************************************************************/
9260 : /* GDALMDArrayFromRasterBand */
9261 : /************************************************************************/
9262 :
9263 : class GDALMDArrayFromRasterBand final : public GDALMDArray
9264 : {
9265 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9266 :
9267 : GDALDataset *m_poDS;
9268 : GDALRasterBand *m_poBand;
9269 : GDALExtendedDataType m_dt;
9270 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9271 : std::string m_osUnit;
9272 : std::vector<GByte> m_pabyNoData{};
9273 : std::shared_ptr<GDALMDArray> m_varX{};
9274 : std::shared_ptr<GDALMDArray> m_varY{};
9275 : std::string m_osFilename{};
9276 :
9277 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9278 : const size_t *count, const GInt64 *arrayStep,
9279 : const GPtrDiff_t *bufferStride,
9280 : const GDALExtendedDataType &bufferDataType,
9281 : void *pBuffer) const;
9282 :
9283 : protected:
9284 23 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9285 46 : : GDALAbstractMDArray(std::string(),
9286 46 : std::string(poDS->GetDescription()) +
9287 : CPLSPrintf(" band %d", poBand->GetBand())),
9288 46 : GDALMDArray(std::string(),
9289 46 : std::string(poDS->GetDescription()) +
9290 : CPLSPrintf(" band %d", poBand->GetBand())),
9291 : m_poDS(poDS), m_poBand(poBand),
9292 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9293 115 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9294 : {
9295 23 : m_poDS->Reference();
9296 :
9297 23 : int bHasNoData = false;
9298 23 : if (m_poBand->GetRasterDataType() == GDT_Int64)
9299 : {
9300 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9301 0 : if (bHasNoData)
9302 : {
9303 0 : m_pabyNoData.resize(m_dt.GetSize());
9304 0 : GDALCopyWords(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9305 : m_dt.GetNumericDataType(), 0, 1);
9306 : }
9307 : }
9308 23 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9309 : {
9310 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9311 0 : if (bHasNoData)
9312 : {
9313 0 : m_pabyNoData.resize(m_dt.GetSize());
9314 0 : GDALCopyWords(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9315 : m_dt.GetNumericDataType(), 0, 1);
9316 : }
9317 : }
9318 : else
9319 : {
9320 23 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9321 23 : if (bHasNoData)
9322 : {
9323 1 : m_pabyNoData.resize(m_dt.GetSize());
9324 1 : GDALCopyWords(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9325 : m_dt.GetNumericDataType(), 0, 1);
9326 : }
9327 : }
9328 :
9329 23 : const int nXSize = poBand->GetXSize();
9330 23 : const int nYSize = poBand->GetYSize();
9331 :
9332 23 : auto poSRS = m_poDS->GetSpatialRef();
9333 46 : std::string osTypeY;
9334 46 : std::string osTypeX;
9335 46 : std::string osDirectionY;
9336 46 : std::string osDirectionX;
9337 23 : if (poSRS && poSRS->GetAxesCount() == 2)
9338 : {
9339 21 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9340 21 : OGRAxisOrientation eOrientation1 = OAO_Other;
9341 21 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
9342 21 : OGRAxisOrientation eOrientation2 = OAO_Other;
9343 21 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
9344 21 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9345 : {
9346 5 : if (mapping == std::vector<int>{1, 2})
9347 : {
9348 5 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9349 5 : osDirectionY = "NORTH";
9350 5 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9351 5 : osDirectionX = "EAST";
9352 : }
9353 : }
9354 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9355 : {
9356 16 : if (mapping == std::vector<int>{2, 1})
9357 : {
9358 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9359 16 : osDirectionY = "NORTH";
9360 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9361 16 : osDirectionX = "EAST";
9362 : }
9363 : }
9364 : }
9365 :
9366 115 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9367 : "/", "Y", osTypeY, osDirectionY, nYSize),
9368 46 : std::make_shared<GDALDimensionWeakIndexingVar>(
9369 69 : "/", "X", osTypeX, osDirectionX, nXSize)};
9370 :
9371 : double adfGeoTransform[6];
9372 23 : if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
9373 23 : adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
9374 : {
9375 44 : m_varX = GDALMDArrayRegularlySpaced::Create(
9376 22 : "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
9377 22 : 0.5);
9378 22 : m_dims[1]->SetIndexingVariable(m_varX);
9379 :
9380 44 : m_varY = GDALMDArrayRegularlySpaced::Create(
9381 22 : "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
9382 22 : 0.5);
9383 22 : m_dims[0]->SetIndexingVariable(m_varY);
9384 : }
9385 23 : }
9386 :
9387 31 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9388 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9389 : const GDALExtendedDataType &bufferDataType,
9390 : void *pDstBuffer) const override
9391 : {
9392 31 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9393 31 : bufferDataType, pDstBuffer);
9394 : }
9395 :
9396 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9397 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9398 : const GDALExtendedDataType &bufferDataType,
9399 : const void *pSrcBuffer) override
9400 : {
9401 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9402 : bufferStride, bufferDataType,
9403 1 : const_cast<void *>(pSrcBuffer));
9404 : }
9405 :
9406 : public:
9407 46 : ~GDALMDArrayFromRasterBand()
9408 23 : {
9409 23 : m_poDS->ReleaseRef();
9410 46 : }
9411 :
9412 23 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9413 : GDALRasterBand *poBand)
9414 : {
9415 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9416 46 : new GDALMDArrayFromRasterBand(poDS, poBand)));
9417 23 : array->SetSelf(array);
9418 46 : return array;
9419 : }
9420 :
9421 2 : bool IsWritable() const override
9422 : {
9423 2 : return m_poDS->GetAccess() == GA_Update;
9424 : }
9425 :
9426 97 : const std::string &GetFilename() const override
9427 : {
9428 97 : return m_osFilename;
9429 : }
9430 :
9431 : const std::vector<std::shared_ptr<GDALDimension>> &
9432 299 : GetDimensions() const override
9433 : {
9434 299 : return m_dims;
9435 : }
9436 :
9437 138 : const GDALExtendedDataType &GetDataType() const override
9438 : {
9439 138 : return m_dt;
9440 : }
9441 :
9442 3 : const std::string &GetUnit() const override
9443 : {
9444 3 : return m_osUnit;
9445 : }
9446 :
9447 29 : const void *GetRawNoDataValue() const override
9448 : {
9449 29 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9450 : }
9451 :
9452 2 : double GetOffset(bool *pbHasOffset,
9453 : GDALDataType *peStorageType) const override
9454 : {
9455 2 : int bHasOffset = false;
9456 2 : double dfRes = m_poBand->GetOffset(&bHasOffset);
9457 2 : if (pbHasOffset)
9458 2 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9459 2 : if (peStorageType)
9460 1 : *peStorageType = GDT_Unknown;
9461 2 : return dfRes;
9462 : }
9463 :
9464 2 : double GetScale(bool *pbHasScale,
9465 : GDALDataType *peStorageType) const override
9466 : {
9467 2 : int bHasScale = false;
9468 2 : double dfRes = m_poBand->GetScale(&bHasScale);
9469 2 : if (pbHasScale)
9470 2 : *pbHasScale = CPL_TO_BOOL(bHasScale);
9471 2 : if (peStorageType)
9472 1 : *peStorageType = GDT_Unknown;
9473 2 : return dfRes;
9474 : }
9475 :
9476 84 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9477 : {
9478 84 : auto poSrcSRS = m_poDS->GetSpatialRef();
9479 84 : if (!poSrcSRS)
9480 2 : return nullptr;
9481 164 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9482 :
9483 164 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9484 82 : constexpr int iYDim = 0;
9485 82 : constexpr int iXDim = 1;
9486 246 : for (auto &m : axisMapping)
9487 : {
9488 164 : if (m == 1)
9489 82 : m = iXDim + 1;
9490 82 : else if (m == 2)
9491 82 : m = iYDim + 1;
9492 : else
9493 0 : m = 0;
9494 : }
9495 82 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9496 82 : return poSRS;
9497 : }
9498 :
9499 29 : std::vector<GUInt64> GetBlockSize() const override
9500 : {
9501 29 : int nBlockXSize = 0;
9502 29 : int nBlockYSize = 0;
9503 29 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9504 29 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9505 29 : static_cast<GUInt64>(nBlockXSize)};
9506 : }
9507 :
9508 : class MDIAsAttribute : public GDALAttribute
9509 : {
9510 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9511 : const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
9512 : std::string m_osValue;
9513 :
9514 : public:
9515 2 : MDIAsAttribute(const std::string &name, const std::string &value)
9516 2 : : GDALAbstractMDArray(std::string(), name),
9517 4 : GDALAttribute(std::string(), name), m_osValue(value)
9518 : {
9519 2 : }
9520 :
9521 : const std::vector<std::shared_ptr<GDALDimension>> &
9522 3 : GetDimensions() const override
9523 : {
9524 3 : return m_dims;
9525 : }
9526 :
9527 2 : const GDALExtendedDataType &GetDataType() const override
9528 : {
9529 2 : return m_dt;
9530 : }
9531 :
9532 1 : bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
9533 : const GPtrDiff_t *,
9534 : const GDALExtendedDataType &bufferDataType,
9535 : void *pDstBuffer) const override
9536 : {
9537 1 : const char *pszStr = m_osValue.c_str();
9538 1 : GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
9539 : bufferDataType);
9540 1 : return true;
9541 : }
9542 : };
9543 :
9544 : std::vector<std::shared_ptr<GDALAttribute>>
9545 14 : GetAttributes(CSLConstList) const override
9546 : {
9547 14 : std::vector<std::shared_ptr<GDALAttribute>> res;
9548 14 : auto papszMD = m_poBand->GetMetadata();
9549 16 : for (auto iter = papszMD; iter && iter[0]; ++iter)
9550 : {
9551 2 : char *pszKey = nullptr;
9552 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9553 2 : if (pszKey && pszValue)
9554 : {
9555 : res.emplace_back(
9556 2 : std::make_shared<MDIAsAttribute>(pszKey, pszValue));
9557 : }
9558 2 : CPLFree(pszKey);
9559 : }
9560 14 : return res;
9561 : }
9562 : };
9563 :
9564 : /************************************************************************/
9565 : /* ReadWrite() */
9566 : /************************************************************************/
9567 :
9568 32 : bool GDALMDArrayFromRasterBand::ReadWrite(
9569 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
9570 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9571 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
9572 : {
9573 32 : constexpr size_t iDimX = 1;
9574 32 : constexpr size_t iDimY = 0;
9575 32 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
9576 : arrayStartIdx, count, arrayStep, bufferStride,
9577 32 : bufferDataType, pBuffer);
9578 : }
9579 :
9580 : /************************************************************************/
9581 : /* GDALMDRasterIOFromBand() */
9582 : /************************************************************************/
9583 :
9584 65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
9585 : size_t iDimX, size_t iDimY,
9586 : const GUInt64 *arrayStartIdx, const size_t *count,
9587 : const GInt64 *arrayStep,
9588 : const GPtrDiff_t *bufferStride,
9589 : const GDALExtendedDataType &bufferDataType,
9590 : void *pBuffer)
9591 : {
9592 65 : const auto eDT(bufferDataType.GetNumericDataType());
9593 65 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
9594 65 : const int nX =
9595 65 : arrayStep[iDimX] > 0
9596 65 : ? static_cast<int>(arrayStartIdx[iDimX])
9597 2 : : static_cast<int>(arrayStartIdx[iDimX] -
9598 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
9599 65 : const int nY =
9600 65 : arrayStep[iDimY] > 0
9601 65 : ? static_cast<int>(arrayStartIdx[iDimY])
9602 2 : : static_cast<int>(arrayStartIdx[iDimY] -
9603 2 : (count[iDimY] - 1) * -arrayStep[iDimY]);
9604 65 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
9605 65 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
9606 65 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
9607 65 : int nStrideXSign = 1;
9608 65 : if (arrayStep[iDimX] < 0)
9609 : {
9610 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
9611 2 : nStrideXSign = -1;
9612 : }
9613 65 : int nStrideYSign = 1;
9614 65 : if (arrayStep[iDimY] < 0)
9615 : {
9616 2 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
9617 2 : nStrideYSign = -1;
9618 : }
9619 :
9620 130 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
9621 65 : static_cast<int>(count[iDimX]),
9622 65 : static_cast<int>(count[iDimY]), eDT,
9623 : static_cast<GSpacing>(
9624 65 : nStrideXSign * bufferStride[iDimX] * nDTSize),
9625 : static_cast<GSpacing>(
9626 65 : nStrideYSign * bufferStride[iDimY] * nDTSize),
9627 65 : nullptr) == CE_None;
9628 : }
9629 :
9630 : /************************************************************************/
9631 : /* AsMDArray() */
9632 : /************************************************************************/
9633 :
9634 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
9635 : *
9636 : * The band must be linked to a GDALDataset. If this dataset is not already
9637 : * marked as shared, it will be, so that the returned array holds a reference
9638 : * to it.
9639 : *
9640 : * If the dataset has a geotransform attached, the X and Y dimensions of the
9641 : * returned array will have an associated indexing variable.
9642 : *
9643 : * This is the same as the C function GDALRasterBandAsMDArray().
9644 : *
9645 : * The "reverse" method is GDALMDArray::AsClassicDataset().
9646 : *
9647 : * @return a new array, or nullptr.
9648 : *
9649 : * @since GDAL 3.1
9650 : */
9651 23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
9652 : {
9653 23 : if (!poDS)
9654 : {
9655 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
9656 0 : return nullptr;
9657 : }
9658 23 : if (!poDS->GetShared())
9659 : {
9660 23 : poDS->MarkAsShared();
9661 : }
9662 : return GDALMDArrayFromRasterBand::Create(
9663 23 : poDS, const_cast<GDALRasterBand *>(this));
9664 : }
9665 :
9666 : /************************************************************************/
9667 : /* InterpolateAtPoint() */
9668 : /************************************************************************/
9669 :
9670 : /**
9671 : * \brief Interpolates the value between pixels using
9672 : * a resampling algorithm
9673 : *
9674 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
9675 : * @param dfLine line coordinate as a double, where interpolation should be done.
9676 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
9677 : * @param pdfRealValue pointer to real part of interpolated value
9678 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
9679 : *
9680 : * @return CE_None on success, or an error code on failure.
9681 : * @since GDAL 3.10
9682 : */
9683 :
9684 115 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
9685 : GDALRIOResampleAlg eInterpolation,
9686 : double *pdfRealValue,
9687 : double *pdfImagValue) const
9688 : {
9689 115 : if (eInterpolation != GRIORA_NearestNeighbour &&
9690 31 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
9691 : eInterpolation != GRIORA_CubicSpline)
9692 : {
9693 2 : CPLError(CE_Failure, CPLE_AppDefined,
9694 : "Only nearest, bilinear, cubic and cubicspline interpolation "
9695 : "methods "
9696 : "allowed");
9697 :
9698 2 : return CE_Failure;
9699 : }
9700 :
9701 113 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
9702 113 : if (!m_poPointsCache)
9703 51 : m_poPointsCache = new GDALDoublePointsCache();
9704 :
9705 : const bool res =
9706 113 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
9707 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
9708 :
9709 113 : return res ? CE_None : CE_Failure;
9710 : }
9711 :
9712 : /************************************************************************/
9713 : /* GDALRasterInterpolateAtPoint() */
9714 : /************************************************************************/
9715 :
9716 : /**
9717 : * \brief Interpolates the value between pixels using
9718 : * a resampling algorithm
9719 : *
9720 : * @see GDALRasterBand::InterpolateAtPoint()
9721 : * @since GDAL 3.10
9722 : */
9723 :
9724 105 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
9725 : double dfLine,
9726 : GDALRIOResampleAlg eInterpolation,
9727 : double *pdfRealValue, double *pdfImagValue)
9728 : {
9729 105 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
9730 :
9731 105 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9732 105 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
9733 105 : pdfRealValue, pdfImagValue);
9734 : }
|