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 1064390 : GDALRasterBand::GDALRasterBand()
50 : : GDALRasterBand(
51 1064390 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
52 : {
53 1064270 : }
54 :
55 : /** Constructor. Applications should never create GDALRasterBands directly.
56 : * @param bForceCachedIOIn Whether cached IO should be forced.
57 : */
58 1200120 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
59 1200120 : : bForceCachedIO(bForceCachedIOIn)
60 :
61 : {
62 1199940 : }
63 :
64 : /************************************************************************/
65 : /* ~GDALRasterBand() */
66 : /************************************************************************/
67 :
68 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
69 : instead destroy the GDALDataset. */
70 :
71 1200110 : GDALRasterBand::~GDALRasterBand()
72 :
73 : {
74 1200120 : if (poDS && poDS->IsMarkedSuppressOnClose())
75 : {
76 433 : if (poBandBlockCache)
77 384 : poBandBlockCache->DisableDirtyBlockWriting();
78 : }
79 1200120 : GDALRasterBand::FlushCache(true);
80 :
81 1200120 : delete poBandBlockCache;
82 :
83 1200120 : if (static_cast<GIntBig>(nBlockReads) >
84 1200120 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
85 214 : nBand == 1 && poDS != nullptr)
86 : {
87 302 : CPLDebug(
88 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
89 151 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
90 151 : poDS->GetDescription());
91 : }
92 :
93 1200120 : InvalidateMaskBand();
94 1200110 : nBand = -nBand;
95 :
96 1200110 : delete m_poPointsCache;
97 1200110 : }
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 3738770 : 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 3738770 : if (psExtraArg == nullptr)
330 : {
331 3647570 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
332 3647570 : psExtraArg = &sExtraArg;
333 : }
334 91200 : 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 3738770 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
343 : nBufYSize);
344 :
345 3746030 : 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 3746030 : 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 3746030 : if (eRWFlag == GF_Write)
369 : {
370 213027 : 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 213027 : 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 3746030 : if (nPixelSpace == 0)
393 : {
394 3654210 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
395 : }
396 :
397 3748520 : if (nLineSpace == 0)
398 : {
399 3650230 : nLineSpace = nPixelSpace * nBufXSize;
400 : }
401 :
402 : /* -------------------------------------------------------------------- */
403 : /* Do some validation of parameters. */
404 : /* -------------------------------------------------------------------- */
405 3748520 : 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 3748510 : 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 3748510 : 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 3748510 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
436 :
437 : CPLErr eErr;
438 3738980 : if (bForceCachedIO)
439 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
440 : pData, nBufXSize, nBufYSize, eBufType,
441 : nPixelSpace, nLineSpace, psExtraArg);
442 : else
443 : eErr =
444 3743910 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
445 3738960 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
446 :
447 3743930 : if (bCallLeaveReadWrite)
448 219682 : LeaveReadWrite();
449 :
450 3737530 : 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 3436840 : 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 3436840 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
474 :
475 3436840 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
476 :
477 3436560 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
478 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
479 3433280 : 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 35111 : 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 35111 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
502 :
503 35111 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
504 :
505 35111 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
506 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
507 35111 : 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 47954 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1328 : int *pnXValid, int *pnYValid) const
1329 : {
1330 95907 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1331 95905 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1332 95902 : nYBlockOff < 0 || nBlockYSize == 0 ||
1333 47951 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1334 : {
1335 4 : return CE_Failure;
1336 : }
1337 :
1338 47950 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1339 47950 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1340 :
1341 47950 : *pnXValid = nBlockXSize;
1342 47950 : *pnYValid = nBlockYSize;
1343 :
1344 47950 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1345 : {
1346 46340 : *pnXValid = nRasterXSize - nXPixelOff;
1347 : }
1348 :
1349 47950 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1350 : {
1351 3434 : *pnYValid = nRasterYSize - nYPixelOff;
1352 : }
1353 :
1354 47950 : 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 2150 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1414 : {
1415 2150 : 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 7617950 : GDALDataType GDALRasterBand::GetRasterDataType() const
1431 :
1432 : {
1433 7617950 : 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 899478 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1447 :
1448 : {
1449 899478 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1450 :
1451 899478 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1452 899478 : 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 5039680 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1482 :
1483 : {
1484 5039680 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1485 : {
1486 3575 : ReportError(CE_Failure, CPLE_AppDefined,
1487 3575 : "Invalid block dimension : %d * %d", nBlockXSize,
1488 3575 : nBlockYSize);
1489 0 : if (pnXSize != nullptr)
1490 0 : *pnXSize = 0;
1491 0 : if (pnYSize != nullptr)
1492 0 : *pnYSize = 0;
1493 : }
1494 : else
1495 : {
1496 5036110 : if (pnXSize != nullptr)
1497 5030710 : *pnXSize = nBlockXSize;
1498 5036110 : if (pnYSize != nullptr)
1499 5031080 : *pnYSize = nBlockYSize;
1500 : }
1501 5036110 : }
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 40280 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1514 : int *pnYSize)
1515 :
1516 : {
1517 40280 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1518 :
1519 40280 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1520 40280 : poBand->GetBlockSize(pnXSize, pnYSize);
1521 : }
1522 :
1523 : /************************************************************************/
1524 : /* InitBlockInfo() */
1525 : /************************************************************************/
1526 :
1527 : //! @cond Doxygen_Suppress
1528 3324920 : int GDALRasterBand::InitBlockInfo()
1529 :
1530 : {
1531 3324920 : if (poBandBlockCache != nullptr)
1532 3291170 : 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 33749 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1537 : {
1538 20 : ReportError(CE_Failure, CPLE_AppDefined,
1539 : "Invalid block dimension : %d * %d", nBlockXSize,
1540 : nBlockYSize);
1541 0 : return FALSE;
1542 : }
1543 :
1544 33729 : 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 33729 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1553 33751 : if (nDataTypeSize == 0)
1554 : {
1555 19 : 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 33732 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1576 33732 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1577 :
1578 : const char *pszBlockStrategy =
1579 33732 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1580 33764 : bool bUseArray = true;
1581 33764 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1582 : {
1583 33724 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1584 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1585 : {
1586 33705 : GUIntBig nBlockCount =
1587 33705 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1588 33705 : if (poDS != nullptr)
1589 33517 : nBlockCount *= poDS->GetRasterCount();
1590 33705 : 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 33724 : }
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 33764 : if (bUseArray)
1605 33694 : 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 33763 : if (poBandBlockCache == nullptr)
1613 0 : return FALSE;
1614 33763 : 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 3862660 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1636 :
1637 : {
1638 3907250 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1639 44598 : poBandBlockCache)
1640 2101 : poBandBlockCache->DisableDirtyBlockWriting();
1641 :
1642 3857220 : CPLErr eGlobalErr = eFlushBlockErr;
1643 :
1644 3857220 : 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 3857220 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1653 3696930 : return eGlobalErr;
1654 :
1655 160291 : 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 130 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1669 :
1670 : {
1671 130 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1672 :
1673 130 : 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 29595 : 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 29595 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1773 29595 : 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 29595 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1786 : {
1787 29595 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1788 29595 : 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 2302 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1804 : int bWriteDirtyBlock)
1805 :
1806 : {
1807 2302 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1808 0 : return (CE_Failure);
1809 :
1810 : /* -------------------------------------------------------------------- */
1811 : /* Validate the request */
1812 : /* -------------------------------------------------------------------- */
1813 2302 : 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 2302 : 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 2302 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1834 2302 : 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 9966380 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1862 : int nYBlockOff)
1863 :
1864 : {
1865 9966380 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1866 66214 : return nullptr;
1867 :
1868 : /* -------------------------------------------------------------------- */
1869 : /* Validate the request */
1870 : /* -------------------------------------------------------------------- */
1871 9900260 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1872 : {
1873 45 : 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 9900220 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1882 : {
1883 25 : 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 9900190 : 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 9765150 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1929 : int nYBlockOff,
1930 : int bJustInitialize)
1931 :
1932 : {
1933 : /* -------------------------------------------------------------------- */
1934 : /* Try and fetch from cache. */
1935 : /* -------------------------------------------------------------------- */
1936 9765150 : 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 9765510 : if (poBlock == nullptr)
1944 : {
1945 3148210 : if (!InitBlockInfo())
1946 0 : return (nullptr);
1947 :
1948 : /* --------------------------------------------------------------------
1949 : */
1950 : /* Validate the request */
1951 : /* --------------------------------------------------------------------
1952 : */
1953 3148140 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1954 : {
1955 26 : 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 3148110 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1964 : {
1965 66 : 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 3148050 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1974 3148320 : if (poBlock == nullptr)
1975 0 : return nullptr;
1976 :
1977 3148320 : 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 3148360 : if (poDS)
1992 3147630 : poDS->TemporarilyDropReadWriteLock();
1993 : /* allocate data space */
1994 3148340 : CPLErr eErr = poBlock->Internalize();
1995 3148500 : if (poDS)
1996 3147760 : poDS->ReacquireReadWriteLock();
1997 3148470 : if (eErr != CE_None)
1998 : {
1999 0 : poBlock->DropLock();
2000 0 : delete poBlock;
2001 0 : return nullptr;
2002 : }
2003 :
2004 3148470 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2005 : {
2006 0 : poBlock->DropLock();
2007 0 : delete poBlock;
2008 0 : return nullptr;
2009 : }
2010 :
2011 3148450 : if (!bJustInitialize)
2012 : {
2013 2791460 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2014 2791430 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2015 2791450 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2016 2791480 : if (bCallLeaveReadWrite)
2017 125946 : LeaveReadWrite();
2018 2791470 : if (eErr != CE_None)
2019 : {
2020 1152 : poBlock->DropLock();
2021 1152 : FlushBlock(nXBlockOff, nYBlockOff);
2022 1152 : ReportError(CE_Failure, CPLE_AppDefined,
2023 : "IReadBlock failed at X offset %d, Y offset %d%s",
2024 : nXBlockOff, nYBlockOff,
2025 1152 : (nErrorCounter != CPLGetErrorCounter())
2026 1150 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2027 : : "");
2028 1152 : return nullptr;
2029 : }
2030 :
2031 2790320 : nBlockReads++;
2032 2790320 : if (static_cast<GIntBig>(nBlockReads) ==
2033 2790320 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2034 214 : 1 &&
2035 214 : nBand == 1 && poDS != nullptr)
2036 : {
2037 151 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2038 151 : poDS->GetDescription());
2039 : }
2040 : }
2041 : }
2042 :
2043 9764570 : 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 169205 : 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 169205 : if (eAccess == GA_ReadOnly)
2082 : {
2083 2 : ReportError(CE_Failure, CPLE_NoWriteAccess,
2084 : "Attempt to write to read only dataset in "
2085 : "GDALRasterBand::Fill().");
2086 2 : return CE_Failure;
2087 : }
2088 :
2089 : // Make sure block parameters are set.
2090 169203 : if (!InitBlockInfo())
2091 0 : return CE_Failure;
2092 :
2093 : // Allocate the source block.
2094 169203 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2095 169203 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2096 169203 : auto blockByteSize = blockSize * elementSize;
2097 : unsigned char *srcBlock =
2098 169203 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2099 169203 : 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 169203 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2110 169203 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2111 : elementSize, blockSize);
2112 :
2113 169203 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2114 :
2115 : // Write block to block cache
2116 637385 : for (int j = 0; j < nBlocksPerColumn; ++j)
2117 : {
2118 1230700 : for (int i = 0; i < nBlocksPerRow; ++i)
2119 : {
2120 762515 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2121 762515 : 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 762515 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2130 762515 : destBlock->MarkDirty();
2131 762515 : destBlock->DropLock();
2132 : }
2133 : }
2134 :
2135 169203 : if (bCallLeaveReadWrite)
2136 168726 : LeaveReadWrite();
2137 :
2138 : // Free up the source block
2139 169203 : VSIFree(srcBlock);
2140 :
2141 169203 : 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 169171 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2154 : double dfImaginaryValue)
2155 : {
2156 169171 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2157 :
2158 169171 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2159 169171 : 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 2499 : GDALAccess GDALRasterBand::GetAccess()
2175 :
2176 : {
2177 2499 : 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 1858 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2191 :
2192 : {
2193 1858 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2194 :
2195 1858 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2196 1858 : 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 234 : char **GDALRasterBand::GetCategoryNames()
2221 :
2222 : {
2223 234 : 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 175 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2237 :
2238 : {
2239 175 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2240 :
2241 175 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2242 175 : 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 31403 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2325 :
2326 : {
2327 31403 : if (pbSuccess != nullptr)
2328 31403 : *pbSuccess = FALSE;
2329 :
2330 31403 : 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 413784 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2344 : int *pbSuccess)
2345 :
2346 : {
2347 413784 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2348 :
2349 413784 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2350 413784 : 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 691 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2542 : double dfValue)
2543 :
2544 : {
2545 691 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2546 :
2547 691 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2548 691 : 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 492 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2761 :
2762 : {
2763 492 : const char *pszValue = nullptr;
2764 :
2765 492 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2766 : {
2767 46 : if (pbSuccess != nullptr)
2768 41 : *pbSuccess = TRUE;
2769 :
2770 46 : return CPLAtofM(pszValue);
2771 : }
2772 :
2773 446 : if (pbSuccess != nullptr)
2774 414 : *pbSuccess = FALSE;
2775 :
2776 446 : switch (eDataType)
2777 : {
2778 317 : case GDT_Byte:
2779 : {
2780 317 : EnablePixelTypeSignedByteWarning(false);
2781 : const char *pszPixelType =
2782 317 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2783 317 : EnablePixelTypeSignedByteWarning(true);
2784 317 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2785 0 : return 127;
2786 :
2787 317 : 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 17 : case GDT_Int32:
2801 : case GDT_CInt32:
2802 17 : 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 24 : case GDT_Float64:
2818 : case GDT_CFloat64:
2819 24 : 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 248 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2839 :
2840 : {
2841 248 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2842 :
2843 248 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2844 248 : 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 500 : double GDALRasterBand::GetMinimum(int *pbSuccess)
2866 :
2867 : {
2868 500 : const char *pszValue = nullptr;
2869 :
2870 500 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
2871 : {
2872 51 : if (pbSuccess != nullptr)
2873 46 : *pbSuccess = TRUE;
2874 :
2875 51 : return CPLAtofM(pszValue);
2876 : }
2877 :
2878 449 : if (pbSuccess != nullptr)
2879 417 : *pbSuccess = FALSE;
2880 :
2881 449 : switch (eDataType)
2882 : {
2883 320 : case GDT_Byte:
2884 : {
2885 320 : EnablePixelTypeSignedByteWarning(false);
2886 : const char *pszPixelType =
2887 320 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2888 320 : EnablePixelTypeSignedByteWarning(true);
2889 320 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2890 0 : return -128;
2891 :
2892 320 : 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 17 : case GDT_Int32:
2907 : case GDT_CInt32:
2908 17 : 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 24 : case GDT_Float64:
2924 : case GDT_CFloat64:
2925 24 : 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 258 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
2945 :
2946 : {
2947 258 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
2948 :
2949 258 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2950 258 : 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 5048 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
2987 :
2988 : {
2989 5048 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
2990 :
2991 5048 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2992 5048 : 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 1765 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3033 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3034 :
3035 : {
3036 1765 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3037 :
3038 1765 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3039 1765 : 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 1819 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3075 :
3076 : {
3077 1819 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3078 :
3079 1819 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3080 1819 : 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 231 : int GDALRasterBand::HasArbitraryOverviews()
3156 :
3157 : {
3158 231 : return FALSE;
3159 : }
3160 :
3161 : /************************************************************************/
3162 : /* GDALHasArbitraryOverviews() */
3163 : /************************************************************************/
3164 :
3165 : /**
3166 : * \brief Check for arbitrary overviews.
3167 : *
3168 : * @see GDALRasterBand::HasArbitraryOverviews()
3169 : */
3170 :
3171 165 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3172 :
3173 : {
3174 165 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3175 :
3176 165 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3177 165 : 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 660383 : int GDALRasterBand::GetOverviewCount()
3193 :
3194 : {
3195 1315910 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3196 655524 : poDS->AreOverviewsEnabled())
3197 655524 : return poDS->oOvManager.GetOverviewCount(nBand);
3198 :
3199 4859 : 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 3185 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3213 :
3214 : {
3215 3185 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3216 :
3217 3185 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3218 3185 : 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 5503 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3256 :
3257 : {
3258 5503 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3259 :
3260 5503 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3261 5503 : 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 343 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3456 :
3457 : {
3458 343 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3459 :
3460 343 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3461 343 : 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 65 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3505 : double dfNewOffset)
3506 :
3507 : {
3508 65 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3509 :
3510 65 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3511 65 : 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 341 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3562 :
3563 : {
3564 341 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3565 :
3566 341 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3567 341 : 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 66 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3612 :
3613 : {
3614 66 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3615 :
3616 66 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3617 66 : 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 1324 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3654 :
3655 : {
3656 1324 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3657 :
3658 1324 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3659 1324 : 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 6760220 : int GDALRasterBand::GetXSize() const
3729 :
3730 : {
3731 6760220 : return nRasterXSize;
3732 : }
3733 :
3734 : /************************************************************************/
3735 : /* GDALGetRasterBandXSize() */
3736 : /************************************************************************/
3737 :
3738 : /**
3739 : * \brief Fetch XSize of raster.
3740 : *
3741 : * @see GDALRasterBand::GetXSize()
3742 : */
3743 :
3744 54102 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3745 :
3746 : {
3747 54102 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3748 :
3749 54102 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3750 54102 : 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 3288910 : int GDALRasterBand::GetYSize() const
3766 :
3767 : {
3768 3288910 : return nRasterYSize;
3769 : }
3770 :
3771 : /************************************************************************/
3772 : /* GDALGetRasterBandYSize() */
3773 : /************************************************************************/
3774 :
3775 : /**
3776 : * \brief Fetch YSize of raster.
3777 : *
3778 : * @see GDALRasterBand::GetYSize()
3779 : */
3780 :
3781 53479 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3782 :
3783 : {
3784 53479 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3785 :
3786 53479 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3787 53479 : 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 19253 : int GDALRasterBand::GetBand() const
3808 :
3809 : {
3810 19253 : 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 3857240 : GDALDataset *GDALRasterBand::GetDataset() const
3849 :
3850 : {
3851 3857240 : 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 311 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
3865 :
3866 : {
3867 311 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
3868 :
3869 311 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3870 311 : return GDALDataset::ToHandle(poBand->GetDataset());
3871 : }
3872 :
3873 : /************************************************************************/
3874 : /* ComputeFloatNoDataValue() */
3875 : /************************************************************************/
3876 :
3877 2037 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
3878 : double dfNoDataValue,
3879 : int &bGotNoDataValue,
3880 : float &fNoDataValue,
3881 : bool &bGotFloatNoDataValue)
3882 : {
3883 2037 : 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 2037 : }
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 39 : 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 39 : CPLAssert(nullptr != panHistogram);
3946 :
3947 39 : if (pfnProgress == nullptr)
3948 26 : pfnProgress = GDALDummyProgress;
3949 :
3950 : /* -------------------------------------------------------------------- */
3951 : /* If we have overviews, use them for the histogram. */
3952 : /* -------------------------------------------------------------------- */
3953 39 : 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 39 : 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 39 : 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 34 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3987 :
3988 34 : const double dfScale = nBuckets / (dfMax - dfMin);
3989 34 : 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 29 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
3997 :
3998 29 : int bGotNoDataValue = FALSE;
3999 29 : const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
4000 29 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4001 29 : bool bGotFloatNoDataValue = false;
4002 29 : float fNoDataValue = 0.0f;
4003 29 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4004 : fNoDataValue, bGotFloatNoDataValue);
4005 29 : GDALRasterBand *poMaskBand = nullptr;
4006 29 : if (!bGotNoDataValue)
4007 : {
4008 28 : const int l_nMaskFlags = GetMaskFlags();
4009 29 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
4010 1 : GetColorInterpretation() != GCI_AlphaBand)
4011 : {
4012 1 : poMaskBand = GetMaskBand();
4013 : }
4014 : }
4015 :
4016 29 : bool bSignedByte = false;
4017 29 : if (eDataType == GDT_Byte)
4018 : {
4019 22 : EnablePixelTypeSignedByteWarning(false);
4020 : const char *pszPixelType =
4021 22 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4022 22 : EnablePixelTypeSignedByteWarning(true);
4023 22 : bSignedByte =
4024 22 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4025 : }
4026 :
4027 29 : 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 29 : 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 29 : int nSampleRate = 1;
4239 29 : 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 29 : GByte *pabyMaskData = nullptr;
4252 29 : 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 29 : for (GIntBig iSampleBlock = 0;
4268 136 : iSampleBlock <
4269 136 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4270 107 : iSampleBlock += nSampleRate)
4271 : {
4272 107 : if (!pfnProgress(
4273 107 : static_cast<double>(iSampleBlock) /
4274 107 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4275 : "Compute Histogram", pProgressData))
4276 : {
4277 0 : CPLFree(pabyMaskData);
4278 0 : return CE_Failure;
4279 : }
4280 :
4281 107 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4282 107 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4283 :
4284 107 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4285 107 : if (poBlock == nullptr)
4286 : {
4287 0 : CPLFree(pabyMaskData);
4288 0 : return CE_Failure;
4289 : }
4290 :
4291 107 : void *pData = poBlock->GetDataRef();
4292 :
4293 107 : int nXCheck = 0, nYCheck = 0;
4294 107 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4295 :
4296 108 : 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 107 : if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4309 85 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4310 82 : nXCheck == nBlockXSize && nBuckets == 256)
4311 : {
4312 82 : const GPtrDiff_t nPixels =
4313 82 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4314 82 : GByte *pabyData = static_cast<GByte *>(pData);
4315 :
4316 72134 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4317 : {
4318 72052 : if (pabyMaskData && pabyMaskData[i] == 0)
4319 0 : continue;
4320 72564 : if (!(bGotNoDataValue &&
4321 72052 : (pabyData[i] == static_cast<GByte>(dfNoDataValue))))
4322 : {
4323 71796 : panHistogram[pabyData[i]]++;
4324 : }
4325 : }
4326 :
4327 82 : poBlock->DropLock();
4328 82 : 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 29 : CPLFree(pabyMaskData);
4471 : }
4472 :
4473 29 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4474 :
4475 29 : 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 22 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4603 : int *pnBuckets,
4604 : GUIntBig **ppanHistogram, int bForce,
4605 : GDALProgressFunc pfnProgress,
4606 : void *pProgressData)
4607 :
4608 : {
4609 22 : CPLAssert(nullptr != pnBuckets);
4610 22 : CPLAssert(nullptr != ppanHistogram);
4611 22 : CPLAssert(nullptr != pdfMin);
4612 22 : CPLAssert(nullptr != pdfMax);
4613 :
4614 22 : *pnBuckets = 0;
4615 22 : *ppanHistogram = nullptr;
4616 :
4617 22 : if (!bForce)
4618 6 : return CE_Warning;
4619 :
4620 16 : const int nBuckets = 256;
4621 :
4622 16 : bool bSignedByte = false;
4623 16 : if (eDataType == GDT_Byte)
4624 : {
4625 16 : EnablePixelTypeSignedByteWarning(false);
4626 : const char *pszPixelType =
4627 16 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4628 16 : EnablePixelTypeSignedByteWarning(true);
4629 16 : bSignedByte =
4630 16 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4631 : }
4632 :
4633 16 : if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4634 : {
4635 16 : *pdfMin = -0.5;
4636 16 : *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 16 : *ppanHistogram =
4652 16 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4653 16 : 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 16 : *pnBuckets = nBuckets;
4661 32 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4662 16 : TRUE, FALSE, pfnProgress, pProgressData);
4663 16 : if (eErr != CE_None)
4664 : {
4665 0 : *pnBuckets = 0;
4666 : }
4667 16 : 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 28 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
4755 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
4756 : GDALProgressFunc pfnProgress, void *pProgressData)
4757 :
4758 : {
4759 28 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4760 28 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4761 28 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4762 28 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4763 28 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4764 :
4765 28 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4766 28 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
4767 28 : 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 42134 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
4820 : int /*nYSize*/, int /*nBufXSize*/,
4821 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
4822 : char ** /*papszOptions*/)
4823 : {
4824 42134 : 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 611 : 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 1222 : if ((pdfMin == nullptr ||
4914 611 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
4915 202 : (pdfMax == nullptr ||
4916 202 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
4917 1424 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
4918 202 : (pdfStdDev == nullptr ||
4919 202 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
4920 : {
4921 202 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
4922 : {
4923 195 : if (pdfMin != nullptr)
4924 195 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
4925 195 : if (pdfMax != nullptr)
4926 195 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
4927 195 : if (pdfMean != nullptr)
4928 195 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
4929 195 : if (pdfStdDev != nullptr)
4930 195 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
4931 :
4932 195 : return CE_None;
4933 : }
4934 : }
4935 :
4936 : /* -------------------------------------------------------------------- */
4937 : /* Does the driver already know the min/max? */
4938 : /* -------------------------------------------------------------------- */
4939 416 : 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 416 : if (!bForce)
4961 161 : return CE_Warning;
4962 : else
4963 255 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
4964 255 : GDALDummyProgress, nullptr);
4965 : }
4966 :
4967 : /************************************************************************/
4968 : /* GDALGetRasterStatistics() */
4969 : /************************************************************************/
4970 :
4971 : /**
4972 : * \brief Fetch image statistics.
4973 : *
4974 : * @see GDALRasterBand::GetStatistics()
4975 : */
4976 :
4977 260 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
4978 : int bForce, double *pdfMin,
4979 : double *pdfMax, double *pdfMean,
4980 : double *pdfStdDev)
4981 :
4982 : {
4983 260 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
4984 :
4985 260 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4986 260 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
4987 260 : pdfStdDev);
4988 : }
4989 :
4990 : /************************************************************************/
4991 : /* GDALUInt128 */
4992 : /************************************************************************/
4993 :
4994 : #ifdef HAVE_UINT128_T
4995 : class GDALUInt128
4996 : {
4997 : __uint128_t val;
4998 :
4999 627 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5000 : {
5001 627 : }
5002 :
5003 : public:
5004 418 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5005 : {
5006 : // Evaluates to just a single mul on x86_64
5007 418 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5008 : }
5009 :
5010 209 : GDALUInt128 operator-(const GDALUInt128 &other) const
5011 : {
5012 209 : return GDALUInt128(val - other.val);
5013 : }
5014 :
5015 200 : operator double() const
5016 : {
5017 200 : return static_cast<double>(val);
5018 : }
5019 : };
5020 : #else
5021 :
5022 : #if defined(_MSC_VER) && defined(_M_X64)
5023 : #include <intrin.h>
5024 : #endif
5025 :
5026 : class GDALUInt128
5027 : {
5028 : GUIntBig low, high;
5029 :
5030 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5031 : {
5032 : }
5033 :
5034 : public:
5035 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5036 : {
5037 : #if defined(_MSC_VER) && defined(_M_X64)
5038 : GUIntBig highRes;
5039 : GUIntBig lowRes = _umul128(first, second, &highRes);
5040 : return GDALUInt128(lowRes, highRes);
5041 : #else
5042 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5043 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5044 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5045 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5046 : GUIntBig highRes = 0;
5047 : const GUIntBig firstLowSecondHigh =
5048 : static_cast<GUIntBig>(firstLow) * secondHigh;
5049 : const GUIntBig firstHighSecondLow =
5050 : static_cast<GUIntBig>(firstHigh) * secondLow;
5051 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5052 : if (middleTerm < firstLowSecondHigh) // check for overflow
5053 : highRes += static_cast<GUIntBig>(1) << 32;
5054 : const GUIntBig firstLowSecondLow =
5055 : static_cast<GUIntBig>(firstLow) * secondLow;
5056 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5057 : if (lowRes < firstLowSecondLow) // check for overflow
5058 : highRes++;
5059 : highRes +=
5060 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5061 : return GDALUInt128(lowRes, highRes);
5062 : #endif
5063 : }
5064 :
5065 : GDALUInt128 operator-(const GDALUInt128 &other) const
5066 : {
5067 : GUIntBig highRes = high - other.high;
5068 : GUIntBig lowRes = low - other.low;
5069 : if (lowRes > low) // check for underflow
5070 : --highRes;
5071 : return GDALUInt128(lowRes, highRes);
5072 : }
5073 :
5074 : operator double() const
5075 : {
5076 : const double twoPow64 = 18446744073709551616.0;
5077 : return high * twoPow64 + low;
5078 : }
5079 : };
5080 : #endif
5081 :
5082 : /************************************************************************/
5083 : /* ComputeStatisticsInternal() */
5084 : /************************************************************************/
5085 :
5086 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5087 : // not needed.
5088 : #define static_cast_for_coverity_scan static_cast
5089 :
5090 : // The rationale for below optimizations is detailed in statistics.txt
5091 :
5092 : // Use with T = GByte or GUInt16 only !
5093 : template <class T, bool COMPUTE_OTHER_STATS>
5094 : struct ComputeStatisticsInternalGeneric
5095 : {
5096 182 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5097 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5098 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5099 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5100 : {
5101 : static_assert(std::is_same<T, GByte>::value ||
5102 : std::is_same<T, GUInt16>::value,
5103 : "bad type for T");
5104 182 : if (bHasNoData)
5105 : {
5106 : // General case
5107 386 : for (int iY = 0; iY < nYCheck; iY++)
5108 : {
5109 81751 : for (int iX = 0; iX < nXCheck; iX++)
5110 : {
5111 81468 : const GPtrDiff_t iOffset =
5112 81468 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5113 81468 : const GUInt32 nValue = pData[iOffset];
5114 81468 : if (nValue == nNoDataValue)
5115 175 : continue;
5116 81293 : if (nValue < nMin)
5117 26 : nMin = nValue;
5118 81293 : if (nValue > nMax)
5119 57 : nMax = nValue;
5120 : if constexpr (COMPUTE_OTHER_STATS)
5121 : {
5122 79657 : nValidCount++;
5123 79657 : nSum += nValue;
5124 79657 : nSumSquare +=
5125 79657 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5126 79657 : nValue;
5127 : }
5128 : }
5129 : }
5130 : if constexpr (COMPUTE_OTHER_STATS)
5131 : {
5132 20 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5133 : }
5134 : }
5135 88 : else if (nMin == std::numeric_limits<T>::min() &&
5136 9 : nMax == std::numeric_limits<T>::max())
5137 : {
5138 : if constexpr (COMPUTE_OTHER_STATS)
5139 : {
5140 : // Optimization when there is no nodata and we know we have already
5141 : // reached the min and max
5142 208 : for (int iY = 0; iY < nYCheck; iY++)
5143 : {
5144 : int iX;
5145 1002 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5146 : {
5147 800 : const GPtrDiff_t iOffset =
5148 800 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5149 800 : const GUIntBig nValue = pData[iOffset];
5150 800 : const GUIntBig nValue2 = pData[iOffset + 1];
5151 800 : const GUIntBig nValue3 = pData[iOffset + 2];
5152 800 : const GUIntBig nValue4 = pData[iOffset + 3];
5153 800 : nSum += nValue;
5154 800 : nSumSquare += nValue * nValue;
5155 800 : nSum += nValue2;
5156 800 : nSumSquare += nValue2 * nValue2;
5157 800 : nSum += nValue3;
5158 800 : nSumSquare += nValue3 * nValue3;
5159 800 : nSum += nValue4;
5160 800 : nSumSquare += nValue4 * nValue4;
5161 : }
5162 207 : for (; iX < nXCheck; ++iX)
5163 : {
5164 5 : const GPtrDiff_t iOffset =
5165 5 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5166 5 : const GUIntBig nValue = pData[iOffset];
5167 5 : nSum += nValue;
5168 5 : nSumSquare += nValue * nValue;
5169 : }
5170 : }
5171 6 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5172 6 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5173 : }
5174 : }
5175 : else
5176 : {
5177 3366 : for (int iY = 0; iY < nYCheck; iY++)
5178 : {
5179 : int iX;
5180 635062 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5181 : {
5182 631769 : const GPtrDiff_t iOffset =
5183 631769 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5184 631769 : const GUInt32 nValue = pData[iOffset];
5185 631769 : const GUInt32 nValue2 = pData[iOffset + 1];
5186 631769 : if (nValue < nValue2)
5187 : {
5188 2160 : if (nValue < nMin)
5189 48 : nMin = nValue;
5190 2160 : if (nValue2 > nMax)
5191 108 : nMax = nValue2;
5192 : }
5193 : else
5194 : {
5195 629609 : if (nValue2 < nMin)
5196 61 : nMin = nValue2;
5197 629609 : if (nValue > nMax)
5198 212 : nMax = nValue;
5199 : }
5200 : if constexpr (COMPUTE_OTHER_STATS)
5201 : {
5202 624719 : nSum += nValue;
5203 624719 : nSumSquare +=
5204 624719 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5205 624719 : nValue;
5206 624719 : nSum += nValue2;
5207 624719 : nSumSquare +=
5208 624719 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5209 624719 : nValue2;
5210 : }
5211 : }
5212 3293 : if (iX < nXCheck)
5213 : {
5214 9 : const GPtrDiff_t iOffset =
5215 9 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5216 9 : const GUInt32 nValue = pData[iOffset];
5217 9 : if (nValue < nMin)
5218 6 : nMin = nValue;
5219 9 : if (nValue > nMax)
5220 6 : nMax = nValue;
5221 : if (COMPUTE_OTHER_STATS)
5222 : {
5223 9 : nSum += nValue;
5224 9 : nSumSquare +=
5225 9 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5226 9 : nValue;
5227 : }
5228 : }
5229 : }
5230 : if constexpr (COMPUTE_OTHER_STATS)
5231 : {
5232 28 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5233 28 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5234 : }
5235 : }
5236 182 : }
5237 : };
5238 :
5239 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5240 : // using 64bit accumulators in internal loops. This also slightly helps in
5241 : // 64bit mode.
5242 : template <bool COMPUTE_OTHER_STATS>
5243 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5244 : {
5245 11756 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5246 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5247 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5248 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5249 : {
5250 11756 : int nOuterLoops = nXCheck / 65536;
5251 11756 : if (nXCheck % 65536)
5252 11756 : nOuterLoops++;
5253 :
5254 11756 : if (bHasNoData)
5255 : {
5256 : // General case
5257 19549 : for (int iY = 0; iY < nYCheck; iY++)
5258 : {
5259 10938 : int iX = 0;
5260 21876 : for (int k = 0; k < nOuterLoops; k++)
5261 : {
5262 10938 : int iMax = iX + 65536;
5263 10938 : if (iMax > nXCheck)
5264 10938 : iMax = nXCheck;
5265 10938 : GUInt32 nSum32bit = 0;
5266 10938 : GUInt32 nSumSquare32bit = 0;
5267 10938 : GUInt32 nValidCount32bit = 0;
5268 10938 : GUInt32 nSampleCount32bit = 0;
5269 16705781 : for (; iX < iMax; iX++)
5270 : {
5271 16694931 : const GPtrDiff_t iOffset =
5272 16694931 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5273 16694931 : const GUInt32 nValue = pData[iOffset];
5274 :
5275 16694931 : nSampleCount32bit++;
5276 16694931 : if (nValue == nNoDataValue)
5277 16353480 : continue;
5278 341396 : if (nValue < nMin)
5279 343 : nMin = nValue;
5280 341396 : if (nValue > nMax)
5281 828 : nMax = nValue;
5282 : if constexpr (COMPUTE_OTHER_STATS)
5283 : {
5284 16951 : nValidCount32bit++;
5285 16951 : nSum32bit += nValue;
5286 16951 : nSumSquare32bit += nValue * nValue;
5287 : }
5288 : }
5289 : if constexpr (COMPUTE_OTHER_STATS)
5290 : {
5291 650 : nSampleCount += nSampleCount32bit;
5292 650 : nValidCount += nValidCount32bit;
5293 650 : nSum += nSum32bit;
5294 650 : nSumSquare += nSumSquare32bit;
5295 : }
5296 : }
5297 : }
5298 : }
5299 3145 : else if (nMin == 0 && nMax == 255)
5300 : {
5301 : if constexpr (COMPUTE_OTHER_STATS)
5302 : {
5303 : // Optimization when there is no nodata and we know we have already
5304 : // reached the min and max
5305 2644 : for (int iY = 0; iY < nYCheck; iY++)
5306 : {
5307 2617 : int iX = 0;
5308 5234 : for (int k = 0; k < nOuterLoops; k++)
5309 : {
5310 2617 : int iMax = iX + 65536;
5311 2617 : if (iMax > nXCheck)
5312 2617 : iMax = nXCheck;
5313 2617 : GUInt32 nSum32bit = 0;
5314 2617 : GUInt32 nSumSquare32bit = 0;
5315 176297 : for (; iX + 3 < iMax; iX += 4)
5316 : {
5317 173680 : const GPtrDiff_t iOffset =
5318 173680 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5319 173680 : const GUInt32 nValue = pData[iOffset];
5320 173680 : const GUInt32 nValue2 = pData[iOffset + 1];
5321 173680 : const GUInt32 nValue3 = pData[iOffset + 2];
5322 173680 : const GUInt32 nValue4 = pData[iOffset + 3];
5323 173680 : nSum32bit += nValue;
5324 173680 : nSumSquare32bit += nValue * nValue;
5325 173680 : nSum32bit += nValue2;
5326 173680 : nSumSquare32bit += nValue2 * nValue2;
5327 173680 : nSum32bit += nValue3;
5328 173680 : nSumSquare32bit += nValue3 * nValue3;
5329 173680 : nSum32bit += nValue4;
5330 173680 : nSumSquare32bit += nValue4 * nValue4;
5331 : }
5332 2617 : nSum += nSum32bit;
5333 2617 : nSumSquare += nSumSquare32bit;
5334 : }
5335 2620 : for (; iX < nXCheck; ++iX)
5336 : {
5337 3 : const GPtrDiff_t iOffset =
5338 3 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5339 3 : const GUIntBig nValue = pData[iOffset];
5340 3 : nSum += nValue;
5341 3 : nSumSquare += nValue * nValue;
5342 : }
5343 : }
5344 27 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5345 27 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5346 27 : }
5347 : }
5348 : else
5349 : {
5350 7895 : for (int iY = 0; iY < nYCheck; iY++)
5351 : {
5352 4777 : int iX = 0;
5353 9554 : for (int k = 0; k < nOuterLoops; k++)
5354 : {
5355 4777 : int iMax = iX + 65536;
5356 4777 : if (iMax > nXCheck)
5357 4777 : iMax = nXCheck;
5358 4777 : GUInt32 nSum32bit = 0;
5359 4777 : GUInt32 nSumSquare32bit = 0;
5360 161686 : for (; iX + 1 < iMax; iX += 2)
5361 : {
5362 156909 : const GPtrDiff_t iOffset =
5363 156909 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5364 156909 : const GUInt32 nValue = pData[iOffset];
5365 156909 : const GUInt32 nValue2 = pData[iOffset + 1];
5366 156909 : if (nValue < nValue2)
5367 : {
5368 8957 : if (nValue < nMin)
5369 252 : nMin = nValue;
5370 8957 : if (nValue2 > nMax)
5371 241 : nMax = nValue2;
5372 : }
5373 : else
5374 : {
5375 147952 : if (nValue2 < nMin)
5376 298 : nMin = nValue2;
5377 147952 : if (nValue > nMax)
5378 859 : nMax = nValue;
5379 : }
5380 : if constexpr (COMPUTE_OTHER_STATS)
5381 : {
5382 132489 : nSum32bit += nValue;
5383 132489 : nSumSquare32bit += nValue * nValue;
5384 132489 : nSum32bit += nValue2;
5385 132489 : nSumSquare32bit += nValue2 * nValue2;
5386 : }
5387 : }
5388 : if constexpr (COMPUTE_OTHER_STATS)
5389 : {
5390 1607 : nSum += nSum32bit;
5391 1607 : nSumSquare += nSumSquare32bit;
5392 : }
5393 : }
5394 4777 : if (iX < nXCheck)
5395 : {
5396 1384 : const GPtrDiff_t iOffset =
5397 1384 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5398 1384 : const GUInt32 nValue = pData[iOffset];
5399 1384 : if (nValue < nMin)
5400 39 : nMin = nValue;
5401 1384 : if (nValue > nMax)
5402 48 : nMax = nValue;
5403 : if constexpr (COMPUTE_OTHER_STATS)
5404 : {
5405 312 : nSum += nValue;
5406 312 : nSumSquare +=
5407 312 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5408 312 : nValue;
5409 : }
5410 : }
5411 : }
5412 : if constexpr (COMPUTE_OTHER_STATS)
5413 : {
5414 906 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5415 906 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5416 : }
5417 : }
5418 11756 : }
5419 : };
5420 :
5421 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5422 : {
5423 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5424 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5425 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5426 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5427 : {
5428 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5429 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5430 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5431 : }
5432 : };
5433 :
5434 : #if (defined(__x86_64__) || defined(_M_X64)) && \
5435 : (defined(__GNUC__) || defined(_MSC_VER))
5436 :
5437 : #include "gdal_avx2_emulation.hpp"
5438 :
5439 : #define ZERO256 GDALmm256_setzero_si256()
5440 :
5441 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5442 : static void
5443 19033 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5444 : // assumed to be aligned on 256 bits
5445 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5446 : GUIntBig &nSum, GUIntBig &nSumSquare,
5447 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5448 : {
5449 : // 32-byte alignment may not be enforced by linker, so do it at hand
5450 : GByte
5451 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5452 19033 : GByte *paby32ByteAligned =
5453 : aby32ByteUnaligned +
5454 19033 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5455 19033 : GByte *pabyMin = paby32ByteAligned;
5456 19033 : GByte *pabyMax = paby32ByteAligned + 32;
5457 19033 : GUInt32 *panSum =
5458 : COMPUTE_OTHER_STATS
5459 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5460 : : nullptr;
5461 19033 : GUInt32 *panSumSquare =
5462 : COMPUTE_OTHER_STATS
5463 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5464 : : nullptr;
5465 :
5466 19033 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5467 :
5468 19033 : GPtrDiff_t i = 0;
5469 : // Make sure that sumSquare can fit on uint32
5470 : // * 8 since we can hold 8 sums per vector register
5471 19033 : const int nMaxIterationsPerInnerLoop =
5472 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5473 19033 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5474 19033 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5475 19033 : nOuterLoops++;
5476 :
5477 : GDALm256i ymm_min =
5478 19033 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5479 19033 : GDALm256i ymm_max = ymm_min;
5480 19033 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5481 :
5482 38066 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5483 : {
5484 19033 : const auto iMax =
5485 19033 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5486 :
5487 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5488 19033 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5489 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5490 19033 : ZERO256; // holds 8 uint32 sums
5491 641852 : for (; i + 31 < iMax; i += 32)
5492 : {
5493 622819 : const GDALm256i ymm = GDALmm256_load_si256(
5494 622819 : reinterpret_cast<const GDALm256i *>(pData + i));
5495 : if (COMPUTE_MIN)
5496 : {
5497 164884 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5498 : }
5499 : if (COMPUTE_MAX)
5500 : {
5501 531878 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5502 : }
5503 :
5504 : if constexpr (COMPUTE_OTHER_STATS)
5505 : {
5506 : // Extract even-8bit values
5507 : const GDALm256i ymm_even =
5508 493495 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5509 : // Compute square of those 16 values as 32 bit result
5510 : // and add adjacent pairs
5511 : const GDALm256i ymm_even_square =
5512 493495 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5513 : // Add to the sumsquare accumulator
5514 : ymm_sumsquare =
5515 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5516 :
5517 : // Extract odd-8bit values
5518 493495 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5519 : const GDALm256i ymm_odd_square =
5520 493495 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5521 : ymm_sumsquare =
5522 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5523 :
5524 : // Now compute the sums
5525 493495 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5526 : GDALmm256_sad_epu8(ymm, ZERO256));
5527 : }
5528 : }
5529 :
5530 : if constexpr (COMPUTE_OTHER_STATS)
5531 : {
5532 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5533 : ymm_sum);
5534 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5535 : ymm_sumsquare);
5536 :
5537 10649 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5538 10649 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5539 10649 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5540 10649 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5541 : panSumSquare[7];
5542 : }
5543 : }
5544 :
5545 : if constexpr (COMPUTE_MIN)
5546 : {
5547 6061 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5548 : }
5549 : if constexpr (COMPUTE_MAX)
5550 : {
5551 15036 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5552 : }
5553 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5554 : {
5555 513678 : for (int j = 0; j < 32; j++)
5556 : {
5557 : if constexpr (COMPUTE_MIN)
5558 : {
5559 193952 : if (pabyMin[j] < nMin)
5560 1264 : nMin = pabyMin[j];
5561 : }
5562 : if constexpr (COMPUTE_MAX)
5563 : {
5564 481152 : if (pabyMax[j] > nMax)
5565 1817 : nMax = pabyMax[j];
5566 : }
5567 : }
5568 : }
5569 :
5570 211583 : for (; i < nBlockPixels; i++)
5571 : {
5572 192550 : const GUInt32 nValue = pData[i];
5573 : if constexpr (COMPUTE_MIN)
5574 : {
5575 66110 : if (nValue < nMin)
5576 1 : nMin = nValue;
5577 : }
5578 : if constexpr (COMPUTE_MAX)
5579 : {
5580 189775 : if (nValue > nMax)
5581 1167 : nMax = nValue;
5582 : }
5583 : if constexpr (COMPUTE_OTHER_STATS)
5584 : {
5585 77195 : nSum += nValue;
5586 77195 : nSumSquare +=
5587 77195 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5588 : }
5589 : }
5590 :
5591 : if constexpr (COMPUTE_OTHER_STATS)
5592 : {
5593 10649 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5594 10649 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5595 : }
5596 19033 : }
5597 :
5598 : // SSE2/AVX2 optimization for GByte case
5599 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5600 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5601 : // there are strictly equivalent to 2 parallel SSE2 streams.
5602 : template <bool COMPUTE_OTHER_STATS>
5603 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5604 : {
5605 28100 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5606 : // assumed to be aligned on 256 bits
5607 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5608 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5609 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5610 : GUIntBig &nValidCount)
5611 : {
5612 28100 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5613 28100 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5614 9352 : nMin <= nMax)
5615 : {
5616 : // 32-byte alignment may not be enforced by linker, so do it at hand
5617 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5618 1240 : GByte *paby32ByteAligned =
5619 : aby32ByteUnaligned +
5620 1240 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5621 1240 : GByte *pabyMin = paby32ByteAligned;
5622 1240 : GByte *pabyMax = paby32ByteAligned + 32;
5623 1240 : GUInt32 *panSum =
5624 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5625 1240 : GUInt32 *panSumSquare =
5626 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5627 :
5628 1240 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5629 :
5630 1240 : GPtrDiff_t i = 0;
5631 : // Make sure that sumSquare can fit on uint32
5632 : // * 8 since we can hold 8 sums per vector register
5633 1240 : const int nMaxIterationsPerInnerLoop =
5634 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5635 1240 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5636 1240 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5637 1240 : nOuterLoops++;
5638 :
5639 : const GDALm256i ymm_nodata =
5640 1240 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5641 : // any non noData value in [min,max] would do.
5642 : const GDALm256i ymm_neutral =
5643 1240 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5644 1240 : GDALm256i ymm_min = ymm_neutral;
5645 1240 : GDALm256i ymm_max = ymm_neutral;
5646 : [[maybe_unused]] const auto ymm_mask_8bits =
5647 1240 : GDALmm256_set1_epi16(0xFF);
5648 :
5649 1240 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5650 1240 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5651 1240 : const bool bComputeMinMax =
5652 1240 : nMin > nMinThreshold || nMax < nMaxThreshold;
5653 :
5654 2480 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5655 : {
5656 1240 : const auto iMax =
5657 1240 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5658 :
5659 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5660 1240 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5661 : // holds 8 uint32 sums
5662 1240 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5663 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5664 1240 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5665 1240 : const auto iInit = i;
5666 13799 : for (; i + 31 < iMax; i += 32)
5667 : {
5668 12559 : const GDALm256i ymm = GDALmm256_load_si256(
5669 12559 : reinterpret_cast<const GDALm256i *>(pData + i));
5670 :
5671 : // Check which values are nodata
5672 : const GDALm256i ymm_eq_nodata =
5673 12559 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5674 : if constexpr (COMPUTE_OTHER_STATS)
5675 : {
5676 : // Count how many values are nodata (due to cmpeq
5677 : // putting 255 when condition is met, this will actually
5678 : // be 255 times the number of nodata value, spread in 4
5679 : // 64 bits words). We can use add_epi32 as the counter
5680 : // will not overflow uint32
5681 4514 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5682 : ymm_count_nodata_mul_255,
5683 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5684 : }
5685 : // Replace all nodata values by zero for the purpose of sum
5686 : // and sumquare.
5687 : const GDALm256i ymm_nodata_by_zero =
5688 12559 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5689 12559 : if (bComputeMinMax)
5690 : {
5691 : // Replace all nodata values by a neutral value for the
5692 : // purpose of min and max.
5693 : const GDALm256i ymm_nodata_by_neutral =
5694 8174 : GDALmm256_or_si256(
5695 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5696 : ymm_nodata_by_zero);
5697 :
5698 : ymm_min =
5699 8174 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5700 : ymm_max =
5701 8174 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
5702 : }
5703 :
5704 : if constexpr (COMPUTE_OTHER_STATS)
5705 : {
5706 : // Extract even-8bit values
5707 4514 : const GDALm256i ymm_even = GDALmm256_and_si256(
5708 : ymm_nodata_by_zero, ymm_mask_8bits);
5709 : // Compute square of those 16 values as 32 bit result
5710 : // and add adjacent pairs
5711 : const GDALm256i ymm_even_square =
5712 4514 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5713 : // Add to the sumsquare accumulator
5714 : ymm_sumsquare =
5715 4514 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5716 :
5717 : // Extract odd-8bit values
5718 : const GDALm256i ymm_odd =
5719 4514 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
5720 : const GDALm256i ymm_odd_square =
5721 4514 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5722 : ymm_sumsquare =
5723 4514 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5724 :
5725 : // Now compute the sums
5726 4514 : ymm_sum = GDALmm256_add_epi32(
5727 : ymm_sum,
5728 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
5729 : }
5730 : }
5731 :
5732 : if constexpr (COMPUTE_OTHER_STATS)
5733 : {
5734 33 : GUInt32 *panCoutNoDataMul255 = panSum;
5735 33 : GDALmm256_store_si256(
5736 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
5737 : ymm_count_nodata_mul_255);
5738 :
5739 33 : nSampleCount += (i - iInit);
5740 :
5741 33 : nValidCount +=
5742 33 : (i - iInit) -
5743 33 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
5744 33 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
5745 : 255;
5746 :
5747 33 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5748 : ymm_sum);
5749 33 : GDALmm256_store_si256(
5750 : reinterpret_cast<GDALm256i *>(panSumSquare),
5751 : ymm_sumsquare);
5752 33 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5753 33 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5754 33 : panSumSquare[1] + panSumSquare[2] +
5755 33 : panSumSquare[3] + panSumSquare[4] +
5756 33 : panSumSquare[5] + panSumSquare[6] +
5757 : panSumSquare[7];
5758 : }
5759 : }
5760 :
5761 1240 : if (bComputeMinMax)
5762 : {
5763 1209 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
5764 : ymm_min);
5765 1209 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
5766 : ymm_max);
5767 39897 : for (int j = 0; j < 32; j++)
5768 : {
5769 38688 : if (pabyMin[j] < nMin)
5770 32 : nMin = pabyMin[j];
5771 38688 : if (pabyMax[j] > nMax)
5772 157 : nMax = pabyMax[j];
5773 : }
5774 : }
5775 :
5776 : if constexpr (COMPUTE_OTHER_STATS)
5777 : {
5778 33 : nSampleCount += nBlockPixels - i;
5779 : }
5780 29810 : for (; i < nBlockPixels; i++)
5781 : {
5782 28570 : const GUInt32 nValue = pData[i];
5783 28570 : if (nValue == nNoDataValue)
5784 24923 : continue;
5785 3647 : if (nValue < nMin)
5786 1 : nMin = nValue;
5787 3647 : if (nValue > nMax)
5788 13 : nMax = nValue;
5789 : if constexpr (COMPUTE_OTHER_STATS)
5790 : {
5791 110 : nValidCount++;
5792 110 : nSum += nValue;
5793 110 : nSumSquare +=
5794 110 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5795 110 : nValue;
5796 : }
5797 1240 : }
5798 : }
5799 26860 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
5800 : {
5801 15077 : if (nMin > 0)
5802 : {
5803 2105 : if (nMax < 255)
5804 : {
5805 : ComputeStatisticsByteNoNodata<true, true,
5806 1575 : COMPUTE_OTHER_STATS>(
5807 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5808 : nSampleCount, nValidCount);
5809 : }
5810 : else
5811 : {
5812 : ComputeStatisticsByteNoNodata<true, false,
5813 530 : COMPUTE_OTHER_STATS>(
5814 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5815 : nSampleCount, nValidCount);
5816 : }
5817 : }
5818 : else
5819 : {
5820 12972 : if (nMax < 255)
5821 : {
5822 : ComputeStatisticsByteNoNodata<false, true,
5823 9505 : COMPUTE_OTHER_STATS>(
5824 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5825 : nSampleCount, nValidCount);
5826 : }
5827 : else
5828 : {
5829 : ComputeStatisticsByteNoNodata<false, false,
5830 3467 : COMPUTE_OTHER_STATS>(
5831 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5832 : nSampleCount, nValidCount);
5833 : }
5834 : }
5835 : }
5836 10533 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
5837 27 : (nBlockXSize % 32) == 0)
5838 : {
5839 3983 : for (int iY = 0; iY < nYCheck; iY++)
5840 : {
5841 3956 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
5842 3956 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
5843 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5844 27 : }
5845 : }
5846 : else
5847 : {
5848 11756 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
5849 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5850 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5851 : }
5852 28100 : }
5853 : };
5854 :
5855 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
5856 404 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
5857 : GUIntBig i)
5858 : {
5859 404 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
5860 404 : }
5861 :
5862 : // AVX2/SSE2 optimization for GUInt16 case
5863 : template <bool COMPUTE_OTHER_STATS>
5864 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
5865 : {
5866 1348 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5867 : // assumed to be aligned on 128 bits
5868 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
5869 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5870 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5871 : GUIntBig &nValidCount)
5872 : {
5873 1348 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5874 1348 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
5875 : {
5876 1166 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
5877 :
5878 1166 : GPtrDiff_t i = 0;
5879 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
5880 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
5881 : // Furthermore the shift is also needed to use madd_epi16
5882 1166 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
5883 1166 : GDALm256i ymm_min = GDALmm256_load_si256(
5884 1166 : reinterpret_cast<const GDALm256i *>(pData + i));
5885 1166 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
5886 1166 : GDALm256i ymm_max = ymm_min;
5887 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5888 1166 : ZERO256; // holds 4 uint64 sums
5889 :
5890 : // Make sure that sum can fit on uint32
5891 : // * 8 since we can hold 8 sums per vector register
5892 1166 : const int nMaxIterationsPerInnerLoop =
5893 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
5894 1166 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5895 1166 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5896 1166 : nOuterLoops++;
5897 :
5898 1166 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
5899 : [[maybe_unused]] const auto ymm_mask_16bits =
5900 1166 : GDALmm256_set1_epi32(0xFFFF);
5901 : [[maybe_unused]] const auto ymm_mask_32bits =
5902 1166 : GDALmm256_set1_epi64x(0xFFFFFFFF);
5903 :
5904 1166 : GUIntBig nSumThis = 0;
5905 2356 : for (int k = 0; k < nOuterLoops; k++)
5906 : {
5907 1190 : const auto iMax =
5908 1190 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5909 :
5910 : [[maybe_unused]] GDALm256i ymm_sum =
5911 1190 : ZERO256; // holds 8 uint32 sums
5912 959522 : for (; i + 15 < iMax; i += 16)
5913 : {
5914 958332 : const GDALm256i ymm = GDALmm256_load_si256(
5915 958332 : reinterpret_cast<const GDALm256i *>(pData + i));
5916 : const GDALm256i ymm_shifted =
5917 958332 : GDALmm256_add_epi16(ymm, ymm_m32768);
5918 958332 : if (bComputeMinMax)
5919 : {
5920 949313 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
5921 949313 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
5922 : }
5923 :
5924 : if constexpr (COMPUTE_OTHER_STATS)
5925 : {
5926 : // Note: the int32 range can overflow for (0-32768)^2 +
5927 : // (0-32768)^2 = 0x80000000, but as we know the result
5928 : // is positive, this is OK as we interpret is a uint32.
5929 : const GDALm256i ymm_square =
5930 99506 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
5931 99506 : ymm_sumsquare = GDALmm256_add_epi64(
5932 : ymm_sumsquare,
5933 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
5934 99506 : ymm_sumsquare = GDALmm256_add_epi64(
5935 : ymm_sumsquare,
5936 : GDALmm256_srli_epi64(ymm_square, 32));
5937 :
5938 : // Now compute the sums
5939 99506 : ymm_sum = GDALmm256_add_epi32(
5940 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
5941 99506 : ymm_sum = GDALmm256_add_epi32(
5942 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
5943 : }
5944 : }
5945 :
5946 : if constexpr (COMPUTE_OTHER_STATS)
5947 : {
5948 : GUInt32 anSum[8];
5949 404 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
5950 : ymm_sum);
5951 404 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
5952 404 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
5953 404 : anSum[6] + anSum[7];
5954 : }
5955 : }
5956 :
5957 1166 : if (bComputeMinMax)
5958 : {
5959 : GUInt16 anMin[16];
5960 : GUInt16 anMax[16];
5961 :
5962 : // Unshift the result
5963 1125 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
5964 1125 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
5965 1125 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
5966 : ymm_min);
5967 1125 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
5968 : ymm_max);
5969 19125 : for (int j = 0; j < 16; j++)
5970 : {
5971 18000 : if (anMin[j] < nMin)
5972 344 : nMin = anMin[j];
5973 18000 : if (anMax[j] > nMax)
5974 482 : nMax = anMax[j];
5975 : }
5976 : }
5977 :
5978 : if constexpr (COMPUTE_OTHER_STATS)
5979 : {
5980 : GUIntBig anSumSquare[4];
5981 404 : GDALmm256_storeu_si256(
5982 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
5983 404 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
5984 : anSumSquare[3];
5985 :
5986 : // Unshift the sum of squares
5987 404 : UnshiftSumSquare(nSumSquare, nSumThis,
5988 : static_cast<GUIntBig>(i));
5989 :
5990 404 : nSum += nSumThis;
5991 :
5992 726 : for (; i < nBlockPixels; i++)
5993 : {
5994 322 : const GUInt32 nValue = pData[i];
5995 322 : if (nValue < nMin)
5996 1 : nMin = nValue;
5997 322 : if (nValue > nMax)
5998 1 : nMax = nValue;
5999 322 : nSum += nValue;
6000 322 : nSumSquare +=
6001 322 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6002 322 : nValue;
6003 : }
6004 :
6005 404 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6006 404 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6007 1166 : }
6008 : }
6009 : else
6010 : {
6011 182 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6012 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6013 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6014 : }
6015 1348 : }
6016 : };
6017 :
6018 : #endif
6019 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6020 : // defined(_MSC_VER))
6021 :
6022 : /************************************************************************/
6023 : /* GetPixelValue() */
6024 : /************************************************************************/
6025 :
6026 23166200 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6027 : const void *pData, GPtrDiff_t iOffset,
6028 : bool bGotNoDataValue, double dfNoDataValue,
6029 : bool bGotFloatNoDataValue,
6030 : float fNoDataValue, bool &bValid)
6031 : {
6032 23166200 : bValid = true;
6033 23166200 : double dfValue = 0;
6034 23166200 : switch (eDataType)
6035 : {
6036 1413680 : case GDT_Byte:
6037 : {
6038 1413680 : if (bSignedByte)
6039 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6040 : else
6041 1413490 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6042 1413680 : break;
6043 : }
6044 10405 : case GDT_Int8:
6045 10405 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6046 10405 : break;
6047 4000 : case GDT_UInt16:
6048 4000 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6049 4000 : break;
6050 60192 : case GDT_Int16:
6051 60192 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6052 60192 : break;
6053 27596 : case GDT_UInt32:
6054 27596 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6055 27596 : break;
6056 460170 : case GDT_Int32:
6057 460170 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6058 460170 : break;
6059 2598 : case GDT_UInt64:
6060 2598 : dfValue = static_cast<double>(
6061 2598 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6062 2598 : break;
6063 7398 : case GDT_Int64:
6064 7398 : dfValue = static_cast<double>(
6065 7398 : static_cast<const std::int64_t *>(pData)[iOffset]);
6066 7398 : break;
6067 17483400 : case GDT_Float32:
6068 : {
6069 17483400 : const float fValue = static_cast<const float *>(pData)[iOffset];
6070 30693400 : if (std::isnan(fValue) ||
6071 13210000 : (bGotFloatNoDataValue && ARE_REAL_EQUAL(fValue, fNoDataValue)))
6072 : {
6073 119863 : bValid = false;
6074 119863 : return 0.0;
6075 : }
6076 17363500 : dfValue = fValue;
6077 17363500 : return dfValue;
6078 : }
6079 3679660 : case GDT_Float64:
6080 3679660 : dfValue = static_cast<const double *>(pData)[iOffset];
6081 3679660 : if (std::isnan(dfValue))
6082 : {
6083 52 : bValid = false;
6084 52 : return 0.0;
6085 : }
6086 3679600 : break;
6087 2692 : case GDT_CInt16:
6088 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6089 2692 : break;
6090 2692 : case GDT_CInt32:
6091 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6092 2692 : break;
6093 5812 : case GDT_CFloat32:
6094 5812 : dfValue = static_cast<const float *>(pData)[iOffset * 2];
6095 5812 : if (std::isnan(dfValue))
6096 : {
6097 0 : bValid = false;
6098 0 : return 0.0;
6099 : }
6100 5812 : break;
6101 5892 : case GDT_CFloat64:
6102 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6103 5892 : if (std::isnan(dfValue))
6104 : {
6105 0 : bValid = false;
6106 0 : return 0.0;
6107 : }
6108 5892 : break;
6109 0 : case GDT_Unknown:
6110 : case GDT_TypeCount:
6111 0 : CPLAssert(false);
6112 : break;
6113 : }
6114 :
6115 5682730 : if (bGotNoDataValue && ARE_REAL_EQUAL(dfValue, dfNoDataValue))
6116 : {
6117 3346220 : bValid = false;
6118 3346220 : return 0.0;
6119 : }
6120 2336510 : return dfValue;
6121 : }
6122 :
6123 : /************************************************************************/
6124 : /* SetValidPercent() */
6125 : /************************************************************************/
6126 :
6127 : //! @cond Doxygen_Suppress
6128 : /**
6129 : * \brief Set percentage of valid (not nodata) pixels.
6130 : *
6131 : * Stores the percentage of valid pixels in the metadata item
6132 : * STATISTICS_VALID_PERCENT
6133 : *
6134 : * @param nSampleCount Number of sampled pixels.
6135 : *
6136 : * @param nValidCount Number of valid pixels.
6137 : */
6138 :
6139 467 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6140 : GUIntBig nValidCount)
6141 : {
6142 467 : if (nValidCount == 0)
6143 : {
6144 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6145 : }
6146 455 : else if (nValidCount == nSampleCount)
6147 : {
6148 412 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6149 : }
6150 : else /* nValidCount < nSampleCount */
6151 : {
6152 43 : char szValue[128] = {0};
6153 :
6154 : /* percentage is only an indicator: limit precision */
6155 43 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6156 43 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6157 :
6158 43 : if (EQUAL(szValue, "100"))
6159 : {
6160 : /* don't set 100 percent valid
6161 : * because some of the sampled pixels were nodata */
6162 0 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6163 : }
6164 : else
6165 : {
6166 43 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6167 : }
6168 : }
6169 467 : }
6170 :
6171 : //! @endcond
6172 :
6173 : /************************************************************************/
6174 : /* ComputeStatistics() */
6175 : /************************************************************************/
6176 :
6177 : /**
6178 : * \brief Compute image statistics.
6179 : *
6180 : * Returns the minimum, maximum, mean and standard deviation of all
6181 : * pixel values in this band. If approximate statistics are sufficient,
6182 : * the bApproxOK flag can be set to true in which case overviews, or a
6183 : * subset of image tiles may be used in computing the statistics.
6184 : *
6185 : * Once computed, the statistics will generally be "set" back on the
6186 : * raster band using SetStatistics().
6187 : *
6188 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6189 : *
6190 : * This method is the same as the C function GDALComputeRasterStatistics().
6191 : *
6192 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6193 : * or a subset of all tiles.
6194 : *
6195 : * @param pdfMin Location into which to load image minimum (may be NULL).
6196 : *
6197 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6198 : *
6199 : * @param pdfMean Location into which to load image mean (may be NULL).
6200 : *
6201 : * @param pdfStdDev Location into which to load image standard deviation
6202 : * (may be NULL).
6203 : *
6204 : * @param pfnProgress a function to call to report progress, or NULL.
6205 : *
6206 : * @param pProgressData application data to pass to the progress function.
6207 : *
6208 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6209 : * is terminated by the user.
6210 : */
6211 :
6212 450 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6213 : double *pdfMax, double *pdfMean,
6214 : double *pdfStdDev,
6215 : GDALProgressFunc pfnProgress,
6216 : void *pProgressData)
6217 :
6218 : {
6219 450 : if (pfnProgress == nullptr)
6220 155 : pfnProgress = GDALDummyProgress;
6221 :
6222 : /* -------------------------------------------------------------------- */
6223 : /* If we have overview bands, use them for statistics. */
6224 : /* -------------------------------------------------------------------- */
6225 450 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6226 : {
6227 : GDALRasterBand *poBand =
6228 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6229 :
6230 3 : if (poBand != this)
6231 : {
6232 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6233 : pdfMean, pdfStdDev,
6234 3 : pfnProgress, pProgressData);
6235 3 : if (eErr == CE_None)
6236 : {
6237 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6238 : {
6239 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6240 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6241 : }
6242 :
6243 : /* transfer metadata from overview band to this */
6244 : const char *pszPercentValid =
6245 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6246 :
6247 3 : if (pszPercentValid != nullptr)
6248 : {
6249 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6250 3 : pszPercentValid);
6251 : }
6252 : }
6253 3 : return eErr;
6254 : }
6255 : }
6256 :
6257 447 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6258 : {
6259 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6260 0 : return CE_Failure;
6261 : }
6262 :
6263 : /* -------------------------------------------------------------------- */
6264 : /* Read actual data and compute statistics. */
6265 : /* -------------------------------------------------------------------- */
6266 : // Using Welford algorithm:
6267 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6268 : // to compute standard deviation in a more numerically robust way than
6269 : // the difference of the sum of square values with the square of the sum.
6270 : // dfMean and dfM2 are updated at each sample.
6271 : // dfM2 is the sum of square of differences to the current mean.
6272 447 : double dfMin = std::numeric_limits<double>::max();
6273 447 : double dfMax = -std::numeric_limits<double>::max();
6274 447 : double dfMean = 0.0;
6275 447 : double dfM2 = 0.0;
6276 :
6277 : GDALRasterIOExtraArg sExtraArg;
6278 447 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6279 :
6280 447 : int bGotNoDataValue = FALSE;
6281 447 : const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
6282 447 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
6283 447 : bool bGotFloatNoDataValue = false;
6284 447 : float fNoDataValue = 0.0f;
6285 447 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
6286 : fNoDataValue, bGotFloatNoDataValue);
6287 :
6288 447 : GDALRasterBand *poMaskBand = nullptr;
6289 447 : if (!bGotNoDataValue)
6290 : {
6291 422 : const int l_nMaskFlags = GetMaskFlags();
6292 438 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
6293 16 : GetColorInterpretation() != GCI_AlphaBand)
6294 : {
6295 16 : poMaskBand = GetMaskBand();
6296 : }
6297 : }
6298 :
6299 447 : bool bSignedByte = false;
6300 447 : if (eDataType == GDT_Byte)
6301 : {
6302 195 : EnablePixelTypeSignedByteWarning(false);
6303 : const char *pszPixelType =
6304 195 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6305 195 : EnablePixelTypeSignedByteWarning(true);
6306 195 : bSignedByte =
6307 195 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6308 : }
6309 :
6310 447 : GUIntBig nSampleCount = 0;
6311 447 : GUIntBig nValidCount = 0;
6312 :
6313 447 : if (bApproxOK && HasArbitraryOverviews())
6314 : {
6315 : /* --------------------------------------------------------------------
6316 : */
6317 : /* Figure out how much the image should be reduced to get an */
6318 : /* approximate value. */
6319 : /* --------------------------------------------------------------------
6320 : */
6321 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6322 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6323 :
6324 0 : int nXReduced = nRasterXSize;
6325 0 : int nYReduced = nRasterYSize;
6326 0 : if (dfReduction > 1.0)
6327 : {
6328 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6329 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6330 :
6331 : // Catch the case of huge resizing ratios here
6332 0 : if (nXReduced == 0)
6333 0 : nXReduced = 1;
6334 0 : if (nYReduced == 0)
6335 0 : nYReduced = 1;
6336 : }
6337 :
6338 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
6339 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6340 :
6341 : const CPLErr eErr =
6342 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6343 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6344 0 : if (eErr != CE_None)
6345 : {
6346 0 : CPLFree(pData);
6347 0 : return eErr;
6348 : }
6349 :
6350 0 : GByte *pabyMaskData = nullptr;
6351 0 : if (poMaskBand)
6352 : {
6353 : pabyMaskData =
6354 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6355 0 : if (!pabyMaskData)
6356 : {
6357 0 : CPLFree(pData);
6358 0 : return CE_Failure;
6359 : }
6360 :
6361 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6362 : pabyMaskData, nXReduced, nYReduced,
6363 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
6364 : {
6365 0 : CPLFree(pData);
6366 0 : CPLFree(pabyMaskData);
6367 0 : return CE_Failure;
6368 : }
6369 : }
6370 :
6371 : /* this isn't the fastest way to do this, but is easier for now */
6372 0 : for (int iY = 0; iY < nYReduced; iY++)
6373 : {
6374 0 : for (int iX = 0; iX < nXReduced; iX++)
6375 : {
6376 0 : const int iOffset = iX + iY * nXReduced;
6377 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6378 0 : continue;
6379 :
6380 0 : bool bValid = true;
6381 : double dfValue =
6382 0 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6383 0 : CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
6384 0 : bGotFloatNoDataValue, fNoDataValue, bValid);
6385 0 : if (!bValid)
6386 0 : continue;
6387 :
6388 0 : dfMin = std::min(dfMin, dfValue);
6389 0 : dfMax = std::max(dfMax, dfValue);
6390 :
6391 0 : nValidCount++;
6392 0 : const double dfDelta = dfValue - dfMean;
6393 0 : dfMean += dfDelta / nValidCount;
6394 0 : dfM2 += dfDelta * (dfValue - dfMean);
6395 : }
6396 : }
6397 :
6398 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6399 :
6400 0 : CPLFree(pData);
6401 0 : CPLFree(pabyMaskData);
6402 : }
6403 :
6404 : else // No arbitrary overviews.
6405 : {
6406 447 : if (!InitBlockInfo())
6407 0 : return CE_Failure;
6408 :
6409 : /* --------------------------------------------------------------------
6410 : */
6411 : /* Figure out the ratio of blocks we will read to get an */
6412 : /* approximate value. */
6413 : /* --------------------------------------------------------------------
6414 : */
6415 447 : int nSampleRate = 1;
6416 447 : if (bApproxOK)
6417 : {
6418 41 : nSampleRate = static_cast<int>(std::max(
6419 82 : 1.0,
6420 41 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6421 : // We want to avoid probing only the first column of blocks for
6422 : // a square shaped raster, because it is not unlikely that it may
6423 : // be padding only (#6378)
6424 41 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6425 2 : nSampleRate += 1;
6426 : }
6427 447 : if (nSampleRate == 1)
6428 413 : bApproxOK = false;
6429 :
6430 : // Particular case for GDT_Byte that only use integral types for all
6431 : // intermediate computations. Only possible if the number of pixels
6432 : // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6433 : // can fit on a uint64. Should be 99.99999% of cases.
6434 : // For GUInt16, this limits to raster of 4 giga pixels
6435 447 : if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6436 180 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6437 180 : nSampleRate <
6438 180 : GUINTBIG_MAX / (255U * 255U) /
6439 180 : (static_cast<GUInt64>(nBlockXSize) *
6440 180 : static_cast<GUInt64>(nBlockYSize))) ||
6441 267 : (eDataType == GDT_UInt16 &&
6442 29 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6443 29 : nSampleRate <
6444 29 : GUINTBIG_MAX / (65535U * 65535U) /
6445 29 : (static_cast<GUInt64>(nBlockXSize) *
6446 29 : static_cast<GUInt64>(nBlockYSize))))
6447 : {
6448 209 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6449 209 : GUInt32 nMin = nMaxValueType;
6450 209 : GUInt32 nMax = 0;
6451 209 : GUIntBig nSum = 0;
6452 209 : GUIntBig nSumSquare = 0;
6453 : // If no valid nodata, map to invalid value (256 for Byte)
6454 209 : const GUInt32 nNoDataValue =
6455 21 : (bGotNoDataValue && dfNoDataValue >= 0 &&
6456 21 : dfNoDataValue <= nMaxValueType &&
6457 21 : fabs(dfNoDataValue -
6458 21 : static_cast<GUInt32>(dfNoDataValue + 1e-10)) < 1e-10)
6459 230 : ? static_cast<GUInt32>(dfNoDataValue + 1e-10)
6460 : : nMaxValueType + 1;
6461 :
6462 209 : for (GIntBig iSampleBlock = 0;
6463 12599 : iSampleBlock <
6464 12599 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6465 12390 : iSampleBlock += nSampleRate)
6466 : {
6467 12390 : const int iYBlock =
6468 12390 : static_cast<int>(iSampleBlock / nBlocksPerRow);
6469 12390 : const int iXBlock =
6470 12390 : static_cast<int>(iSampleBlock % nBlocksPerRow);
6471 :
6472 : GDALRasterBlock *const poBlock =
6473 12390 : GetLockedBlockRef(iXBlock, iYBlock);
6474 12390 : if (poBlock == nullptr)
6475 0 : return CE_Failure;
6476 :
6477 12390 : void *const pData = poBlock->GetDataRef();
6478 :
6479 12390 : int nXCheck = 0, nYCheck = 0;
6480 12390 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6481 :
6482 12390 : if (eDataType == GDT_Byte)
6483 : {
6484 : ComputeStatisticsInternal<
6485 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
6486 11932 : f(nXCheck, nBlockXSize, nYCheck,
6487 : static_cast<const GByte *>(pData),
6488 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6489 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6490 : }
6491 : else
6492 : {
6493 : ComputeStatisticsInternal<
6494 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6495 458 : f(nXCheck, nBlockXSize, nYCheck,
6496 : static_cast<const GUInt16 *>(pData),
6497 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6498 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6499 : }
6500 :
6501 12390 : poBlock->DropLock();
6502 :
6503 12390 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
6504 12390 : (static_cast<double>(nBlocksPerRow) *
6505 12390 : nBlocksPerColumn),
6506 : "Compute Statistics", pProgressData))
6507 : {
6508 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
6509 : "User terminated");
6510 0 : return CE_Failure;
6511 : }
6512 : }
6513 :
6514 209 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6515 : {
6516 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6517 0 : return CE_Failure;
6518 : }
6519 :
6520 : /* --------------------------------------------------------------------
6521 : */
6522 : /* Save computed information. */
6523 : /* --------------------------------------------------------------------
6524 : */
6525 209 : if (nValidCount)
6526 200 : dfMean = static_cast<double>(nSum) / nValidCount;
6527 :
6528 : // To avoid potential precision issues when doing the difference,
6529 : // we need to do that computation on 128 bit rather than casting
6530 : // to double
6531 : const GDALUInt128 nTmpForStdDev(
6532 209 : GDALUInt128::Mul(nSumSquare, nValidCount) -
6533 418 : GDALUInt128::Mul(nSum, nSum));
6534 : const double dfStdDev =
6535 209 : nValidCount > 0
6536 209 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6537 209 : : 0.0;
6538 :
6539 209 : if (nValidCount > 0)
6540 : {
6541 200 : if (bApproxOK)
6542 : {
6543 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6544 : }
6545 176 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6546 : {
6547 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6548 : }
6549 200 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
6550 : }
6551 :
6552 209 : SetValidPercent(nSampleCount, nValidCount);
6553 :
6554 : /* --------------------------------------------------------------------
6555 : */
6556 : /* Record results. */
6557 : /* --------------------------------------------------------------------
6558 : */
6559 209 : if (pdfMin != nullptr)
6560 206 : *pdfMin = nValidCount ? nMin : 0;
6561 209 : if (pdfMax != nullptr)
6562 206 : *pdfMax = nValidCount ? nMax : 0;
6563 :
6564 209 : if (pdfMean != nullptr)
6565 202 : *pdfMean = dfMean;
6566 :
6567 209 : if (pdfStdDev != nullptr)
6568 202 : *pdfStdDev = dfStdDev;
6569 :
6570 209 : if (nValidCount > 0)
6571 200 : return CE_None;
6572 :
6573 9 : ReportError(CE_Failure, CPLE_AppDefined,
6574 : "Failed to compute statistics, no valid pixels found "
6575 : "in sampling.");
6576 9 : return CE_Failure;
6577 : }
6578 :
6579 238 : GByte *pabyMaskData = nullptr;
6580 238 : if (poMaskBand)
6581 : {
6582 : pabyMaskData = static_cast<GByte *>(
6583 16 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6584 16 : if (!pabyMaskData)
6585 : {
6586 0 : return CE_Failure;
6587 : }
6588 : }
6589 :
6590 238 : for (GIntBig iSampleBlock = 0;
6591 5489 : iSampleBlock <
6592 5489 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6593 5251 : iSampleBlock += nSampleRate)
6594 : {
6595 5251 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6596 5251 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6597 :
6598 : GDALRasterBlock *const poBlock =
6599 5251 : GetLockedBlockRef(iXBlock, iYBlock);
6600 5251 : if (poBlock == nullptr)
6601 : {
6602 0 : CPLFree(pabyMaskData);
6603 0 : return CE_Failure;
6604 : }
6605 :
6606 5251 : void *const pData = poBlock->GetDataRef();
6607 :
6608 5251 : int nXCheck = 0, nYCheck = 0;
6609 5251 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6610 :
6611 5352 : if (poMaskBand &&
6612 101 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6613 101 : iYBlock * nBlockYSize, nXCheck, nYCheck,
6614 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6615 101 : 0, nBlockXSize, nullptr) != CE_None)
6616 : {
6617 0 : CPLFree(pabyMaskData);
6618 0 : poBlock->DropLock();
6619 0 : return CE_Failure;
6620 : }
6621 :
6622 : // This isn't the fastest way to do this, but is easier for now.
6623 10686 : for (int iY = 0; iY < nYCheck; iY++)
6624 : {
6625 4342140 : for (int iX = 0; iX < nXCheck; iX++)
6626 : {
6627 4336710 : const GPtrDiff_t iOffset =
6628 4336710 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6629 4336710 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6630 109941 : continue;
6631 :
6632 4326840 : bool bValid = true;
6633 4326840 : double dfValue = GetPixelValue(
6634 : eDataType, bSignedByte, pData, iOffset,
6635 4326840 : CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
6636 4326840 : bGotFloatNoDataValue, fNoDataValue, bValid);
6637 :
6638 4326840 : if (!bValid)
6639 100070 : continue;
6640 :
6641 4226770 : dfMin = std::min(dfMin, dfValue);
6642 4226770 : dfMax = std::max(dfMax, dfValue);
6643 :
6644 4226770 : nValidCount++;
6645 4226770 : const double dfDelta = dfValue - dfMean;
6646 4226770 : dfMean += dfDelta / nValidCount;
6647 4226770 : dfM2 += dfDelta * (dfValue - dfMean);
6648 : }
6649 : }
6650 :
6651 5251 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6652 :
6653 5251 : poBlock->DropLock();
6654 :
6655 5251 : if (!pfnProgress(
6656 5251 : static_cast<double>(iSampleBlock) /
6657 5251 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6658 : "Compute Statistics", pProgressData))
6659 : {
6660 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6661 0 : CPLFree(pabyMaskData);
6662 0 : return CE_Failure;
6663 : }
6664 : }
6665 :
6666 238 : CPLFree(pabyMaskData);
6667 : }
6668 :
6669 238 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6670 : {
6671 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6672 0 : return CE_Failure;
6673 : }
6674 :
6675 : /* -------------------------------------------------------------------- */
6676 : /* Save computed information. */
6677 : /* -------------------------------------------------------------------- */
6678 238 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
6679 :
6680 238 : if (nValidCount > 0)
6681 : {
6682 237 : if (bApproxOK)
6683 : {
6684 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6685 : }
6686 229 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6687 : {
6688 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6689 : }
6690 237 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6691 : }
6692 : else
6693 : {
6694 1 : dfMin = 0.0;
6695 1 : dfMax = 0.0;
6696 : }
6697 :
6698 238 : SetValidPercent(nSampleCount, nValidCount);
6699 :
6700 : /* -------------------------------------------------------------------- */
6701 : /* Record results. */
6702 : /* -------------------------------------------------------------------- */
6703 238 : if (pdfMin != nullptr)
6704 235 : *pdfMin = dfMin;
6705 238 : if (pdfMax != nullptr)
6706 235 : *pdfMax = dfMax;
6707 :
6708 238 : if (pdfMean != nullptr)
6709 233 : *pdfMean = dfMean;
6710 :
6711 238 : if (pdfStdDev != nullptr)
6712 233 : *pdfStdDev = dfStdDev;
6713 :
6714 238 : if (nValidCount > 0)
6715 237 : return CE_None;
6716 :
6717 1 : ReportError(
6718 : CE_Failure, CPLE_AppDefined,
6719 : "Failed to compute statistics, no valid pixels found in sampling.");
6720 1 : return CE_Failure;
6721 : }
6722 :
6723 : /************************************************************************/
6724 : /* GDALComputeRasterStatistics() */
6725 : /************************************************************************/
6726 :
6727 : /**
6728 : * \brief Compute image statistics.
6729 : *
6730 : * @see GDALRasterBand::ComputeStatistics()
6731 : */
6732 :
6733 142 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
6734 : int bApproxOK, double *pdfMin,
6735 : double *pdfMax, double *pdfMean,
6736 : double *pdfStdDev,
6737 : GDALProgressFunc pfnProgress,
6738 : void *pProgressData)
6739 :
6740 : {
6741 142 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
6742 :
6743 142 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6744 :
6745 142 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
6746 142 : pdfStdDev, pfnProgress, pProgressData);
6747 : }
6748 :
6749 : /************************************************************************/
6750 : /* SetStatistics() */
6751 : /************************************************************************/
6752 :
6753 : /**
6754 : * \brief Set statistics on band.
6755 : *
6756 : * This method can be used to store min/max/mean/standard deviation
6757 : * statistics on a raster band.
6758 : *
6759 : * The default implementation stores them as metadata, and will only work
6760 : * on formats that can save arbitrary metadata. This method cannot detect
6761 : * whether metadata will be properly saved and so may return CE_None even
6762 : * if the statistics will never be saved.
6763 : *
6764 : * This method is the same as the C function GDALSetRasterStatistics().
6765 : *
6766 : * @param dfMin minimum pixel value.
6767 : *
6768 : * @param dfMax maximum pixel value.
6769 : *
6770 : * @param dfMean mean (average) of all pixel values.
6771 : *
6772 : * @param dfStdDev Standard deviation of all pixel values.
6773 : *
6774 : * @return CE_None on success or CE_Failure on failure.
6775 : */
6776 :
6777 465 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
6778 : double dfStdDev)
6779 :
6780 : {
6781 465 : char szValue[128] = {0};
6782 :
6783 465 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
6784 465 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
6785 :
6786 465 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
6787 465 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
6788 :
6789 465 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
6790 465 : SetMetadataItem("STATISTICS_MEAN", szValue);
6791 :
6792 465 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
6793 465 : SetMetadataItem("STATISTICS_STDDEV", szValue);
6794 :
6795 465 : return CE_None;
6796 : }
6797 :
6798 : /************************************************************************/
6799 : /* GDALSetRasterStatistics() */
6800 : /************************************************************************/
6801 :
6802 : /**
6803 : * \brief Set statistics on band.
6804 : *
6805 : * @see GDALRasterBand::SetStatistics()
6806 : */
6807 :
6808 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
6809 : double dfMax, double dfMean,
6810 : double dfStdDev)
6811 :
6812 : {
6813 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
6814 :
6815 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6816 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6817 : }
6818 :
6819 : /************************************************************************/
6820 : /* ComputeRasterMinMax() */
6821 : /************************************************************************/
6822 :
6823 : template <class T, bool HAS_NODATA>
6824 134689 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
6825 : T *pMax)
6826 : {
6827 134689 : T min0 = *pMin;
6828 134689 : T max0 = *pMax;
6829 134689 : T min1 = *pMin;
6830 134689 : T max1 = *pMax;
6831 : size_t i;
6832 1017014 : for (i = 0; i + 1 < nElts; i += 2)
6833 : {
6834 869734 : if (!HAS_NODATA || buffer[i] != nodataValue)
6835 : {
6836 881141 : min0 = std::min(min0, buffer[i]);
6837 881141 : max0 = std::max(max0, buffer[i]);
6838 : }
6839 869734 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
6840 : {
6841 881354 : min1 = std::min(min1, buffer[i + 1]);
6842 881354 : max1 = std::max(max1, buffer[i + 1]);
6843 : }
6844 : }
6845 134689 : T min = std::min(min0, min1);
6846 134689 : T max = std::max(max0, max1);
6847 134689 : if (i < nElts)
6848 : {
6849 119260 : if (!HAS_NODATA || buffer[i] != nodataValue)
6850 : {
6851 119276 : min = std::min(min, buffer[i]);
6852 119276 : max = std::max(max, buffer[i]);
6853 : }
6854 : }
6855 134689 : *pMin = min;
6856 134689 : *pMax = max;
6857 134689 : }
6858 :
6859 : template <GDALDataType eDataType, bool bSignedByte>
6860 11512 : static void ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
6861 : int nBlockXSize, bool bGotNoDataValue,
6862 : double dfNoDataValue,
6863 : bool bGotFloatNoDataValue, float fNoDataValue,
6864 : const GByte *pabyMaskData, double &dfMin,
6865 : double &dfMax)
6866 : {
6867 11512 : double dfLocalMin = dfMin;
6868 11512 : double dfLocalMax = dfMax;
6869 :
6870 43491 : for (int iY = 0; iY < nYCheck; iY++)
6871 : {
6872 18965527 : for (int iX = 0; iX < nXCheck; iX++)
6873 : {
6874 18933565 : const GPtrDiff_t iOffset =
6875 18933565 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6876 18933565 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6877 3460307 : continue;
6878 18839324 : bool bValid = true;
6879 18839324 : double dfValue = GetPixelValue(
6880 : eDataType, bSignedByte, pData, iOffset, bGotNoDataValue,
6881 : dfNoDataValue, bGotFloatNoDataValue, fNoDataValue, bValid);
6882 18839324 : if (!bValid)
6883 3366066 : continue;
6884 :
6885 15473217 : dfLocalMin = std::min(dfLocalMin, dfValue);
6886 15473217 : dfLocalMax = std::max(dfLocalMax, dfValue);
6887 : }
6888 : }
6889 :
6890 11512 : dfMin = dfLocalMin;
6891 11512 : dfMax = dfLocalMax;
6892 11512 : }
6893 :
6894 11512 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
6895 : bool bSignedByte, int nXCheck, int nYCheck,
6896 : int nBlockXSize, bool bGotNoDataValue,
6897 : double dfNoDataValue,
6898 : bool bGotFloatNoDataValue, float fNoDataValue,
6899 : const GByte *pabyMaskData, double &dfMin,
6900 : double &dfMax)
6901 : {
6902 11512 : switch (eDataType)
6903 : {
6904 0 : case GDT_Unknown:
6905 0 : CPLAssert(false);
6906 : break;
6907 672 : case GDT_Byte:
6908 672 : if (bSignedByte)
6909 : {
6910 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
6911 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6912 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6913 : }
6914 : else
6915 : {
6916 669 : ComputeMinMaxGeneric<GDT_Byte, false>(
6917 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6918 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6919 : }
6920 672 : break;
6921 102 : case GDT_Int8:
6922 102 : ComputeMinMaxGeneric<GDT_Int8, false>(
6923 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6924 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6925 102 : break;
6926 200 : case GDT_UInt16:
6927 200 : ComputeMinMaxGeneric<GDT_UInt16, false>(
6928 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6929 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6930 200 : break;
6931 1 : case GDT_Int16:
6932 1 : ComputeMinMaxGeneric<GDT_Int16, false>(
6933 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6934 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6935 1 : break;
6936 197 : case GDT_UInt32:
6937 197 : ComputeMinMaxGeneric<GDT_UInt32, false>(
6938 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6939 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6940 197 : break;
6941 1111 : case GDT_Int32:
6942 1111 : ComputeMinMaxGeneric<GDT_Int32, false>(
6943 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6944 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6945 1111 : break;
6946 12 : case GDT_UInt64:
6947 12 : ComputeMinMaxGeneric<GDT_UInt64, false>(
6948 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6949 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6950 12 : break;
6951 24 : case GDT_Int64:
6952 24 : ComputeMinMaxGeneric<GDT_Int64, false>(
6953 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6954 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6955 24 : break;
6956 5675 : case GDT_Float32:
6957 5675 : ComputeMinMaxGeneric<GDT_Float32, false>(
6958 : pData, nXCheck, nYCheck, nBlockXSize, false, 0,
6959 : bGotFloatNoDataValue, fNoDataValue, pabyMaskData, dfMin, dfMax);
6960 5675 : break;
6961 3408 : case GDT_Float64:
6962 3408 : ComputeMinMaxGeneric<GDT_Float64, false>(
6963 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6964 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6965 3408 : break;
6966 9 : case GDT_CInt16:
6967 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(
6968 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6969 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6970 9 : break;
6971 9 : case GDT_CInt32:
6972 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(
6973 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6974 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6975 9 : break;
6976 75 : case GDT_CFloat32:
6977 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
6978 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6979 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6980 75 : break;
6981 17 : case GDT_CFloat64:
6982 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
6983 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6984 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6985 17 : break;
6986 0 : case GDT_TypeCount:
6987 0 : CPLAssert(false);
6988 : break;
6989 : }
6990 11512 : }
6991 :
6992 704 : static bool ComputeMinMaxGenericIterBlocks(
6993 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
6994 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
6995 : bool bGotNoDataValue, double dfNoDataValue, bool bGotFloatNoDataValue,
6996 : float fNoDataValue, GDALRasterBand *poMaskBand, double &dfMin,
6997 : double &dfMax)
6998 :
6999 : {
7000 704 : GByte *pabyMaskData = nullptr;
7001 : int nBlockXSize, nBlockYSize;
7002 704 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7003 :
7004 704 : if (poMaskBand)
7005 : {
7006 : pabyMaskData =
7007 40 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7008 40 : if (!pabyMaskData)
7009 : {
7010 0 : return false;
7011 : }
7012 : }
7013 :
7014 12216 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7015 11512 : iSampleBlock += nSampleRate)
7016 : {
7017 11512 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7018 11512 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7019 :
7020 11512 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7021 11512 : if (poBlock == nullptr)
7022 : {
7023 0 : CPLFree(pabyMaskData);
7024 0 : return false;
7025 : }
7026 :
7027 11512 : void *const pData = poBlock->GetDataRef();
7028 :
7029 11512 : int nXCheck = 0, nYCheck = 0;
7030 11512 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7031 :
7032 12383 : if (poMaskBand &&
7033 871 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7034 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7035 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7036 : nBlockXSize, nullptr) != CE_None)
7037 : {
7038 0 : poBlock->DropLock();
7039 0 : CPLFree(pabyMaskData);
7040 0 : return false;
7041 : }
7042 :
7043 11512 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7044 11512 : nBlockXSize, CPL_TO_BOOL(bGotNoDataValue),
7045 : dfNoDataValue, bGotFloatNoDataValue, fNoDataValue,
7046 : pabyMaskData, dfMin, dfMax);
7047 :
7048 11512 : poBlock->DropLock();
7049 : }
7050 :
7051 704 : CPLFree(pabyMaskData);
7052 704 : return true;
7053 : }
7054 :
7055 : /**
7056 : * \brief Compute the min/max values for a band.
7057 : *
7058 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7059 : * be trusted. If it doesn't work, a subsample of blocks will be read to
7060 : * get an approximate min/max. If the band has a nodata value it will
7061 : * be excluded from the minimum and maximum.
7062 : *
7063 : * If bApprox is FALSE, then all pixels will be read and used to compute
7064 : * an exact range.
7065 : *
7066 : * This method is the same as the C function GDALComputeRasterMinMax().
7067 : *
7068 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7069 : * FALSE.
7070 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7071 : * maximum (adfMinMax[1]) are returned.
7072 : *
7073 : * @return CE_None on success or CE_Failure on failure.
7074 : */
7075 :
7076 1554 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7077 : {
7078 : /* -------------------------------------------------------------------- */
7079 : /* Does the driver already know the min/max? */
7080 : /* -------------------------------------------------------------------- */
7081 1554 : if (bApproxOK)
7082 : {
7083 12 : int bSuccessMin = FALSE;
7084 12 : int bSuccessMax = FALSE;
7085 :
7086 12 : double dfMin = GetMinimum(&bSuccessMin);
7087 12 : double dfMax = GetMaximum(&bSuccessMax);
7088 :
7089 12 : if (bSuccessMin && bSuccessMax)
7090 : {
7091 1 : adfMinMax[0] = dfMin;
7092 1 : adfMinMax[1] = dfMax;
7093 1 : return CE_None;
7094 : }
7095 : }
7096 :
7097 : /* -------------------------------------------------------------------- */
7098 : /* If we have overview bands, use them for min/max. */
7099 : /* -------------------------------------------------------------------- */
7100 : // cppcheck-suppress knownConditionTrueFalse
7101 1553 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7102 : {
7103 : GDALRasterBand *poBand =
7104 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7105 :
7106 0 : if (poBand != this)
7107 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7108 : }
7109 :
7110 : /* -------------------------------------------------------------------- */
7111 : /* Read actual data and compute minimum and maximum. */
7112 : /* -------------------------------------------------------------------- */
7113 1553 : int bGotNoDataValue = FALSE;
7114 1553 : const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
7115 1553 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
7116 1553 : bool bGotFloatNoDataValue = false;
7117 1553 : float fNoDataValue = 0.0f;
7118 1553 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
7119 : fNoDataValue, bGotFloatNoDataValue);
7120 :
7121 1553 : GDALRasterBand *poMaskBand = nullptr;
7122 1553 : if (!bGotNoDataValue)
7123 : {
7124 1289 : const int l_nMaskFlags = GetMaskFlags();
7125 1329 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7126 40 : GetColorInterpretation() != GCI_AlphaBand)
7127 : {
7128 40 : poMaskBand = GetMaskBand();
7129 : }
7130 : }
7131 :
7132 1553 : bool bSignedByte = false;
7133 1553 : if (eDataType == GDT_Byte)
7134 : {
7135 638 : EnablePixelTypeSignedByteWarning(false);
7136 : const char *pszPixelType =
7137 638 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7138 638 : EnablePixelTypeSignedByteWarning(true);
7139 638 : bSignedByte =
7140 638 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7141 : }
7142 :
7143 : GDALRasterIOExtraArg sExtraArg;
7144 1553 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7145 :
7146 3106 : GUInt32 nMin = (eDataType == GDT_Byte)
7147 1553 : ? 255
7148 : : 65535; // used for GByte & GUInt16 cases
7149 1553 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
7150 1553 : GInt16 nMinInt16 =
7151 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
7152 1553 : GInt16 nMaxInt16 =
7153 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
7154 1553 : double dfMin =
7155 : std::numeric_limits<double>::max(); // used for generic code path
7156 1553 : double dfMax =
7157 : -std::numeric_limits<double>::max(); // used for generic code path
7158 1553 : const bool bUseOptimizedPath =
7159 2459 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7160 906 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7161 :
7162 : const auto ComputeMinMaxForBlock =
7163 18582 : [this, bSignedByte, bGotNoDataValue, dfNoDataValue, &nMin, &nMax,
7164 : &nMinInt16, &nMaxInt16](const void *pData, int nXCheck,
7165 241828 : int nBufferWidth, int nYCheck)
7166 : {
7167 18582 : if (eDataType == GDT_Byte && !bSignedByte)
7168 : {
7169 : const bool bHasNoData =
7170 25669 : bGotNoDataValue && GDALIsValueInRange<GByte>(dfNoDataValue) &&
7171 9501 : static_cast<GByte>(dfNoDataValue) == dfNoDataValue;
7172 16168 : const GUInt32 nNoDataValue =
7173 16168 : bHasNoData ? static_cast<GByte>(dfNoDataValue) : 0;
7174 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7175 : ComputeStatisticsInternal<GByte,
7176 : /* COMPUTE_OTHER_STATS = */ false>::
7177 16168 : f(nXCheck, nBufferWidth, nYCheck,
7178 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7179 16168 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7180 : }
7181 2414 : else if (eDataType == GDT_UInt16)
7182 : {
7183 : const bool bHasNoData =
7184 973 : bGotNoDataValue && GDALIsValueInRange<GUInt16>(dfNoDataValue) &&
7185 83 : static_cast<GUInt16>(dfNoDataValue) == dfNoDataValue;
7186 890 : const GUInt32 nNoDataValue =
7187 890 : bHasNoData ? static_cast<GUInt16>(dfNoDataValue) : 0;
7188 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7189 : ComputeStatisticsInternal<GUInt16,
7190 : /* COMPUTE_OTHER_STATS = */ false>::
7191 890 : f(nXCheck, nBufferWidth, nYCheck,
7192 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7193 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7194 : }
7195 1524 : else if (eDataType == GDT_Int16)
7196 : {
7197 : const bool bHasNoData =
7198 2877 : bGotNoDataValue && GDALIsValueInRange<int16_t>(dfNoDataValue) &&
7199 1353 : static_cast<int16_t>(dfNoDataValue) == dfNoDataValue;
7200 1524 : if (bHasNoData)
7201 : {
7202 1353 : const int16_t nNoDataValue =
7203 : static_cast<int16_t>(dfNoDataValue);
7204 134754 : for (int iY = 0; iY < nYCheck; iY++)
7205 : {
7206 133401 : ComputeMinMax<int16_t, true>(
7207 133401 : static_cast<const int16_t *>(pData) +
7208 133401 : static_cast<size_t>(iY) * nBufferWidth,
7209 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7210 : }
7211 : }
7212 : else
7213 : {
7214 1459 : for (int iY = 0; iY < nYCheck; iY++)
7215 : {
7216 1288 : ComputeMinMax<int16_t, false>(
7217 1288 : static_cast<const int16_t *>(pData) +
7218 1288 : static_cast<size_t>(iY) * nBufferWidth,
7219 : nXCheck, 0, &nMinInt16, &nMaxInt16);
7220 : }
7221 : }
7222 : }
7223 18582 : };
7224 :
7225 1553 : if (bApproxOK && HasArbitraryOverviews())
7226 : {
7227 : /* --------------------------------------------------------------------
7228 : */
7229 : /* Figure out how much the image should be reduced to get an */
7230 : /* approximate value. */
7231 : /* --------------------------------------------------------------------
7232 : */
7233 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7234 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7235 :
7236 0 : int nXReduced = nRasterXSize;
7237 0 : int nYReduced = nRasterYSize;
7238 0 : if (dfReduction > 1.0)
7239 : {
7240 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7241 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7242 :
7243 : // Catch the case of huge resizing ratios here
7244 0 : if (nXReduced == 0)
7245 0 : nXReduced = 1;
7246 0 : if (nYReduced == 0)
7247 0 : nYReduced = 1;
7248 : }
7249 :
7250 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
7251 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7252 :
7253 : const CPLErr eErr =
7254 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7255 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7256 0 : if (eErr != CE_None)
7257 : {
7258 0 : CPLFree(pData);
7259 0 : return eErr;
7260 : }
7261 :
7262 0 : GByte *pabyMaskData = nullptr;
7263 0 : if (poMaskBand)
7264 : {
7265 : pabyMaskData =
7266 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7267 0 : if (!pabyMaskData)
7268 : {
7269 0 : CPLFree(pData);
7270 0 : return CE_Failure;
7271 : }
7272 :
7273 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7274 : pabyMaskData, nXReduced, nYReduced,
7275 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
7276 : {
7277 0 : CPLFree(pData);
7278 0 : CPLFree(pabyMaskData);
7279 0 : return CE_Failure;
7280 : }
7281 : }
7282 :
7283 0 : if (bUseOptimizedPath)
7284 : {
7285 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7286 : }
7287 : else
7288 : {
7289 0 : ComputeMinMaxGeneric(
7290 : pData, eDataType, bSignedByte, nXReduced, nYReduced, nXReduced,
7291 0 : CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
7292 : bGotFloatNoDataValue, fNoDataValue, pabyMaskData, dfMin, dfMax);
7293 : }
7294 :
7295 0 : CPLFree(pData);
7296 0 : CPLFree(pabyMaskData);
7297 : }
7298 :
7299 : else // No arbitrary overviews
7300 : {
7301 1553 : if (!InitBlockInfo())
7302 0 : return CE_Failure;
7303 :
7304 : /* --------------------------------------------------------------------
7305 : */
7306 : /* Figure out the ratio of blocks we will read to get an */
7307 : /* approximate value. */
7308 : /* --------------------------------------------------------------------
7309 : */
7310 1553 : int nSampleRate = 1;
7311 :
7312 1553 : if (bApproxOK)
7313 : {
7314 11 : nSampleRate = static_cast<int>(std::max(
7315 22 : 1.0,
7316 11 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7317 : // We want to avoid probing only the first column of blocks for
7318 : // a square shaped raster, because it is not unlikely that it may
7319 : // be padding only (#6378).
7320 11 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7321 0 : nSampleRate += 1;
7322 : }
7323 :
7324 1553 : if (bUseOptimizedPath)
7325 : {
7326 849 : for (GIntBig iSampleBlock = 0;
7327 19357 : iSampleBlock <
7328 19357 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7329 18508 : iSampleBlock += nSampleRate)
7330 : {
7331 18583 : const int iYBlock =
7332 18583 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7333 18583 : const int iXBlock =
7334 18583 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7335 :
7336 18583 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7337 18583 : if (poBlock == nullptr)
7338 1 : return CE_Failure;
7339 :
7340 18582 : void *const pData = poBlock->GetDataRef();
7341 :
7342 18582 : int nXCheck = 0, nYCheck = 0;
7343 18582 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7344 :
7345 18582 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7346 :
7347 18582 : poBlock->DropLock();
7348 :
7349 18582 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7350 4120 : nMax == 255)
7351 74 : break;
7352 : }
7353 : }
7354 : else
7355 : {
7356 704 : const GIntBig nTotalBlocks =
7357 704 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7358 704 : if (!ComputeMinMaxGenericIterBlocks(
7359 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7360 704 : nBlocksPerRow, CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
7361 : bGotFloatNoDataValue, fNoDataValue, poMaskBand, dfMin,
7362 : dfMax))
7363 : {
7364 0 : return CE_Failure;
7365 : }
7366 : }
7367 : }
7368 :
7369 1552 : if (bUseOptimizedPath)
7370 : {
7371 848 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7372 : {
7373 736 : dfMin = nMin;
7374 736 : dfMax = nMax;
7375 : }
7376 112 : else if (eDataType == GDT_Int16)
7377 : {
7378 112 : dfMin = nMinInt16;
7379 112 : dfMax = nMaxInt16;
7380 : }
7381 : }
7382 :
7383 1552 : if (dfMin > dfMax)
7384 : {
7385 4 : adfMinMax[0] = 0;
7386 4 : adfMinMax[1] = 0;
7387 4 : ReportError(
7388 : CE_Failure, CPLE_AppDefined,
7389 : "Failed to compute min/max, no valid pixels found in sampling.");
7390 4 : return CE_Failure;
7391 : }
7392 :
7393 1548 : adfMinMax[0] = dfMin;
7394 1548 : adfMinMax[1] = dfMax;
7395 :
7396 1548 : return CE_None;
7397 : }
7398 :
7399 : /************************************************************************/
7400 : /* GDALComputeRasterMinMax() */
7401 : /************************************************************************/
7402 :
7403 : /**
7404 : * \brief Compute the min/max values for a band.
7405 : *
7406 : * @see GDALRasterBand::ComputeRasterMinMax()
7407 : *
7408 : * @note Prior to GDAL 3.6, this function returned void
7409 : */
7410 :
7411 1476 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7412 : double adfMinMax[2])
7413 :
7414 : {
7415 1476 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7416 :
7417 1476 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7418 1476 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7419 : }
7420 :
7421 : /************************************************************************/
7422 : /* ComputeRasterMinMaxLocation() */
7423 : /************************************************************************/
7424 :
7425 : /**
7426 : * \brief Compute the min/max values for a band, and their location.
7427 : *
7428 : * Pixels whose value matches the nodata value or are masked by the mask
7429 : * band are ignored.
7430 : *
7431 : * If the minimum or maximum value is hit in several locations, it is not
7432 : * specified which one will be returned.
7433 : *
7434 : * @param[out] pdfMin Pointer to the minimum value.
7435 : * @param[out] pdfMax Pointer to the maximum value.
7436 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7437 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7438 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7439 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7440 : *
7441 : * @return CE_None in case of success, CE_Warning if there are no valid values,
7442 : * CE_Failure in case of error.
7443 : *
7444 : * @since GDAL 3.11
7445 : */
7446 :
7447 8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7448 : double *pdfMax, int *pnMinX,
7449 : int *pnMinY, int *pnMaxX,
7450 : int *pnMaxY)
7451 : {
7452 8 : int nMinX = -1;
7453 8 : int nMinY = -1;
7454 8 : int nMaxX = -1;
7455 8 : int nMaxY = -1;
7456 8 : double dfMin = std::numeric_limits<double>::infinity();
7457 8 : double dfMax = -std::numeric_limits<double>::infinity();
7458 8 : if (pdfMin)
7459 5 : *pdfMin = dfMin;
7460 8 : if (pdfMax)
7461 5 : *pdfMax = dfMax;
7462 8 : if (pnMinX)
7463 6 : *pnMinX = nMinX;
7464 8 : if (pnMinY)
7465 6 : *pnMinY = nMinY;
7466 8 : if (pnMaxX)
7467 6 : *pnMaxX = nMaxX;
7468 8 : if (pnMaxY)
7469 6 : *pnMaxY = nMaxY;
7470 :
7471 8 : if (GDALDataTypeIsComplex(eDataType))
7472 : {
7473 0 : CPLError(CE_Failure, CPLE_NotSupported,
7474 : "Complex data type not supported");
7475 0 : return CE_Failure;
7476 : }
7477 :
7478 8 : if (!InitBlockInfo())
7479 0 : return CE_Failure;
7480 :
7481 8 : int bGotNoDataValue = FALSE;
7482 8 : const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
7483 8 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
7484 8 : bool bGotFloatNoDataValue = false;
7485 8 : float fNoDataValue = 0.0f;
7486 8 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
7487 : fNoDataValue, bGotFloatNoDataValue);
7488 :
7489 8 : GDALRasterBand *poMaskBand = nullptr;
7490 8 : if (!bGotNoDataValue)
7491 : {
7492 8 : const int l_nMaskFlags = GetMaskFlags();
7493 9 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7494 1 : GetColorInterpretation() != GCI_AlphaBand)
7495 : {
7496 1 : poMaskBand = GetMaskBand();
7497 : }
7498 : }
7499 :
7500 8 : bool bSignedByte = false;
7501 8 : if (eDataType == GDT_Byte)
7502 : {
7503 7 : EnablePixelTypeSignedByteWarning(false);
7504 : const char *pszPixelType =
7505 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7506 7 : EnablePixelTypeSignedByteWarning(true);
7507 7 : bSignedByte =
7508 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7509 : }
7510 :
7511 8 : GByte *pabyMaskData = nullptr;
7512 8 : if (poMaskBand)
7513 : {
7514 : pabyMaskData =
7515 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7516 1 : if (!pabyMaskData)
7517 : {
7518 0 : return CE_Failure;
7519 : }
7520 : }
7521 :
7522 8 : const GIntBig nTotalBlocks =
7523 8 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7524 8 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7525 8 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7526 16 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7527 : {
7528 11 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7529 11 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7530 :
7531 11 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7532 11 : if (poBlock == nullptr)
7533 : {
7534 0 : CPLFree(pabyMaskData);
7535 0 : return CE_Failure;
7536 : }
7537 :
7538 11 : void *const pData = poBlock->GetDataRef();
7539 :
7540 11 : int nXCheck = 0, nYCheck = 0;
7541 11 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7542 :
7543 13 : if (poMaskBand &&
7544 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7545 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7546 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7547 2 : nBlockXSize, nullptr) != CE_None)
7548 : {
7549 0 : poBlock->DropLock();
7550 0 : CPLFree(pabyMaskData);
7551 0 : return CE_Failure;
7552 : }
7553 :
7554 11 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7555 : {
7556 4 : for (int iY = 0; iY < nYCheck; ++iY)
7557 : {
7558 6 : for (int iX = 0; iX < nXCheck; ++iX)
7559 : {
7560 4 : const GPtrDiff_t iOffset =
7561 4 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7562 4 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7563 2 : continue;
7564 2 : bool bValid = true;
7565 2 : double dfValue = GetPixelValue(
7566 : eDataType, bSignedByte, pData, iOffset, bGotNoDataValue,
7567 : dfNoDataValue, bGotFloatNoDataValue, fNoDataValue,
7568 : bValid);
7569 2 : if (!bValid)
7570 0 : continue;
7571 2 : if (dfValue < dfMin)
7572 : {
7573 2 : dfMin = dfValue;
7574 2 : nMinX = iXBlock * nBlockXSize + iX;
7575 2 : nMinY = iYBlock * nBlockYSize + iY;
7576 : }
7577 2 : if (dfValue > dfMax)
7578 : {
7579 1 : dfMax = dfValue;
7580 1 : nMaxX = iXBlock * nBlockXSize + iX;
7581 1 : nMaxY = iYBlock * nBlockYSize + iY;
7582 : }
7583 : }
7584 2 : }
7585 : }
7586 : else
7587 : {
7588 9 : size_t pos_min = 0;
7589 9 : size_t pos_max = 0;
7590 9 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7591 9 : if (bNeedsMin && bNeedsMax)
7592 : {
7593 10 : std::tie(pos_min, pos_max) = gdal::minmax_element(
7594 5 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7595 10 : eEffectiveDT, bGotNoDataValue, dfNoDataValue);
7596 : }
7597 4 : else if (bNeedsMin)
7598 : {
7599 1 : pos_min = gdal::min_element(
7600 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7601 : eEffectiveDT, bGotNoDataValue, dfNoDataValue);
7602 : }
7603 3 : else if (bNeedsMax)
7604 : {
7605 2 : pos_max = gdal::max_element(
7606 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7607 : eEffectiveDT, bGotNoDataValue, dfNoDataValue);
7608 : }
7609 :
7610 9 : if (bNeedsMin)
7611 : {
7612 6 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7613 6 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7614 6 : bool bValid = true;
7615 6 : const double dfMinValueBlock = GetPixelValue(
7616 : eDataType, bSignedByte, pData, pos_min, bGotNoDataValue,
7617 : dfNoDataValue, bGotFloatNoDataValue, fNoDataValue, bValid);
7618 6 : if (bValid && dfMinValueBlock < dfMin)
7619 : {
7620 5 : dfMin = dfMinValueBlock;
7621 5 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
7622 5 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
7623 : }
7624 : }
7625 :
7626 9 : if (bNeedsMax)
7627 : {
7628 7 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7629 7 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7630 7 : bool bValid = true;
7631 7 : const double dfMaxValueBlock = GetPixelValue(
7632 : eDataType, bSignedByte, pData, pos_max, bGotNoDataValue,
7633 : dfNoDataValue, bGotFloatNoDataValue, fNoDataValue, bValid);
7634 7 : if (bValid && dfMaxValueBlock > dfMax)
7635 : {
7636 5 : dfMax = dfMaxValueBlock;
7637 5 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7638 5 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7639 : }
7640 : }
7641 : }
7642 :
7643 11 : poBlock->DropLock();
7644 :
7645 11 : if (eDataType == GDT_Byte)
7646 : {
7647 10 : if (bNeedsMin && dfMin == 0)
7648 : {
7649 1 : bNeedsMin = false;
7650 : }
7651 10 : if (bNeedsMax && dfMax == 255)
7652 : {
7653 4 : bNeedsMax = false;
7654 : }
7655 10 : if (!bNeedsMin && !bNeedsMax)
7656 : {
7657 3 : break;
7658 : }
7659 : }
7660 : }
7661 :
7662 8 : CPLFree(pabyMaskData);
7663 :
7664 8 : if (pdfMin)
7665 5 : *pdfMin = dfMin;
7666 8 : if (pdfMax)
7667 5 : *pdfMax = dfMax;
7668 8 : if (pnMinX)
7669 6 : *pnMinX = nMinX;
7670 8 : if (pnMinY)
7671 6 : *pnMinY = nMinY;
7672 8 : if (pnMaxX)
7673 6 : *pnMaxX = nMaxX;
7674 8 : if (pnMaxY)
7675 6 : *pnMaxY = nMaxY;
7676 8 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
7677 8 : : CE_None;
7678 : }
7679 :
7680 : /************************************************************************/
7681 : /* GDALComputeRasterMinMaxLocation() */
7682 : /************************************************************************/
7683 :
7684 : /**
7685 : * \brief Compute the min/max values for a band, and their location.
7686 : *
7687 : * @see GDALRasterBand::ComputeRasterMinMax()
7688 : * @since GDAL 3.11
7689 : */
7690 :
7691 6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
7692 : double *pdfMax, int *pnMinX, int *pnMinY,
7693 : int *pnMaxX, int *pnMaxY)
7694 :
7695 : {
7696 6 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
7697 :
7698 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7699 6 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
7700 6 : pnMaxX, pnMaxY);
7701 : }
7702 :
7703 : /************************************************************************/
7704 : /* SetDefaultHistogram() */
7705 : /************************************************************************/
7706 :
7707 : /* FIXME : add proper documentation */
7708 : /**
7709 : * \brief Set default histogram.
7710 : *
7711 : * This method is the same as the C function GDALSetDefaultHistogram() and
7712 : * GDALSetDefaultHistogramEx()
7713 : */
7714 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
7715 : double /* dfMax */,
7716 : int /* nBuckets */,
7717 : GUIntBig * /* panHistogram */)
7718 :
7719 : {
7720 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
7721 0 : ReportError(CE_Failure, CPLE_NotSupported,
7722 : "SetDefaultHistogram() not implemented for this format.");
7723 :
7724 0 : return CE_Failure;
7725 : }
7726 :
7727 : /************************************************************************/
7728 : /* GDALSetDefaultHistogram() */
7729 : /************************************************************************/
7730 :
7731 : /**
7732 : * \brief Set default histogram.
7733 : *
7734 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
7735 : * 2 billion.
7736 : *
7737 : * @see GDALRasterBand::SetDefaultHistogram()
7738 : * @see GDALSetRasterHistogramEx()
7739 : */
7740 :
7741 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
7742 : double dfMax, int nBuckets,
7743 : int *panHistogram)
7744 :
7745 : {
7746 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
7747 :
7748 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7749 :
7750 : GUIntBig *panHistogramTemp =
7751 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
7752 0 : if (panHistogramTemp == nullptr)
7753 : {
7754 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
7755 : "Out of memory in GDALSetDefaultHistogram().");
7756 0 : return CE_Failure;
7757 : }
7758 :
7759 0 : for (int i = 0; i < nBuckets; ++i)
7760 : {
7761 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
7762 : }
7763 :
7764 : const CPLErr eErr =
7765 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
7766 :
7767 0 : CPLFree(panHistogramTemp);
7768 :
7769 0 : return eErr;
7770 : }
7771 :
7772 : /************************************************************************/
7773 : /* GDALSetDefaultHistogramEx() */
7774 : /************************************************************************/
7775 :
7776 : /**
7777 : * \brief Set default histogram.
7778 : *
7779 : * @see GDALRasterBand::SetDefaultHistogram()
7780 : *
7781 : * @since GDAL 2.0
7782 : */
7783 :
7784 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
7785 : double dfMin, double dfMax,
7786 : int nBuckets,
7787 : GUIntBig *panHistogram)
7788 :
7789 : {
7790 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
7791 :
7792 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7793 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
7794 : }
7795 :
7796 : /************************************************************************/
7797 : /* GetDefaultRAT() */
7798 : /************************************************************************/
7799 :
7800 : /**
7801 : * \brief Fetch default Raster Attribute Table.
7802 : *
7803 : * A RAT will be returned if there is a default one associated with the
7804 : * band, otherwise NULL is returned. The returned RAT is owned by the
7805 : * band and should not be deleted by the application.
7806 : *
7807 : * This method is the same as the C function GDALGetDefaultRAT().
7808 : *
7809 : * @return NULL, or a pointer to an internal RAT owned by the band.
7810 : */
7811 :
7812 112 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
7813 :
7814 : {
7815 112 : return nullptr;
7816 : }
7817 :
7818 : /************************************************************************/
7819 : /* GDALGetDefaultRAT() */
7820 : /************************************************************************/
7821 :
7822 : /**
7823 : * \brief Fetch default Raster Attribute Table.
7824 : *
7825 : * @see GDALRasterBand::GetDefaultRAT()
7826 : */
7827 :
7828 980 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
7829 :
7830 : {
7831 980 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
7832 :
7833 980 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7834 980 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
7835 : }
7836 :
7837 : /************************************************************************/
7838 : /* SetDefaultRAT() */
7839 : /************************************************************************/
7840 :
7841 : /**
7842 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
7843 : * \brief Set default Raster Attribute Table.
7844 : *
7845 : * Associates a default RAT with the band. If not implemented for the
7846 : * format a CPLE_NotSupported error will be issued. If successful a copy
7847 : * of the RAT is made, the original remains owned by the caller.
7848 : *
7849 : * This method is the same as the C function GDALSetDefaultRAT().
7850 : *
7851 : * @param poRAT the RAT to assign to the band.
7852 : *
7853 : * @return CE_None on success or CE_Failure if unsupported or otherwise
7854 : * failing.
7855 : */
7856 :
7857 : /**/
7858 : /**/
7859 :
7860 : CPLErr
7861 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
7862 : {
7863 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
7864 : {
7865 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
7866 0 : ReportError(CE_Failure, CPLE_NotSupported,
7867 : "SetDefaultRAT() not implemented for this format.");
7868 0 : CPLPopErrorHandler();
7869 : }
7870 0 : return CE_Failure;
7871 : }
7872 :
7873 : /************************************************************************/
7874 : /* GDALSetDefaultRAT() */
7875 : /************************************************************************/
7876 :
7877 : /**
7878 : * \brief Set default Raster Attribute Table.
7879 : *
7880 : * @see GDALRasterBand::GDALSetDefaultRAT()
7881 : */
7882 :
7883 18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
7884 : GDALRasterAttributeTableH hRAT)
7885 :
7886 : {
7887 18 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
7888 :
7889 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7890 :
7891 18 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
7892 : }
7893 :
7894 : /************************************************************************/
7895 : /* GetMaskBand() */
7896 : /************************************************************************/
7897 :
7898 : /**
7899 : * \brief Return the mask band associated with the band.
7900 : *
7901 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
7902 : * that returns one of four default implementations :
7903 : * <ul>
7904 : * <li>If a corresponding .msk file exists it will be used for the mask band.
7905 : * </li>
7906 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
7907 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
7908 : * GMF_NODATA | GMF_PER_DATASET.
7909 : * </li>
7910 : * <li>If the band has a nodata value set, an instance of the new
7911 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
7912 : * GMF_NODATA.
7913 : * </li>
7914 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
7915 : * to apply to this band (specific rules yet to be determined) and that is of
7916 : * type GDT_Byte then that alpha band will be returned, and the flags
7917 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
7918 : * </li>
7919 : * <li>If neither of the above apply, an instance of the new
7920 : * GDALAllValidRasterBand class will be returned that has 255 values for all
7921 : * pixels. The null flags will return GMF_ALL_VALID.
7922 : * </li>
7923 : * </ul>
7924 : *
7925 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
7926 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
7927 : *
7928 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
7929 : * dataset, with the same name as the main dataset and suffixed with .msk,
7930 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
7931 : * main dataset.
7932 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
7933 : * level, where xx matches the band number of a band of the main dataset. The
7934 : * value of those items is a combination of the flags GMF_ALL_VALID,
7935 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
7936 : * a band, then the other rules explained above will be used to generate a
7937 : * on-the-fly mask band.
7938 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
7939 : *
7940 : * This method is the same as the C function GDALGetMaskBand().
7941 : *
7942 : * @return a valid mask band.
7943 : *
7944 : * @since GDAL 1.5.0
7945 : *
7946 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
7947 : *
7948 : */
7949 733528 : GDALRasterBand *GDALRasterBand::GetMaskBand()
7950 :
7951 : {
7952 179537 : const auto HasNoData = [this]()
7953 : {
7954 59582 : int bHaveNoDataRaw = FALSE;
7955 59582 : bool bHaveNoData = false;
7956 59582 : if (eDataType == GDT_Int64)
7957 : {
7958 54 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
7959 54 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
7960 : }
7961 59528 : else if (eDataType == GDT_UInt64)
7962 : {
7963 41 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
7964 41 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
7965 : }
7966 : else
7967 : {
7968 59487 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
7969 59465 : if (bHaveNoDataRaw &&
7970 59465 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
7971 : {
7972 816 : bHaveNoData = true;
7973 : }
7974 : }
7975 59543 : return bHaveNoData;
7976 733528 : };
7977 :
7978 733528 : if (poMask != nullptr)
7979 : {
7980 704407 : if (poMask.IsOwned())
7981 : {
7982 324354 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
7983 : {
7984 31973 : if (HasNoData())
7985 : {
7986 9 : InvalidateMaskBand();
7987 : }
7988 : }
7989 294101 : else if (auto poNoDataMaskBand =
7990 293839 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
7991 : {
7992 182 : int bHaveNoDataRaw = FALSE;
7993 182 : bool bIsSame = false;
7994 182 : if (eDataType == GDT_Int64)
7995 9 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
7996 11 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
7997 2 : bHaveNoDataRaw;
7998 173 : else if (eDataType == GDT_UInt64)
7999 9 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8000 11 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8001 2 : bHaveNoDataRaw;
8002 : else
8003 : {
8004 : const double dfNoDataValue =
8005 164 : GetNoDataValue(&bHaveNoDataRaw);
8006 164 : if (bHaveNoDataRaw)
8007 : {
8008 161 : bIsSame =
8009 161 : std::isnan(dfNoDataValue)
8010 161 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8011 135 : : poNoDataMaskBand->m_dfNoDataValue ==
8012 : dfNoDataValue;
8013 : }
8014 : }
8015 182 : if (!bIsSame)
8016 23 : InvalidateMaskBand();
8017 : }
8018 : }
8019 :
8020 710316 : if (poMask)
8021 710581 : return poMask.get();
8022 : }
8023 :
8024 : /* -------------------------------------------------------------------- */
8025 : /* Check for a mask in a .msk file. */
8026 : /* -------------------------------------------------------------------- */
8027 27710 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8028 : {
8029 46 : poMask.reset(poDS->oOvManager.GetMaskBand(nBand), false);
8030 46 : if (poMask != nullptr)
8031 : {
8032 44 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8033 44 : return poMask.get();
8034 : }
8035 : }
8036 :
8037 : /* -------------------------------------------------------------------- */
8038 : /* Check for NODATA_VALUES metadata. */
8039 : /* -------------------------------------------------------------------- */
8040 27667 : if (poDS != nullptr)
8041 : {
8042 27652 : const char *pszNoDataValues = poDS->GetMetadataItem("NODATA_VALUES");
8043 27652 : if (pszNoDataValues != nullptr)
8044 : {
8045 : char **papszNoDataValues =
8046 56 : CSLTokenizeStringComplex(pszNoDataValues, " ", FALSE, FALSE);
8047 :
8048 : // Make sure we have as many values as bands.
8049 112 : if (CSLCount(papszNoDataValues) == poDS->GetRasterCount() &&
8050 56 : poDS->GetRasterCount() != 0)
8051 : {
8052 : // Make sure that all bands have the same data type
8053 : // This is clearly not a fundamental condition, just a
8054 : // condition to make implementation easier.
8055 56 : GDALDataType eDT = GDT_Unknown;
8056 56 : int i = 0; // Used after for.
8057 224 : for (; i < poDS->GetRasterCount(); ++i)
8058 : {
8059 168 : if (i == 0)
8060 56 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8061 112 : else if (eDT !=
8062 112 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
8063 : {
8064 0 : break;
8065 : }
8066 : }
8067 56 : if (i == poDS->GetRasterCount())
8068 : {
8069 56 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8070 : try
8071 : {
8072 56 : poMask.reset(new GDALNoDataValuesMaskBand(poDS), true);
8073 : }
8074 0 : catch (const std::bad_alloc &)
8075 : {
8076 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8077 0 : poMask.reset();
8078 : }
8079 56 : CSLDestroy(papszNoDataValues);
8080 56 : return poMask.get();
8081 : }
8082 : else
8083 : {
8084 0 : ReportError(CE_Warning, CPLE_AppDefined,
8085 : "All bands should have the same type in "
8086 : "order the NODATA_VALUES metadata item "
8087 : "to be used as a mask.");
8088 : }
8089 : }
8090 : else
8091 : {
8092 0 : ReportError(
8093 : CE_Warning, CPLE_AppDefined,
8094 : "NODATA_VALUES metadata item doesn't have the same number "
8095 : "of values as the number of bands. "
8096 : "Ignoring it for mask.");
8097 : }
8098 :
8099 0 : CSLDestroy(papszNoDataValues);
8100 : }
8101 : }
8102 :
8103 : /* -------------------------------------------------------------------- */
8104 : /* Check for nodata case. */
8105 : /* -------------------------------------------------------------------- */
8106 27611 : if (HasNoData())
8107 : {
8108 838 : nMaskFlags = GMF_NODATA;
8109 : try
8110 : {
8111 838 : poMask.reset(new GDALNoDataMaskBand(this), true);
8112 : }
8113 0 : catch (const std::bad_alloc &)
8114 : {
8115 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8116 0 : poMask.reset();
8117 : }
8118 838 : return poMask.get();
8119 : }
8120 :
8121 : /* -------------------------------------------------------------------- */
8122 : /* Check for alpha case. */
8123 : /* -------------------------------------------------------------------- */
8124 26759 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8125 54059 : this == poDS->GetRasterBand(1) &&
8126 526 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8127 : {
8128 196 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8129 : {
8130 152 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8131 152 : poMask.reset(poDS->GetRasterBand(2), false);
8132 152 : return poMask.get();
8133 : }
8134 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8135 : {
8136 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8137 : try
8138 : {
8139 23 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(2)),
8140 : true);
8141 : }
8142 0 : catch (const std::bad_alloc &)
8143 : {
8144 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8145 0 : poMask.reset();
8146 : }
8147 23 : return poMask.get();
8148 : }
8149 : }
8150 :
8151 26584 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8152 2697 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8153 53822 : this == poDS->GetRasterBand(3)) &&
8154 2106 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8155 : {
8156 1224 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8157 : {
8158 1177 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8159 1177 : poMask.reset(poDS->GetRasterBand(4), false);
8160 1177 : return poMask.get();
8161 : }
8162 47 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8163 : {
8164 35 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8165 : try
8166 : {
8167 35 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(4)),
8168 : true);
8169 : }
8170 0 : catch (const std::bad_alloc &)
8171 : {
8172 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8173 0 : poMask.reset();
8174 : }
8175 35 : return poMask.get();
8176 : }
8177 : }
8178 :
8179 : /* -------------------------------------------------------------------- */
8180 : /* Fallback to all valid case. */
8181 : /* -------------------------------------------------------------------- */
8182 25387 : nMaskFlags = GMF_ALL_VALID;
8183 : try
8184 : {
8185 25387 : poMask.reset(new GDALAllValidMaskBand(this), true);
8186 : }
8187 0 : catch (const std::bad_alloc &)
8188 : {
8189 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8190 0 : poMask.reset();
8191 : }
8192 :
8193 25386 : return poMask.get();
8194 : }
8195 :
8196 : /************************************************************************/
8197 : /* GDALGetMaskBand() */
8198 : /************************************************************************/
8199 :
8200 : /**
8201 : * \brief Return the mask band associated with the band.
8202 : *
8203 : * @see GDALRasterBand::GetMaskBand()
8204 : */
8205 :
8206 10910 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8207 :
8208 : {
8209 10910 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8210 :
8211 10910 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8212 10910 : return poBand->GetMaskBand();
8213 : }
8214 :
8215 : /************************************************************************/
8216 : /* GetMaskFlags() */
8217 : /************************************************************************/
8218 :
8219 : /**
8220 : * \brief Return the status flags of the mask band associated with the band.
8221 : *
8222 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8223 : * the following available definitions that may be extended in the future:
8224 : * <ul>
8225 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8226 : * 255. When used this will normally be the only flag set.
8227 : * </li>
8228 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8229 : * dataset.
8230 : * </li>
8231 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8232 : * and may have values other than 0 and 255.
8233 : * </li>
8234 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8235 : * nodata values. (mutually exclusive of GMF_ALPHA)
8236 : * </li>
8237 : * </ul>
8238 : *
8239 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8240 : * that returns one of four default implementations:
8241 : * <ul>
8242 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8243 : * </li>
8244 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8245 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8246 : * GMF_NODATA | GMF_PER_DATASET.
8247 : * </li>
8248 : * <li>If the band has a nodata value set, an instance of the new
8249 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8250 : * GMF_NODATA.
8251 : * </li>
8252 : * <li>If there is no nodata value, but the dataset has an alpha band that
8253 : * seems to apply to this band (specific rules yet to be determined) and that is
8254 : * of type GDT_Byte then that alpha band will be returned, and the flags
8255 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8256 : * </li>
8257 : * <li>If neither of the above apply, an instance of the new
8258 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8259 : * pixels. The null flags will return GMF_ALL_VALID.
8260 : * </li>
8261 : * </ul>
8262 : *
8263 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8264 : * dataset, with the same name as the main dataset and suffixed with .msk,
8265 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8266 : * main dataset.
8267 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8268 : * level, where xx matches the band number of a band of the main dataset. The
8269 : * value of those items is a combination of the flags GMF_ALL_VALID,
8270 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8271 : * a band, then the other rules explained above will be used to generate a
8272 : * on-the-fly mask band.
8273 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8274 : *
8275 : * This method is the same as the C function GDALGetMaskFlags().
8276 : *
8277 : * @since GDAL 1.5.0
8278 : *
8279 : * @return a valid mask band.
8280 : *
8281 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8282 : *
8283 : */
8284 78922 : int GDALRasterBand::GetMaskFlags()
8285 :
8286 : {
8287 : // If we don't have a band yet, force this now so that the masks value
8288 : // will be initialized.
8289 :
8290 78922 : if (poMask == nullptr)
8291 26489 : GetMaskBand();
8292 :
8293 78916 : return nMaskFlags;
8294 : }
8295 :
8296 : /************************************************************************/
8297 : /* GDALGetMaskFlags() */
8298 : /************************************************************************/
8299 :
8300 : /**
8301 : * \brief Return the status flags of the mask band associated with the band.
8302 : *
8303 : * @see GDALRasterBand::GetMaskFlags()
8304 : */
8305 :
8306 6101 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8307 :
8308 : {
8309 6101 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8310 :
8311 6101 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8312 6101 : return poBand->GetMaskFlags();
8313 : }
8314 :
8315 : /************************************************************************/
8316 : /* InvalidateMaskBand() */
8317 : /************************************************************************/
8318 :
8319 : //! @cond Doxygen_Suppress
8320 1200240 : void GDALRasterBand::InvalidateMaskBand()
8321 : {
8322 1200240 : poMask.reset();
8323 1200230 : nMaskFlags = 0;
8324 1200230 : }
8325 :
8326 : //! @endcond
8327 :
8328 : /************************************************************************/
8329 : /* CreateMaskBand() */
8330 : /************************************************************************/
8331 :
8332 : /**
8333 : * \brief Adds a mask band to the current band
8334 : *
8335 : * The default implementation of the CreateMaskBand() method is implemented
8336 : * based on similar rules to the .ovr handling implemented using the
8337 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8338 : * be created with the same basename as the original file, and it will have
8339 : * as many bands as the original image (or just one for GMF_PER_DATASET).
8340 : * The mask images will be deflate compressed tiled images with the same
8341 : * block size as the original image if possible.
8342 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8343 : * level, where xx matches the band number of a band of the main dataset. The
8344 : * value of those items will be the one of the nFlagsIn parameter.
8345 : *
8346 : * Note that if you got a mask band with a previous call to GetMaskBand(),
8347 : * it might be invalidated by CreateMaskBand(). So you have to call
8348 : * GetMaskBand() again.
8349 : *
8350 : * This method is the same as the C function GDALCreateMaskBand().
8351 : *
8352 : * @since GDAL 1.5.0
8353 : *
8354 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8355 : *
8356 : * @return CE_None on success or CE_Failure on an error.
8357 : *
8358 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8359 : * @see GDALDataset::CreateMaskBand()
8360 : *
8361 : */
8362 :
8363 9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8364 :
8365 : {
8366 9 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8367 : {
8368 9 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8369 9 : if (eErr != CE_None)
8370 1 : return eErr;
8371 :
8372 8 : InvalidateMaskBand();
8373 :
8374 8 : return CE_None;
8375 : }
8376 :
8377 0 : ReportError(CE_Failure, CPLE_NotSupported,
8378 : "CreateMaskBand() not supported for this band.");
8379 :
8380 0 : return CE_Failure;
8381 : }
8382 :
8383 : /************************************************************************/
8384 : /* GDALCreateMaskBand() */
8385 : /************************************************************************/
8386 :
8387 : /**
8388 : * \brief Adds a mask band to the current band
8389 : *
8390 : * @see GDALRasterBand::CreateMaskBand()
8391 : */
8392 :
8393 33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8394 :
8395 : {
8396 33 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8397 :
8398 33 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8399 33 : return poBand->CreateMaskBand(nFlags);
8400 : }
8401 :
8402 : /************************************************************************/
8403 : /* IsMaskBand() */
8404 : /************************************************************************/
8405 :
8406 : /**
8407 : * \brief Returns whether a band is a mask band.
8408 : *
8409 : * Mask band must be understood in the broad term: it can be a per-dataset
8410 : * mask band, an alpha band, or an implicit mask band.
8411 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8412 : *
8413 : * This method is the same as the C function GDALIsMaskBand().
8414 : *
8415 : * @return true if the band is a mask band.
8416 : *
8417 : * @see GDALDataset::CreateMaskBand()
8418 : *
8419 : * @since GDAL 3.5.0
8420 : *
8421 : */
8422 :
8423 403 : bool GDALRasterBand::IsMaskBand() const
8424 : {
8425 : // The GeoTIFF driver, among others, override this method to
8426 : // also handle external .msk bands.
8427 403 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8428 403 : GCI_AlphaBand;
8429 : }
8430 :
8431 : /************************************************************************/
8432 : /* GDALIsMaskBand() */
8433 : /************************************************************************/
8434 :
8435 : /**
8436 : * \brief Returns whether a band is a mask band.
8437 : *
8438 : * Mask band must be understood in the broad term: it can be a per-dataset
8439 : * mask band, an alpha band, or an implicit mask band.
8440 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8441 : *
8442 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8443 : *
8444 : * @return true if the band is a mask band.
8445 : *
8446 : * @see GDALRasterBand::IsMaskBand()
8447 : *
8448 : * @since GDAL 3.5.0
8449 : *
8450 : */
8451 :
8452 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
8453 :
8454 : {
8455 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8456 :
8457 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8458 37 : return poBand->IsMaskBand();
8459 : }
8460 :
8461 : /************************************************************************/
8462 : /* GetMaskValueRange() */
8463 : /************************************************************************/
8464 :
8465 : /**
8466 : * \brief Returns the range of values that a mask band can take.
8467 : *
8468 : * @return the range of values that a mask band can take.
8469 : *
8470 : * @since GDAL 3.5.0
8471 : *
8472 : */
8473 :
8474 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8475 : {
8476 0 : return GMVR_UNKNOWN;
8477 : }
8478 :
8479 : /************************************************************************/
8480 : /* GetIndexColorTranslationTo() */
8481 : /************************************************************************/
8482 :
8483 : /**
8484 : * \brief Compute translation table for color tables.
8485 : *
8486 : * When the raster band has a palette index, it may be useful to compute
8487 : * the "translation" of this palette to the palette of another band.
8488 : * The translation tries to do exact matching first, and then approximate
8489 : * matching if no exact matching is possible.
8490 : * This method returns a table such that table[i] = j where i is an index
8491 : * of the 'this' rasterband and j the corresponding index for the reference
8492 : * rasterband.
8493 : *
8494 : * This method is thought as internal to GDAL and is used for drivers
8495 : * like RPFTOC.
8496 : *
8497 : * The implementation only supports 1-byte palette rasterbands.
8498 : *
8499 : * @param poReferenceBand the raster band
8500 : * @param pTranslationTable an already allocated translation table (at least 256
8501 : * bytes), or NULL to let the method allocate it
8502 : * @param pApproximateMatching a pointer to a flag that is set if the matching
8503 : * is approximate. May be NULL.
8504 : *
8505 : * @return a translation table if the two bands are palette index and that they
8506 : * do not match or NULL in other cases. The table must be freed with CPLFree if
8507 : * NULL was passed for pTranslationTable.
8508 : */
8509 :
8510 : unsigned char *
8511 5 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8512 : unsigned char *pTranslationTable,
8513 : int *pApproximateMatching)
8514 : {
8515 5 : if (poReferenceBand == nullptr)
8516 0 : return nullptr;
8517 :
8518 : // cppcheck-suppress knownConditionTrueFalse
8519 5 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8520 : // cppcheck-suppress knownConditionTrueFalse
8521 5 : GetColorInterpretation() == GCI_PaletteIndex &&
8522 15 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
8523 5 : GetRasterDataType() == GDT_Byte)
8524 : {
8525 5 : const GDALColorTable *srcColorTable = GetColorTable();
8526 5 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8527 5 : if (srcColorTable != nullptr && destColorTable != nullptr)
8528 : {
8529 5 : const int nEntries = srcColorTable->GetColorEntryCount();
8530 5 : const int nRefEntries = destColorTable->GetColorEntryCount();
8531 :
8532 5 : int bHasNoDataValueSrc = FALSE;
8533 5 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8534 5 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8535 4 : dfNoDataValueSrc <= 255 &&
8536 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8537 1 : bHasNoDataValueSrc = FALSE;
8538 5 : const int noDataValueSrc =
8539 5 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8540 :
8541 5 : int bHasNoDataValueRef = FALSE;
8542 : const double dfNoDataValueRef =
8543 5 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8544 5 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8545 3 : dfNoDataValueRef <= 255 &&
8546 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8547 2 : bHasNoDataValueRef = FALSE;
8548 5 : const int noDataValueRef =
8549 5 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8550 :
8551 5 : bool samePalette = false;
8552 :
8553 5 : if (pApproximateMatching)
8554 3 : *pApproximateMatching = FALSE;
8555 :
8556 5 : if (nEntries == nRefEntries &&
8557 4 : bHasNoDataValueSrc == bHasNoDataValueRef &&
8558 4 : (bHasNoDataValueSrc == FALSE ||
8559 : noDataValueSrc == noDataValueRef))
8560 : {
8561 4 : samePalette = true;
8562 911 : for (int i = 0; i < nEntries; ++i)
8563 : {
8564 907 : if (noDataValueSrc == i)
8565 4 : continue;
8566 : const GDALColorEntry *entry =
8567 903 : srcColorTable->GetColorEntry(i);
8568 : const GDALColorEntry *entryRef =
8569 903 : destColorTable->GetColorEntry(i);
8570 903 : if (entry->c1 != entryRef->c1 ||
8571 903 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8572 : {
8573 0 : samePalette = false;
8574 : }
8575 : }
8576 : }
8577 :
8578 5 : if (!samePalette)
8579 : {
8580 1 : if (pTranslationTable == nullptr)
8581 : {
8582 : pTranslationTable = static_cast<unsigned char *>(
8583 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8584 1 : if (pTranslationTable == nullptr)
8585 1 : return nullptr;
8586 : }
8587 :
8588 : // Trying to remap the product palette on the subdataset
8589 : // palette.
8590 5 : for (int i = 0; i < nEntries; ++i)
8591 : {
8592 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8593 : noDataValueSrc == i)
8594 0 : continue;
8595 : const GDALColorEntry *entry =
8596 4 : srcColorTable->GetColorEntry(i);
8597 4 : bool bMatchFound = false;
8598 13 : for (int j = 0; j < nRefEntries; ++j)
8599 : {
8600 10 : if (bHasNoDataValueRef && noDataValueRef == j)
8601 0 : continue;
8602 : const GDALColorEntry *entryRef =
8603 10 : destColorTable->GetColorEntry(j);
8604 10 : if (entry->c1 == entryRef->c1 &&
8605 2 : entry->c2 == entryRef->c2 &&
8606 2 : entry->c3 == entryRef->c3)
8607 : {
8608 1 : pTranslationTable[i] =
8609 : static_cast<unsigned char>(j);
8610 1 : bMatchFound = true;
8611 1 : break;
8612 : }
8613 : }
8614 4 : if (!bMatchFound)
8615 : {
8616 : // No exact match. Looking for closest color now.
8617 3 : int best_j = 0;
8618 3 : int best_distance = 0;
8619 3 : if (pApproximateMatching)
8620 0 : *pApproximateMatching = TRUE;
8621 12 : for (int j = 0; j < nRefEntries; ++j)
8622 : {
8623 : const GDALColorEntry *entryRef =
8624 9 : destColorTable->GetColorEntry(j);
8625 9 : int distance = (entry->c1 - entryRef->c1) *
8626 9 : (entry->c1 - entryRef->c1) +
8627 9 : (entry->c2 - entryRef->c2) *
8628 9 : (entry->c2 - entryRef->c2) +
8629 9 : (entry->c3 - entryRef->c3) *
8630 9 : (entry->c3 - entryRef->c3);
8631 9 : if (j == 0 || distance < best_distance)
8632 : {
8633 7 : best_j = j;
8634 7 : best_distance = distance;
8635 : }
8636 : }
8637 3 : pTranslationTable[i] =
8638 : static_cast<unsigned char>(best_j);
8639 : }
8640 : }
8641 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
8642 0 : pTranslationTable[noDataValueSrc] =
8643 : static_cast<unsigned char>(noDataValueRef);
8644 :
8645 1 : return pTranslationTable;
8646 : }
8647 : }
8648 : }
8649 4 : return nullptr;
8650 : }
8651 :
8652 : /************************************************************************/
8653 : /* SetFlushBlockErr() */
8654 : /************************************************************************/
8655 :
8656 : /**
8657 : * \brief Store that an error occurred while writing a dirty block.
8658 : *
8659 : * This function stores the fact that an error occurred while writing a dirty
8660 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8661 : * flushed when the block cache get full, it is not convenient/possible to
8662 : * report that a dirty block could not be written correctly. This function
8663 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8664 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8665 : * places where the user can easily match the error with the relevant dataset.
8666 : */
8667 :
8668 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8669 : {
8670 0 : eFlushBlockErr = eErr;
8671 0 : }
8672 :
8673 : /************************************************************************/
8674 : /* IncDirtyBlocks() */
8675 : /************************************************************************/
8676 :
8677 : /**
8678 : * \brief Increment/decrement the number of dirty blocks
8679 : */
8680 :
8681 515147 : void GDALRasterBand::IncDirtyBlocks(int nInc)
8682 : {
8683 515147 : if (poBandBlockCache)
8684 515147 : poBandBlockCache->IncDirtyBlocks(nInc);
8685 515144 : }
8686 :
8687 : /************************************************************************/
8688 : /* ReportError() */
8689 : /************************************************************************/
8690 :
8691 : #ifndef DOXYGEN_XML
8692 : /**
8693 : * \brief Emits an error related to a raster band.
8694 : *
8695 : * This function is a wrapper for regular CPLError(). The only difference
8696 : * with CPLError() is that it prepends the error message with the dataset
8697 : * name and the band number.
8698 : *
8699 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
8700 : * @param err_no the error number (CPLE_*) from cpl_error.h.
8701 : * @param fmt a printf() style format string. Any additional arguments
8702 : * will be treated as arguments to fill in this format in a manner
8703 : * similar to printf().
8704 : *
8705 : * @since GDAL 1.9.0
8706 : */
8707 :
8708 2448 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
8709 : const char *fmt, ...) const
8710 : {
8711 : va_list args;
8712 :
8713 2448 : va_start(args, fmt);
8714 :
8715 2448 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
8716 2448 : pszDSName = CPLGetFilename(pszDSName);
8717 2448 : if (pszDSName[0] != '\0')
8718 : {
8719 2392 : CPLError(eErrClass, err_no, "%s",
8720 4784 : CPLString()
8721 2392 : .Printf("%s, band %d: ", pszDSName, GetBand())
8722 4784 : .append(CPLString().vPrintf(fmt, args))
8723 : .c_str());
8724 : }
8725 : else
8726 : {
8727 56 : CPLErrorV(eErrClass, err_no, fmt, args);
8728 : }
8729 :
8730 2448 : va_end(args);
8731 2448 : }
8732 : #endif
8733 :
8734 : /************************************************************************/
8735 : /* GetVirtualMemAuto() */
8736 : /************************************************************************/
8737 :
8738 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
8739 : *
8740 : * Only supported on Linux and Unix systems with mmap() for now.
8741 : *
8742 : * This method allows creating a virtual memory object for a GDALRasterBand,
8743 : * that exposes the whole image data as a virtual array.
8744 : *
8745 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
8746 : * specialized implementation, such as for raw files, may also directly use
8747 : * mechanisms of the operating system to create a view of the underlying file
8748 : * into virtual memory ( CPLVirtualMemFileMapNew() )
8749 : *
8750 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
8751 : * offer a specialized implementation with direct file mapping, provided that
8752 : * some requirements are met :
8753 : * - for all drivers, the dataset must be backed by a "real" file in the file
8754 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
8755 : * must match the native ordering of the CPU.
8756 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
8757 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
8758 : * the file in sequential order, and be equally spaced (which is generally the
8759 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
8760 : * GDT_Int16/GDT_UInt16, 32 for GDT_Float32 and 64 for GDT_Float64)
8761 : *
8762 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
8763 : * CPLVirtualMemFree() must be called before the raster band object is
8764 : * destroyed.
8765 : *
8766 : * If p is such a pointer and base_type the type matching
8767 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
8768 : * accessed with
8769 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
8770 : *
8771 : * This method is the same as the C GDALGetVirtualMemAuto() function.
8772 : *
8773 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
8774 : * read/write the band.
8775 : *
8776 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
8777 : * one pixel value in the buffer to the start of the next pixel value within a
8778 : * scanline.
8779 : *
8780 : * @param pnLineSpace Output parameter giving the byte offset from the start of
8781 : * one scanline in the buffer to the start of the next.
8782 : *
8783 : * @param papszOptions NULL terminated list of options.
8784 : * If a specialized implementation exists, defining
8785 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
8786 : * used. On the contrary, starting with GDAL 2.2, defining
8787 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
8788 : * being used (thus only allowing efficient implementations to be used). When
8789 : * requiring or falling back to the default implementation, the following
8790 : * options are available : CACHE_SIZE (in bytes, defaults to
8791 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
8792 : * to FALSE)
8793 : *
8794 : * @return a virtual memory object that must be unreferenced by
8795 : * CPLVirtualMemFree(), or NULL in case of failure.
8796 : *
8797 : * @since GDAL 1.11
8798 : */
8799 :
8800 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
8801 : int *pnPixelSpace,
8802 : GIntBig *pnLineSpace,
8803 : char **papszOptions)
8804 : {
8805 9 : const char *pszImpl = CSLFetchNameValueDef(
8806 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
8807 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
8808 8 : EQUAL(pszImpl, "FALSE"))
8809 : {
8810 1 : return nullptr;
8811 : }
8812 :
8813 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
8814 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
8815 8 : if (pnPixelSpace)
8816 8 : *pnPixelSpace = nPixelSpace;
8817 8 : if (pnLineSpace)
8818 8 : *pnLineSpace = nLineSpace;
8819 : const size_t nCacheSize =
8820 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
8821 : const size_t nPageSizeHint =
8822 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
8823 8 : const bool bSingleThreadUsage = CPLTestBool(
8824 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
8825 8 : return GDALRasterBandGetVirtualMem(
8826 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
8827 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
8828 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
8829 8 : papszOptions);
8830 : }
8831 :
8832 : /************************************************************************/
8833 : /* GDALGetVirtualMemAuto() */
8834 : /************************************************************************/
8835 :
8836 : /**
8837 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
8838 : *
8839 : * @see GDALRasterBand::GetVirtualMemAuto()
8840 : */
8841 :
8842 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
8843 : int *pnPixelSpace, GIntBig *pnLineSpace,
8844 : CSLConstList papszOptions)
8845 : {
8846 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
8847 :
8848 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8849 :
8850 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
8851 31 : const_cast<char **>(papszOptions));
8852 : }
8853 :
8854 : /************************************************************************/
8855 : /* GDALGetDataCoverageStatus() */
8856 : /************************************************************************/
8857 :
8858 : /**
8859 : * \brief Get the coverage status of a sub-window of the raster.
8860 : *
8861 : * Returns whether a sub-window of the raster contains only data, only empty
8862 : * blocks or a mix of both. This function can be used to determine quickly
8863 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
8864 : * be sparse.
8865 : *
8866 : * Empty blocks are blocks that are generally not physically present in the
8867 : * file, and when read through GDAL, contain only pixels whose value is the
8868 : * nodata value when it is set, or whose value is 0 when the nodata value is
8869 : * not set.
8870 : *
8871 : * The query is done in an efficient way without reading the actual pixel
8872 : * values. If not possible, or not implemented at all by the driver,
8873 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
8874 : * be returned.
8875 : *
8876 : * The values that can be returned by the function are the following,
8877 : * potentially combined with the binary or operator :
8878 : * <ul>
8879 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
8880 : * GetDataCoverageStatus(). This flag should be returned together with
8881 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
8882 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
8883 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
8884 : * the queried window. This is typically identified by the concept of missing
8885 : * block in formats that supports it.
8886 : * </li>
8887 : * </ul>
8888 : *
8889 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
8890 : * should be interpreted more as hint of potential presence of data. For example
8891 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
8892 : * nodata value), instead of using the missing block mechanism,
8893 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
8894 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
8895 : *
8896 : * The nMaskFlagStop should be generally set to 0. It can be set to a
8897 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
8898 : * the function as soon as the computed mask matches the nMaskFlagStop. For
8899 : * example, you can issue a request on the whole raster with nMaskFlagStop =
8900 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
8901 : * the function will exit, so that you can potentially refine the requested area
8902 : * to find which particular region(s) have missing blocks.
8903 : *
8904 : * @see GDALRasterBand::GetDataCoverageStatus()
8905 : *
8906 : * @param hBand raster band
8907 : *
8908 : * @param nXOff The pixel offset to the top left corner of the region
8909 : * of the band to be queried. This would be zero to start from the left side.
8910 : *
8911 : * @param nYOff The line offset to the top left corner of the region
8912 : * of the band to be queried. This would be zero to start from the top.
8913 : *
8914 : * @param nXSize The width of the region of the band to be queried in pixels.
8915 : *
8916 : * @param nYSize The height of the region of the band to be queried in lines.
8917 : *
8918 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
8919 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8920 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
8921 : * as the computation of the coverage matches the mask, the computation will be
8922 : * stopped. *pdfDataPct will not be valid in that case.
8923 : *
8924 : * @param pdfDataPct Optional output parameter whose pointed value will be set
8925 : * to the (approximate) percentage in [0,100] of pixels in the queried
8926 : * sub-window that have valid values. The implementation might not always be
8927 : * able to compute it, in which case it will be set to a negative value.
8928 : *
8929 : * @return a binary-or'ed combination of possible values
8930 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8931 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
8932 : *
8933 : * @note Added in GDAL 2.2
8934 : */
8935 :
8936 26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
8937 : int nYOff, int nXSize, int nYSize,
8938 : int nMaskFlagStop, double *pdfDataPct)
8939 : {
8940 26 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
8941 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
8942 :
8943 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8944 :
8945 26 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
8946 26 : nMaskFlagStop, pdfDataPct);
8947 : }
8948 :
8949 : /************************************************************************/
8950 : /* GetDataCoverageStatus() */
8951 : /************************************************************************/
8952 :
8953 : /**
8954 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
8955 : * int nYOff,
8956 : * int nXSize,
8957 : * int nYSize,
8958 : * int nMaskFlagStop,
8959 : * double* pdfDataPct)
8960 : * \brief Get the coverage status of a sub-window of the raster.
8961 : *
8962 : * Returns whether a sub-window of the raster contains only data, only empty
8963 : * blocks or a mix of both. This function can be used to determine quickly
8964 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
8965 : * be sparse.
8966 : *
8967 : * Empty blocks are blocks that contain only pixels whose value is the nodata
8968 : * value when it is set, or whose value is 0 when the nodata value is not set.
8969 : *
8970 : * The query is done in an efficient way without reading the actual pixel
8971 : * values. If not possible, or not implemented at all by the driver,
8972 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
8973 : * be returned.
8974 : *
8975 : * The values that can be returned by the function are the following,
8976 : * potentially combined with the binary or operator :
8977 : * <ul>
8978 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
8979 : * GetDataCoverageStatus(). This flag should be returned together with
8980 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
8981 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
8982 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
8983 : * the queried window. This is typically identified by the concept of missing
8984 : * block in formats that supports it.
8985 : * </li>
8986 : * </ul>
8987 : *
8988 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
8989 : * should be interpreted more as hint of potential presence of data. For example
8990 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
8991 : * nodata value), instead of using the missing block mechanism,
8992 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
8993 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
8994 : *
8995 : * The nMaskFlagStop should be generally set to 0. It can be set to a
8996 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
8997 : * the function as soon as the computed mask matches the nMaskFlagStop. For
8998 : * example, you can issue a request on the whole raster with nMaskFlagStop =
8999 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9000 : * the function will exit, so that you can potentially refine the requested area
9001 : * to find which particular region(s) have missing blocks.
9002 : *
9003 : * @see GDALGetDataCoverageStatus()
9004 : *
9005 : * @param nXOff The pixel offset to the top left corner of the region
9006 : * of the band to be queried. This would be zero to start from the left side.
9007 : *
9008 : * @param nYOff The line offset to the top left corner of the region
9009 : * of the band to be queried. This would be zero to start from the top.
9010 : *
9011 : * @param nXSize The width of the region of the band to be queried in pixels.
9012 : *
9013 : * @param nYSize The height of the region of the band to be queried in lines.
9014 : *
9015 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9016 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9017 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9018 : * as the computation of the coverage matches the mask, the computation will be
9019 : * stopped. *pdfDataPct will not be valid in that case.
9020 : *
9021 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9022 : * to the (approximate) percentage in [0,100] of pixels in the queried
9023 : * sub-window that have valid values. The implementation might not always be
9024 : * able to compute it, in which case it will be set to a negative value.
9025 : *
9026 : * @return a binary-or'ed combination of possible values
9027 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9028 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9029 : *
9030 : * @note Added in GDAL 2.2
9031 : */
9032 :
9033 : /**
9034 : * \brief Get the coverage status of a sub-window of the raster.
9035 : *
9036 : * Returns whether a sub-window of the raster contains only data, only empty
9037 : * blocks or a mix of both. This function can be used to determine quickly
9038 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9039 : * be sparse.
9040 : *
9041 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9042 : * value when it is set, or whose value is 0 when the nodata value is not set.
9043 : *
9044 : * The query is done in an efficient way without reading the actual pixel
9045 : * values. If not possible, or not implemented at all by the driver,
9046 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9047 : * be returned.
9048 : *
9049 : * The values that can be returned by the function are the following,
9050 : * potentially combined with the binary or operator :
9051 : * <ul>
9052 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9053 : * GetDataCoverageStatus(). This flag should be returned together with
9054 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9055 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9056 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9057 : * the queried window. This is typically identified by the concept of missing
9058 : * block in formats that supports it.
9059 : * </li>
9060 : * </ul>
9061 : *
9062 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9063 : * should be interpreted more as hint of potential presence of data. For example
9064 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9065 : * nodata value), instead of using the missing block mechanism,
9066 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9067 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9068 : *
9069 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9070 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9071 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9072 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9073 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9074 : * the function will exit, so that you can potentially refine the requested area
9075 : * to find which particular region(s) have missing blocks.
9076 : *
9077 : * @see GDALGetDataCoverageStatus()
9078 : *
9079 : * @param nXOff The pixel offset to the top left corner of the region
9080 : * of the band to be queried. This would be zero to start from the left side.
9081 : *
9082 : * @param nYOff The line offset to the top left corner of the region
9083 : * of the band to be queried. This would be zero to start from the top.
9084 : *
9085 : * @param nXSize The width of the region of the band to be queried in pixels.
9086 : *
9087 : * @param nYSize The height of the region of the band to be queried in lines.
9088 : *
9089 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9090 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9091 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9092 : * as the computation of the coverage matches the mask, the computation will be
9093 : * stopped. *pdfDataPct will not be valid in that case.
9094 : *
9095 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9096 : * to the (approximate) percentage in [0,100] of pixels in the queried
9097 : * sub-window that have valid values. The implementation might not always be
9098 : * able to compute it, in which case it will be set to a negative value.
9099 : *
9100 : * @return a binary-or'ed combination of possible values
9101 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9102 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9103 : *
9104 : * @note Added in GDAL 2.2
9105 : */
9106 :
9107 2702 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9108 : int nYSize, int nMaskFlagStop,
9109 : double *pdfDataPct)
9110 : {
9111 2702 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9112 2702 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9113 2702 : nYOff + nYSize > nRasterYSize)
9114 : {
9115 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9116 0 : if (pdfDataPct)
9117 0 : *pdfDataPct = 0.0;
9118 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9119 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
9120 : }
9121 2702 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9122 2702 : pdfDataPct);
9123 : }
9124 :
9125 : /************************************************************************/
9126 : /* IGetDataCoverageStatus() */
9127 : /************************************************************************/
9128 :
9129 501 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9130 : int /*nXSize*/, int /*nYSize*/,
9131 : int /*nMaskFlagStop*/,
9132 : double *pdfDataPct)
9133 : {
9134 501 : if (pdfDataPct != nullptr)
9135 0 : *pdfDataPct = 100.0;
9136 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9137 501 : GDAL_DATA_COVERAGE_STATUS_DATA;
9138 : }
9139 :
9140 : //! @cond Doxygen_Suppress
9141 : /************************************************************************/
9142 : /* EnterReadWrite() */
9143 : /************************************************************************/
9144 :
9145 6896980 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9146 : {
9147 6896980 : if (poDS != nullptr)
9148 6146130 : return poDS->EnterReadWrite(eRWFlag);
9149 750849 : return FALSE;
9150 : }
9151 :
9152 : /************************************************************************/
9153 : /* LeaveReadWrite() */
9154 : /************************************************************************/
9155 :
9156 638461 : void GDALRasterBand::LeaveReadWrite()
9157 : {
9158 638461 : if (poDS != nullptr)
9159 638462 : poDS->LeaveReadWrite();
9160 638454 : }
9161 :
9162 : /************************************************************************/
9163 : /* InitRWLock() */
9164 : /************************************************************************/
9165 :
9166 3644950 : void GDALRasterBand::InitRWLock()
9167 : {
9168 3644950 : if (poDS != nullptr)
9169 3644550 : poDS->InitRWLock();
9170 3644950 : }
9171 :
9172 : //! @endcond
9173 :
9174 : // clang-format off
9175 :
9176 : /**
9177 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9178 : * \brief Set metadata.
9179 : *
9180 : * CAUTION: depending on the format, older values of the updated information
9181 : * might still be found in the file in a "ghost" state, even if no longer
9182 : * accessible through the GDAL API. This is for example the case of the GTiff
9183 : * format (this is not a exhaustive list)
9184 : *
9185 : * The C function GDALSetMetadata() does the same thing as this method.
9186 : *
9187 : * @param papszMetadata the metadata in name=value string list format to
9188 : * apply.
9189 : * @param pszDomain the domain of interest. Use "" or NULL for the default
9190 : * domain.
9191 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9192 : * metadata has been accepted, but is likely not maintained persistently
9193 : * by the underlying object between sessions.
9194 : */
9195 :
9196 : /**
9197 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9198 : * \brief Set single metadata item.
9199 : *
9200 : * CAUTION: depending on the format, older values of the updated information
9201 : * might still be found in the file in a "ghost" state, even if no longer
9202 : * accessible through the GDAL API. This is for example the case of the GTiff
9203 : * format (this is not a exhaustive list)
9204 : *
9205 : * The C function GDALSetMetadataItem() does the same thing as this method.
9206 : *
9207 : * @param pszName the key for the metadata item to fetch.
9208 : * @param pszValue the value to assign to the key.
9209 : * @param pszDomain the domain to set within, use NULL for the default domain.
9210 : *
9211 : * @return CE_None on success, or an error code on failure.
9212 : */
9213 :
9214 : // clang-format on
9215 :
9216 : //! @cond Doxygen_Suppress
9217 : /************************************************************************/
9218 : /* EnablePixelTypeSignedByteWarning() */
9219 : /************************************************************************/
9220 :
9221 27835 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9222 : {
9223 27835 : m_bEnablePixelTypeSignedByteWarning = b;
9224 27835 : }
9225 :
9226 8360 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9227 : {
9228 8360 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9229 8360 : }
9230 :
9231 : //! @endcond
9232 :
9233 : /************************************************************************/
9234 : /* GetMetadataItem() */
9235 : /************************************************************************/
9236 :
9237 61365 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9238 : const char *pszDomain)
9239 : {
9240 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9241 61365 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9242 36873 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9243 27980 : EQUAL(pszName, "PIXELTYPE"))
9244 : {
9245 2 : CPLError(CE_Warning, CPLE_AppDefined,
9246 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9247 : "used to signal signed 8-bit raster. Change your code to "
9248 : "test for the new GDT_Int8 data type instead.");
9249 : }
9250 61365 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9251 : }
9252 :
9253 : /************************************************************************/
9254 : /* GDALMDArrayFromRasterBand */
9255 : /************************************************************************/
9256 :
9257 : class GDALMDArrayFromRasterBand final : public GDALMDArray
9258 : {
9259 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9260 :
9261 : GDALDataset *m_poDS;
9262 : GDALRasterBand *m_poBand;
9263 : GDALExtendedDataType m_dt;
9264 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9265 : std::string m_osUnit;
9266 : std::vector<GByte> m_pabyNoData{};
9267 : std::shared_ptr<GDALMDArray> m_varX{};
9268 : std::shared_ptr<GDALMDArray> m_varY{};
9269 : std::string m_osFilename{};
9270 :
9271 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9272 : const size_t *count, const GInt64 *arrayStep,
9273 : const GPtrDiff_t *bufferStride,
9274 : const GDALExtendedDataType &bufferDataType,
9275 : void *pBuffer) const;
9276 :
9277 : protected:
9278 23 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9279 46 : : GDALAbstractMDArray(std::string(),
9280 46 : std::string(poDS->GetDescription()) +
9281 : CPLSPrintf(" band %d", poBand->GetBand())),
9282 46 : GDALMDArray(std::string(),
9283 46 : std::string(poDS->GetDescription()) +
9284 : CPLSPrintf(" band %d", poBand->GetBand())),
9285 : m_poDS(poDS), m_poBand(poBand),
9286 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9287 115 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9288 : {
9289 23 : m_poDS->Reference();
9290 :
9291 23 : int bHasNoData = false;
9292 23 : if (m_poBand->GetRasterDataType() == GDT_Int64)
9293 : {
9294 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9295 0 : if (bHasNoData)
9296 : {
9297 0 : m_pabyNoData.resize(m_dt.GetSize());
9298 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9299 : m_dt.GetNumericDataType(), 0, 1);
9300 : }
9301 : }
9302 23 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9303 : {
9304 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9305 0 : if (bHasNoData)
9306 : {
9307 0 : m_pabyNoData.resize(m_dt.GetSize());
9308 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9309 : m_dt.GetNumericDataType(), 0, 1);
9310 : }
9311 : }
9312 : else
9313 : {
9314 23 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9315 23 : if (bHasNoData)
9316 : {
9317 1 : m_pabyNoData.resize(m_dt.GetSize());
9318 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9319 : m_dt.GetNumericDataType(), 0, 1);
9320 : }
9321 : }
9322 :
9323 23 : const int nXSize = poBand->GetXSize();
9324 23 : const int nYSize = poBand->GetYSize();
9325 :
9326 23 : auto poSRS = m_poDS->GetSpatialRef();
9327 46 : std::string osTypeY;
9328 46 : std::string osTypeX;
9329 46 : std::string osDirectionY;
9330 46 : std::string osDirectionX;
9331 23 : if (poSRS && poSRS->GetAxesCount() == 2)
9332 : {
9333 21 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9334 21 : OGRAxisOrientation eOrientation1 = OAO_Other;
9335 21 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
9336 21 : OGRAxisOrientation eOrientation2 = OAO_Other;
9337 21 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
9338 21 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9339 : {
9340 5 : if (mapping == std::vector<int>{1, 2})
9341 : {
9342 5 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9343 5 : osDirectionY = "NORTH";
9344 5 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9345 5 : osDirectionX = "EAST";
9346 : }
9347 : }
9348 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9349 : {
9350 16 : if (mapping == std::vector<int>{2, 1})
9351 : {
9352 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9353 16 : osDirectionY = "NORTH";
9354 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9355 16 : osDirectionX = "EAST";
9356 : }
9357 : }
9358 : }
9359 :
9360 115 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9361 : "/", "Y", osTypeY, osDirectionY, nYSize),
9362 46 : std::make_shared<GDALDimensionWeakIndexingVar>(
9363 69 : "/", "X", osTypeX, osDirectionX, nXSize)};
9364 :
9365 : double adfGeoTransform[6];
9366 23 : if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
9367 23 : adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
9368 : {
9369 44 : m_varX = GDALMDArrayRegularlySpaced::Create(
9370 22 : "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
9371 22 : 0.5);
9372 22 : m_dims[1]->SetIndexingVariable(m_varX);
9373 :
9374 44 : m_varY = GDALMDArrayRegularlySpaced::Create(
9375 22 : "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
9376 22 : 0.5);
9377 22 : m_dims[0]->SetIndexingVariable(m_varY);
9378 : }
9379 23 : }
9380 :
9381 31 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9382 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9383 : const GDALExtendedDataType &bufferDataType,
9384 : void *pDstBuffer) const override
9385 : {
9386 31 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9387 31 : bufferDataType, pDstBuffer);
9388 : }
9389 :
9390 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9391 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9392 : const GDALExtendedDataType &bufferDataType,
9393 : const void *pSrcBuffer) override
9394 : {
9395 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9396 : bufferStride, bufferDataType,
9397 1 : const_cast<void *>(pSrcBuffer));
9398 : }
9399 :
9400 : public:
9401 46 : ~GDALMDArrayFromRasterBand()
9402 23 : {
9403 23 : m_poDS->ReleaseRef();
9404 46 : }
9405 :
9406 23 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9407 : GDALRasterBand *poBand)
9408 : {
9409 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9410 46 : new GDALMDArrayFromRasterBand(poDS, poBand)));
9411 23 : array->SetSelf(array);
9412 46 : return array;
9413 : }
9414 :
9415 2 : bool IsWritable() const override
9416 : {
9417 2 : return m_poDS->GetAccess() == GA_Update;
9418 : }
9419 :
9420 97 : const std::string &GetFilename() const override
9421 : {
9422 97 : return m_osFilename;
9423 : }
9424 :
9425 : const std::vector<std::shared_ptr<GDALDimension>> &
9426 299 : GetDimensions() const override
9427 : {
9428 299 : return m_dims;
9429 : }
9430 :
9431 138 : const GDALExtendedDataType &GetDataType() const override
9432 : {
9433 138 : return m_dt;
9434 : }
9435 :
9436 3 : const std::string &GetUnit() const override
9437 : {
9438 3 : return m_osUnit;
9439 : }
9440 :
9441 29 : const void *GetRawNoDataValue() const override
9442 : {
9443 29 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9444 : }
9445 :
9446 2 : double GetOffset(bool *pbHasOffset,
9447 : GDALDataType *peStorageType) const override
9448 : {
9449 2 : int bHasOffset = false;
9450 2 : double dfRes = m_poBand->GetOffset(&bHasOffset);
9451 2 : if (pbHasOffset)
9452 2 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9453 2 : if (peStorageType)
9454 1 : *peStorageType = GDT_Unknown;
9455 2 : return dfRes;
9456 : }
9457 :
9458 2 : double GetScale(bool *pbHasScale,
9459 : GDALDataType *peStorageType) const override
9460 : {
9461 2 : int bHasScale = false;
9462 2 : double dfRes = m_poBand->GetScale(&bHasScale);
9463 2 : if (pbHasScale)
9464 2 : *pbHasScale = CPL_TO_BOOL(bHasScale);
9465 2 : if (peStorageType)
9466 1 : *peStorageType = GDT_Unknown;
9467 2 : return dfRes;
9468 : }
9469 :
9470 84 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9471 : {
9472 84 : auto poSrcSRS = m_poDS->GetSpatialRef();
9473 84 : if (!poSrcSRS)
9474 2 : return nullptr;
9475 164 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9476 :
9477 164 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9478 82 : constexpr int iYDim = 0;
9479 82 : constexpr int iXDim = 1;
9480 246 : for (auto &m : axisMapping)
9481 : {
9482 164 : if (m == 1)
9483 82 : m = iXDim + 1;
9484 82 : else if (m == 2)
9485 82 : m = iYDim + 1;
9486 : else
9487 0 : m = 0;
9488 : }
9489 82 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9490 82 : return poSRS;
9491 : }
9492 :
9493 29 : std::vector<GUInt64> GetBlockSize() const override
9494 : {
9495 29 : int nBlockXSize = 0;
9496 29 : int nBlockYSize = 0;
9497 29 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9498 29 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9499 29 : static_cast<GUInt64>(nBlockXSize)};
9500 : }
9501 :
9502 : class MDIAsAttribute : public GDALAttribute
9503 : {
9504 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9505 : const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
9506 : std::string m_osValue;
9507 :
9508 : public:
9509 2 : MDIAsAttribute(const std::string &name, const std::string &value)
9510 2 : : GDALAbstractMDArray(std::string(), name),
9511 4 : GDALAttribute(std::string(), name), m_osValue(value)
9512 : {
9513 2 : }
9514 :
9515 : const std::vector<std::shared_ptr<GDALDimension>> &
9516 3 : GetDimensions() const override
9517 : {
9518 3 : return m_dims;
9519 : }
9520 :
9521 2 : const GDALExtendedDataType &GetDataType() const override
9522 : {
9523 2 : return m_dt;
9524 : }
9525 :
9526 1 : bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
9527 : const GPtrDiff_t *,
9528 : const GDALExtendedDataType &bufferDataType,
9529 : void *pDstBuffer) const override
9530 : {
9531 1 : const char *pszStr = m_osValue.c_str();
9532 1 : GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
9533 : bufferDataType);
9534 1 : return true;
9535 : }
9536 : };
9537 :
9538 : std::vector<std::shared_ptr<GDALAttribute>>
9539 14 : GetAttributes(CSLConstList) const override
9540 : {
9541 14 : std::vector<std::shared_ptr<GDALAttribute>> res;
9542 14 : auto papszMD = m_poBand->GetMetadata();
9543 16 : for (auto iter = papszMD; iter && iter[0]; ++iter)
9544 : {
9545 2 : char *pszKey = nullptr;
9546 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9547 2 : if (pszKey && pszValue)
9548 : {
9549 : res.emplace_back(
9550 2 : std::make_shared<MDIAsAttribute>(pszKey, pszValue));
9551 : }
9552 2 : CPLFree(pszKey);
9553 : }
9554 14 : return res;
9555 : }
9556 : };
9557 :
9558 : /************************************************************************/
9559 : /* ReadWrite() */
9560 : /************************************************************************/
9561 :
9562 32 : bool GDALMDArrayFromRasterBand::ReadWrite(
9563 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
9564 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9565 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
9566 : {
9567 32 : constexpr size_t iDimX = 1;
9568 32 : constexpr size_t iDimY = 0;
9569 32 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
9570 : arrayStartIdx, count, arrayStep, bufferStride,
9571 32 : bufferDataType, pBuffer);
9572 : }
9573 :
9574 : /************************************************************************/
9575 : /* GDALMDRasterIOFromBand() */
9576 : /************************************************************************/
9577 :
9578 65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
9579 : size_t iDimX, size_t iDimY,
9580 : const GUInt64 *arrayStartIdx, const size_t *count,
9581 : const GInt64 *arrayStep,
9582 : const GPtrDiff_t *bufferStride,
9583 : const GDALExtendedDataType &bufferDataType,
9584 : void *pBuffer)
9585 : {
9586 65 : const auto eDT(bufferDataType.GetNumericDataType());
9587 65 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
9588 65 : const int nX =
9589 65 : arrayStep[iDimX] > 0
9590 65 : ? static_cast<int>(arrayStartIdx[iDimX])
9591 2 : : static_cast<int>(arrayStartIdx[iDimX] -
9592 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
9593 65 : const int nY =
9594 65 : arrayStep[iDimY] > 0
9595 65 : ? static_cast<int>(arrayStartIdx[iDimY])
9596 2 : : static_cast<int>(arrayStartIdx[iDimY] -
9597 2 : (count[iDimY] - 1) * -arrayStep[iDimY]);
9598 65 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
9599 65 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
9600 65 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
9601 65 : int nStrideXSign = 1;
9602 65 : if (arrayStep[iDimX] < 0)
9603 : {
9604 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
9605 2 : nStrideXSign = -1;
9606 : }
9607 65 : int nStrideYSign = 1;
9608 65 : if (arrayStep[iDimY] < 0)
9609 : {
9610 2 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
9611 2 : nStrideYSign = -1;
9612 : }
9613 :
9614 130 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
9615 65 : static_cast<int>(count[iDimX]),
9616 65 : static_cast<int>(count[iDimY]), eDT,
9617 : static_cast<GSpacing>(
9618 65 : nStrideXSign * bufferStride[iDimX] * nDTSize),
9619 : static_cast<GSpacing>(
9620 65 : nStrideYSign * bufferStride[iDimY] * nDTSize),
9621 65 : nullptr) == CE_None;
9622 : }
9623 :
9624 : /************************************************************************/
9625 : /* AsMDArray() */
9626 : /************************************************************************/
9627 :
9628 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
9629 : *
9630 : * The band must be linked to a GDALDataset. If this dataset is not already
9631 : * marked as shared, it will be, so that the returned array holds a reference
9632 : * to it.
9633 : *
9634 : * If the dataset has a geotransform attached, the X and Y dimensions of the
9635 : * returned array will have an associated indexing variable.
9636 : *
9637 : * This is the same as the C function GDALRasterBandAsMDArray().
9638 : *
9639 : * The "reverse" method is GDALMDArray::AsClassicDataset().
9640 : *
9641 : * @return a new array, or nullptr.
9642 : *
9643 : * @since GDAL 3.1
9644 : */
9645 23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
9646 : {
9647 23 : if (!poDS)
9648 : {
9649 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
9650 0 : return nullptr;
9651 : }
9652 23 : if (!poDS->GetShared())
9653 : {
9654 23 : poDS->MarkAsShared();
9655 : }
9656 : return GDALMDArrayFromRasterBand::Create(
9657 23 : poDS, const_cast<GDALRasterBand *>(this));
9658 : }
9659 :
9660 : /************************************************************************/
9661 : /* InterpolateAtPoint() */
9662 : /************************************************************************/
9663 :
9664 : /**
9665 : * \brief Interpolates the value between pixels using a resampling algorithm,
9666 : * taking pixel/line coordinates as input.
9667 : *
9668 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
9669 : * @param dfLine line coordinate as a double, where interpolation should be done.
9670 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
9671 : * @param pdfRealValue pointer to real part of interpolated value
9672 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
9673 : *
9674 : * @return CE_None on success, or an error code on failure.
9675 : * @since GDAL 3.10
9676 : */
9677 :
9678 124 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
9679 : GDALRIOResampleAlg eInterpolation,
9680 : double *pdfRealValue,
9681 : double *pdfImagValue) const
9682 : {
9683 124 : if (eInterpolation != GRIORA_NearestNeighbour &&
9684 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
9685 : eInterpolation != GRIORA_CubicSpline)
9686 : {
9687 2 : CPLError(CE_Failure, CPLE_AppDefined,
9688 : "Only nearest, bilinear, cubic and cubicspline interpolation "
9689 : "methods "
9690 : "allowed");
9691 :
9692 2 : return CE_Failure;
9693 : }
9694 :
9695 122 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
9696 122 : if (!m_poPointsCache)
9697 52 : m_poPointsCache = new GDALDoublePointsCache();
9698 :
9699 : const bool res =
9700 122 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
9701 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
9702 :
9703 122 : return res ? CE_None : CE_Failure;
9704 : }
9705 :
9706 : /************************************************************************/
9707 : /* GDALRasterInterpolateAtPoint() */
9708 : /************************************************************************/
9709 :
9710 : /**
9711 : * \brief Interpolates the value between pixels using
9712 : * a resampling algorithm
9713 : *
9714 : * @see GDALRasterBand::InterpolateAtPoint()
9715 : * @since GDAL 3.10
9716 : */
9717 :
9718 106 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
9719 : double dfLine,
9720 : GDALRIOResampleAlg eInterpolation,
9721 : double *pdfRealValue, double *pdfImagValue)
9722 : {
9723 106 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
9724 :
9725 106 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9726 106 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
9727 106 : pdfRealValue, pdfImagValue);
9728 : }
9729 :
9730 : /************************************************************************/
9731 : /* InterpolateAtGeolocation() */
9732 : /************************************************************************/
9733 :
9734 : /**
9735 : * \brief Interpolates the value between pixels using a resampling algorithm,
9736 : * taking georeferenced coordinates as input.
9737 : *
9738 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
9739 : * must be in the "natural" SRS of the dataset, that is the one returned by
9740 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
9741 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
9742 : * array (generally WGS 84) if there is a geolocation array.
9743 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
9744 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
9745 : * be a easting, and dfGeolocY a northing.
9746 : *
9747 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
9748 : * expressed in that CRS, and that tuple must be conformant with the
9749 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
9750 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
9751 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
9752 : * before calling this method, and in that case, dfGeolocX must be a longitude
9753 : * or an easting value, and dfGeolocX a latitude or a northing value.
9754 : *
9755 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
9756 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
9757 : * it for details on how that transformation is done.
9758 : *
9759 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
9760 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
9761 : * where interpolation should be done.
9762 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
9763 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
9764 : * where interpolation should be done.
9765 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
9766 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
9767 : * @param pdfRealValue pointer to real part of interpolated value
9768 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
9769 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
9770 : *
9771 : * @return CE_None on success, or an error code on failure.
9772 : * @since GDAL 3.11
9773 : */
9774 :
9775 10 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
9776 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
9777 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
9778 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
9779 : {
9780 : double dfPixel;
9781 : double dfLine;
9782 10 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
9783 : &dfLine,
9784 10 : papszTransformerOptions) != CE_None)
9785 : {
9786 1 : return CE_Failure;
9787 : }
9788 9 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
9789 9 : pdfImagValue);
9790 : }
9791 :
9792 : /************************************************************************/
9793 : /* GDALRasterInterpolateAtGeolocation() */
9794 : /************************************************************************/
9795 :
9796 : /**
9797 : * \brief Interpolates the value between pixels using a resampling algorithm,
9798 : * taking georeferenced coordinates as input.
9799 : *
9800 : * @see GDALRasterBand::InterpolateAtGeolocation()
9801 : * @since GDAL 3.11
9802 : */
9803 :
9804 10 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
9805 : double dfGeolocX, double dfGeolocY,
9806 : OGRSpatialReferenceH hSRS,
9807 : GDALRIOResampleAlg eInterpolation,
9808 : double *pdfRealValue,
9809 : double *pdfImagValue,
9810 : CSLConstList papszTransformerOptions)
9811 : {
9812 10 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
9813 :
9814 10 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9815 10 : return poBand->InterpolateAtGeolocation(
9816 10 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
9817 10 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
9818 : }
|