Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Base class for format specific band class implementation. This
5 : * base class provides default implementation for many methods.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1998, Frank Warmerdam
10 : * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "cpl_port.h"
16 : #include "gdal_priv.h"
17 :
18 : #include <climits>
19 : #include <cmath>
20 : #include <cstdarg>
21 : #include <cstddef>
22 : #include <cstdio>
23 : #include <cstdlib>
24 : #include <cstring>
25 : #include <algorithm>
26 : #include <limits>
27 : #include <memory>
28 : #include <new>
29 : #include <type_traits>
30 :
31 : #include "cpl_conv.h"
32 : #include "cpl_error.h"
33 : #include "cpl_float.h"
34 : #include "cpl_progress.h"
35 : #include "cpl_string.h"
36 : #include "cpl_virtualmem.h"
37 : #include "cpl_vsi.h"
38 : #include "gdal.h"
39 : #include "gdal_rat.h"
40 : #include "gdal_priv_templates.hpp"
41 : #include "gdal_interpolateatpoint.h"
42 : #include "gdal_minmax_element.hpp"
43 :
44 : /************************************************************************/
45 : /* GDALRasterBand() */
46 : /************************************************************************/
47 :
48 : /*! Constructor. Applications should never create GDALRasterBands directly. */
49 :
50 1065300 : GDALRasterBand::GDALRasterBand()
51 : : GDALRasterBand(
52 1065300 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
53 : {
54 1065140 : }
55 :
56 : /** Constructor. Applications should never create GDALRasterBands directly.
57 : * @param bForceCachedIOIn Whether cached IO should be forced.
58 : */
59 1201220 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
60 1201220 : : bForceCachedIO(bForceCachedIOIn)
61 :
62 : {
63 1200960 : }
64 :
65 : /************************************************************************/
66 : /* ~GDALRasterBand() */
67 : /************************************************************************/
68 :
69 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
70 : instead destroy the GDALDataset. */
71 :
72 1201190 : GDALRasterBand::~GDALRasterBand()
73 :
74 : {
75 1201220 : if (poDS && poDS->IsMarkedSuppressOnClose())
76 : {
77 433 : if (poBandBlockCache)
78 384 : poBandBlockCache->DisableDirtyBlockWriting();
79 : }
80 1201220 : GDALRasterBand::FlushCache(true);
81 :
82 1201210 : delete poBandBlockCache;
83 :
84 1201220 : if (static_cast<GIntBig>(nBlockReads) >
85 1201220 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
86 214 : nBand == 1 && poDS != nullptr)
87 : {
88 302 : CPLDebug(
89 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
90 151 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
91 151 : poDS->GetDescription());
92 : }
93 :
94 1201220 : InvalidateMaskBand();
95 1201190 : nBand = -nBand;
96 :
97 1201190 : delete m_poPointsCache;
98 1201200 : }
99 :
100 : /************************************************************************/
101 : /* RasterIO() */
102 : /************************************************************************/
103 :
104 : /**
105 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
106 : * int nXOff, int nYOff, int nXSize, int nYSize,
107 : * void * pData, int nBufXSize, int nBufYSize,
108 : * GDALDataType eBufType,
109 : * GSpacing nPixelSpace,
110 : * GSpacing nLineSpace,
111 : * GDALRasterIOExtraArg* psExtraArg )
112 : * \brief Read/write a region of image data for this band.
113 : *
114 : * This method allows reading a region of a GDALRasterBand into a buffer,
115 : * or writing data from a buffer into a region of a GDALRasterBand. It
116 : * automatically takes care of data type translation if the data type
117 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
118 : * The method also takes care of image decimation / replication if the
119 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
120 : * region being accessed (nXSize x nYSize).
121 : *
122 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
123 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
124 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
125 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
126 : * Or use nLineSpace and a possibly shifted pData value.
127 : *
128 : * The nPixelSpace and nLineSpace parameters allow reading into or
129 : * writing from unusually organized buffers. This is primarily used
130 : * for buffers containing more than one bands raster data in interleaved
131 : * format.
132 : *
133 : * Some formats may efficiently implement decimation into a buffer by
134 : * reading from lower resolution overview images. The logic of the default
135 : * implementation in the base class GDALRasterBand is the following one. It
136 : * computes a target_downscaling_factor from the window of interest and buffer
137 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
138 : * It then walks through overviews and will select the first one whose
139 : * downscaling factor is greater than target_downscaling_factor / 1.2.
140 : *
141 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
142 : * The relationship between target_downscaling_factor and the select overview
143 : * level is the following one:
144 : *
145 : * target_downscaling_factor | selected_overview
146 : * ------------------------- | -----------------
147 : * ]0, 2 / 1.2] | full resolution band
148 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
149 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
150 : * ]8 / 1.2, infinity[ | 8x downsampled band
151 : *
152 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
153 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
154 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
155 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
156 : * this oversampling threshold defaults to 1. Consequently if there are overviews
157 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
158 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
159 : *
160 : * For highest performance full resolution data access, read and write
161 : * on "block boundaries" as returned by GetBlockSize(), or use the
162 : * ReadBlock() and WriteBlock() methods.
163 : *
164 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
165 : * functions.
166 : *
167 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
168 : * write a region of data.
169 : *
170 : * @param nXOff The pixel offset to the top left corner of the region
171 : * of the band to be accessed. This would be zero to start from the left side.
172 : *
173 : * @param nYOff The line offset to the top left corner of the region
174 : * of the band to be accessed. This would be zero to start from the top.
175 : *
176 : * @param nXSize The width of the region of the band to be accessed in pixels.
177 : *
178 : * @param nYSize The height of the region of the band to be accessed in lines.
179 : *
180 : * @param pData The buffer into which the data should be read, or from which
181 : * it should be written. This buffer must contain at least nBufXSize *
182 : * nBufYSize words of type eBufType. It is organized in left to right,
183 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
184 : * and nLineSpace parameters.
185 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
186 : * temporarily modified during the execution of this method (and eventually
187 : * restored back to its original content), so it is not safe to use a buffer
188 : * stored in a read-only section of the calling program.
189 : *
190 : * @param nBufXSize the width of the buffer image into which the desired region
191 : * is to be read, or from which it is to be written.
192 : *
193 : * @param nBufYSize the height of the buffer image into which the desired region
194 : * is to be read, or from which it is to be written.
195 : *
196 : * @param eBufType the type of the pixel values in the pData data buffer. The
197 : * pixel values will automatically be translated to/from the GDALRasterBand
198 : * data type as needed. Most driver implementations will use GDALCopyWords64()
199 : * to perform data type translation.
200 : *
201 : * @param nPixelSpace The byte offset from the start of one pixel value in
202 : * pData to the start of the next pixel value within a scanline. If defaulted
203 : * (0) the size of the datatype eBufType is used.
204 : *
205 : * @param nLineSpace The byte offset from the start of one scanline in
206 : * pData to the start of the next. If defaulted (0) the size of the datatype
207 : * eBufType * nBufXSize is used.
208 : *
209 : * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
210 : * structure with additional arguments to specify resampling and progress
211 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
212 : * configuration option can also be defined to override the default resampling
213 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
214 : *
215 : * @return CE_Failure if the access fails, otherwise CE_None.
216 : */
217 :
218 : /**
219 : * \brief Read/write a region of image data for this band.
220 : *
221 : * This method allows reading a region of a GDALRasterBand into a buffer,
222 : * or writing data from a buffer into a region of a GDALRasterBand. It
223 : * automatically takes care of data type translation if the data type
224 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
225 : * The method also takes care of image decimation / replication if the
226 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
227 : * region being accessed (nXSize x nYSize).
228 : *
229 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
230 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
231 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
232 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
233 : * Or use nLineSpace and a possibly shifted pData value.
234 : *
235 : * The nPixelSpace and nLineSpace parameters allow reading into or
236 : * writing from unusually organized buffers. This is primarily used
237 : * for buffers containing more than one bands raster data in interleaved
238 : * format.
239 : *
240 : * Some formats may efficiently implement decimation into a buffer by
241 : * reading from lower resolution overview images. The logic of the default
242 : * implementation in the base class GDALRasterBand is the following one. It
243 : * computes a target_downscaling_factor from the window of interest and buffer
244 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
245 : * It then walks through overviews and will select the first one whose
246 : * downscaling factor is greater than target_downscaling_factor / 1.2.
247 : *
248 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
249 : * The relationship between target_downscaling_factor and the select overview
250 : * level is the following one:
251 : *
252 : * target_downscaling_factor | selected_overview
253 : * ------------------------- | -----------------
254 : * ]0, 2 / 1.2] | full resolution band
255 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
256 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
257 : * ]8 / 1.2, infinity[ | 8x downsampled band
258 : *
259 : * For highest performance full resolution data access, read and write
260 : * on "block boundaries" as returned by GetBlockSize(), or use the
261 : * ReadBlock() and WriteBlock() methods.
262 : *
263 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
264 : * functions.
265 : *
266 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
267 : * more convenient to use for most common use cases.
268 : *
269 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
270 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
271 : * instance of this dataset) concurrently from several threads.
272 : *
273 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
274 : * write a region of data.
275 : *
276 : * @param nXOff The pixel offset to the top left corner of the region
277 : * of the band to be accessed. This would be zero to start from the left side.
278 : *
279 : * @param nYOff The line offset to the top left corner of the region
280 : * of the band to be accessed. This would be zero to start from the top.
281 : *
282 : * @param nXSize The width of the region of the band to be accessed in pixels.
283 : *
284 : * @param nYSize The height of the region of the band to be accessed in lines.
285 : *
286 : * @param[in,out] pData The buffer into which the data should be read, or from
287 : * which it should be written. This buffer must contain at least nBufXSize *
288 : * nBufYSize words of type eBufType. It is organized in left to right,
289 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
290 : * and nLineSpace parameters.
291 : *
292 : * @param nBufXSize the width of the buffer image into which the desired region
293 : * is to be read, or from which it is to be written.
294 : *
295 : * @param nBufYSize the height of the buffer image into which the desired region
296 : * is to be read, or from which it is to be written.
297 : *
298 : * @param eBufType the type of the pixel values in the pData data buffer. The
299 : * pixel values will automatically be translated to/from the GDALRasterBand
300 : * data type as needed.
301 : *
302 : * @param nPixelSpace The byte offset from the start of one pixel value in
303 : * pData to the start of the next pixel value within a scanline. If defaulted
304 : * (0) the size of the datatype eBufType is used.
305 : *
306 : * @param nLineSpace The byte offset from the start of one scanline in
307 : * pData to the start of the next. If defaulted (0) the size of the datatype
308 : * eBufType * nBufXSize is used.
309 : *
310 : * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
311 : * structure with additional arguments to specify resampling and progress
312 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
313 : * configuration option can also be defined to override the default resampling
314 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
315 : *
316 : * @return CE_Failure if the access fails, otherwise CE_None.
317 : *
318 : * @see GDALRasterBand::ReadRaster()
319 : */
320 :
321 3752100 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
322 : int nXSize, int nYSize, void *pData,
323 : int nBufXSize, int nBufYSize,
324 : GDALDataType eBufType, GSpacing nPixelSpace,
325 : GSpacing nLineSpace,
326 : GDALRasterIOExtraArg *psExtraArg)
327 :
328 : {
329 : GDALRasterIOExtraArg sExtraArg;
330 3752100 : if (psExtraArg == nullptr)
331 : {
332 3668390 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
333 3668390 : psExtraArg = &sExtraArg;
334 : }
335 83717 : else if (CPL_UNLIKELY(psExtraArg->nVersion !=
336 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
337 : {
338 0 : ReportError(CE_Failure, CPLE_AppDefined,
339 : "Unhandled version of GDALRasterIOExtraArg");
340 0 : return CE_Failure;
341 : }
342 :
343 3752100 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
344 : nBufYSize);
345 :
346 3751880 : if (CPL_UNLIKELY(nullptr == pData))
347 : {
348 0 : ReportError(CE_Failure, CPLE_AppDefined,
349 : "The buffer into which the data should be read is null");
350 0 : return CE_Failure;
351 : }
352 :
353 : /* -------------------------------------------------------------------- */
354 : /* Some size values are "noop". Lets just return to avoid */
355 : /* stressing lower level functions. */
356 : /* -------------------------------------------------------------------- */
357 3751880 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
358 : nBufYSize < 1))
359 : {
360 2 : CPLDebug("GDAL",
361 : "RasterIO() skipped for odd window or buffer size.\n"
362 : " Window = (%d,%d)x%dx%d\n"
363 : " Buffer = %dx%d\n",
364 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
365 :
366 2 : return CE_None;
367 : }
368 :
369 3751880 : if (eRWFlag == GF_Write)
370 : {
371 213378 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
372 : {
373 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
374 : "An error occurred while writing a dirty block "
375 : "from GDALRasterBand::RasterIO");
376 0 : CPLErr eErr = eFlushBlockErr;
377 0 : eFlushBlockErr = CE_None;
378 0 : return eErr;
379 : }
380 213378 : if (CPL_UNLIKELY(eAccess != GA_Update))
381 : {
382 3 : ReportError(CE_Failure, CPLE_AppDefined,
383 : "Write operation not permitted on dataset opened "
384 : "in read-only mode");
385 3 : return CE_Failure;
386 : }
387 : }
388 :
389 : /* -------------------------------------------------------------------- */
390 : /* If pixel and line spacing are defaulted assign reasonable */
391 : /* value assuming a packed buffer. */
392 : /* -------------------------------------------------------------------- */
393 3751880 : if (nPixelSpace == 0)
394 : {
395 3662010 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
396 : }
397 :
398 3751690 : if (nLineSpace == 0)
399 : {
400 3656320 : nLineSpace = nPixelSpace * nBufXSize;
401 : }
402 :
403 : /* -------------------------------------------------------------------- */
404 : /* Do some validation of parameters. */
405 : /* -------------------------------------------------------------------- */
406 3751690 : if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
407 : nXOff + nXSize > nRasterXSize || nYOff < 0 ||
408 : nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
409 : {
410 14 : ReportError(CE_Failure, CPLE_IllegalArg,
411 : "Access window out of range in RasterIO(). Requested\n"
412 : "(%d,%d) of size %dx%d on raster of %dx%d.",
413 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
414 14 : return CE_Failure;
415 : }
416 :
417 3751670 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
418 : {
419 0 : ReportError(
420 : CE_Failure, CPLE_IllegalArg,
421 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
422 : eRWFlag);
423 0 : return CE_Failure;
424 : }
425 3751670 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
426 : {
427 2 : ReportError(CE_Failure, CPLE_IllegalArg,
428 : "Illegal GDT_Unknown/GDT_TypeCount argument");
429 2 : return CE_Failure;
430 : }
431 :
432 : /* -------------------------------------------------------------------- */
433 : /* Call the format specific function. */
434 : /* -------------------------------------------------------------------- */
435 :
436 3751670 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
437 :
438 : CPLErr eErr;
439 3747480 : if (bForceCachedIO)
440 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
441 : pData, nBufXSize, nBufYSize, eBufType,
442 : nPixelSpace, nLineSpace, psExtraArg);
443 : else
444 : eErr =
445 3748390 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
446 3747460 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
447 :
448 3748410 : if (bCallLeaveReadWrite)
449 220768 : LeaveReadWrite();
450 :
451 3745270 : return eErr;
452 : }
453 :
454 : /************************************************************************/
455 : /* GDALRasterIO() */
456 : /************************************************************************/
457 :
458 : /**
459 : * \brief Read/write a region of image data for this band.
460 : *
461 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
462 : * resolution, progress callback, etc. are needed)
463 : *
464 : * @see GDALRasterBand::RasterIO()
465 : */
466 :
467 3445180 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
468 : int nXOff, int nYOff, int nXSize, int nYSize,
469 : void *pData, int nBufXSize, int nBufYSize,
470 : GDALDataType eBufType, int nPixelSpace,
471 : int nLineSpace)
472 :
473 : {
474 3445180 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
475 :
476 3445180 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
477 :
478 3444160 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
479 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
480 3437100 : nLineSpace, nullptr));
481 : }
482 :
483 : /************************************************************************/
484 : /* GDALRasterIOEx() */
485 : /************************************************************************/
486 :
487 : /**
488 : * \brief Read/write a region of image data for this band.
489 : *
490 : * @see GDALRasterBand::RasterIO()
491 : * @since GDAL 2.0
492 : */
493 :
494 35159 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
495 : int nXOff, int nYOff, int nXSize, int nYSize,
496 : void *pData, int nBufXSize, int nBufYSize,
497 : GDALDataType eBufType, GSpacing nPixelSpace,
498 : GSpacing nLineSpace,
499 : GDALRasterIOExtraArg *psExtraArg)
500 :
501 : {
502 35159 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
503 :
504 35159 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
505 :
506 35159 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
507 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
508 35158 : nLineSpace, psExtraArg));
509 : }
510 :
511 : /************************************************************************/
512 : /* GetGDTFromCppType() */
513 : /************************************************************************/
514 :
515 : namespace
516 : {
517 : template <class T> struct GetGDTFromCppType;
518 :
519 : #define DEFINE_GetGDTFromCppType(T, eDT) \
520 : template <> struct GetGDTFromCppType<T> \
521 : { \
522 : static constexpr GDALDataType GDT = eDT; \
523 : }
524 :
525 : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
526 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
527 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
528 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
529 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
530 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
531 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
532 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
533 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
534 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
535 : // Not allowed by C++ standard
536 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
537 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
538 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
539 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
540 : } // namespace
541 :
542 : /************************************************************************/
543 : /* ReadRaster() */
544 : /************************************************************************/
545 :
546 : // clang-format off
547 : /** Read a region of image data for this band.
548 : *
549 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
550 : * for common use cases, like reading a whole band.
551 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
552 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
553 : * float, double, std::complex<float|double>.
554 : *
555 : * 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>&,
556 : * and can allocate memory automatically.
557 : *
558 : * To read a whole band (assuming it fits into memory), as an array of double:
559 : *
560 : \code{.cpp}
561 : double* myArray = static_cast<double*>(
562 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
563 : // TODO: check here that myArray != nullptr
564 : const size_t nArrayEltCount =
565 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
566 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
567 : {
568 : // do something
569 : }
570 : VSIFree(myArray)
571 : \endcode
572 : *
573 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
574 : *
575 : \code{.cpp}
576 : double* myArray = static_cast<double*>(
577 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
578 : // TODO: check here that myArray != nullptr
579 : const size_t nArrayEltCount = 128 * 128;
580 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
581 : {
582 : // do something
583 : }
584 : VSIFree(myArray)
585 : \endcode
586 : *
587 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
588 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
589 : * instance of this dataset) concurrently from several threads.
590 : *
591 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
592 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
593 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
594 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
595 : * Or use nLineSpace and a possibly shifted pData value.
596 : *
597 : * @param[out] pData The buffer into which the data should be written.
598 : * This buffer must contain at least nBufXSize *
599 : * nBufYSize words of type T. It is organized in left to right,
600 : * top to bottom pixel order, and fully packed.
601 : * The type of the buffer does not need to be the one of GetDataType(). The
602 : * method will perform data type translation (with potential rounding, clamping)
603 : * if needed.
604 : *
605 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
606 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
607 : * return in error if it is not. If set to zero, then pData is trusted to be
608 : * large enough.
609 : *
610 : * @param dfXOff The pixel offset to the top left corner of the region
611 : * of the band to be accessed. This would be zero to start from the left side.
612 : * Defaults to 0.
613 : *
614 : * @param dfYOff The line offset to the top left corner of the region
615 : * of the band to be accessed. This would be zero to start from the top.
616 : * Defaults to 0.
617 : *
618 : * @param dfXSize The width of the region of the band to be accessed in pixels.
619 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
620 : * dfXSize is set to the band width.
621 : *
622 : * @param dfYSize The height of the region of the band to be accessed in lines.
623 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
624 : * dfYSize is set to the band height.
625 : *
626 : * @param nBufXSize the width of the buffer image into which the desired region
627 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
628 : * then nBufXSize is initialized with dfXSize.
629 : *
630 : * @param nBufYSize the height of the buffer image into which the desired region
631 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
632 : * then nBufYSize is initialized with dfYSize.
633 : *
634 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
635 : *
636 : * @param pfnProgress Progress function. May be nullptr.
637 : *
638 : * @param pProgressData User data of pfnProgress. May be nullptr.
639 : *
640 : * @return CE_Failure if the access fails, otherwise CE_None.
641 : *
642 : * @see GDALRasterBand::RasterIO()
643 : * @since GDAL 3.10
644 : */
645 : // clang-format on
646 :
647 : template <class T>
648 19 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
649 : double dfXOff, double dfYOff, double dfXSize,
650 : double dfYSize, size_t nBufXSize,
651 : size_t nBufYSize,
652 : GDALRIOResampleAlg eResampleAlg,
653 : GDALProgressFunc pfnProgress,
654 : void *pProgressData) const
655 : {
656 19 : if (((nBufXSize | nBufYSize) >> 31) != 0)
657 : {
658 2 : return CE_Failure;
659 : }
660 :
661 17 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
662 : {
663 15 : dfXSize = nRasterXSize;
664 15 : dfYSize = nRasterYSize;
665 : }
666 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
667 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
668 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
669 2 : dfYOff + dfYSize > INT_MAX)
670 : {
671 0 : return CE_Failure;
672 : }
673 :
674 : GDALRasterIOExtraArg sExtraArg;
675 17 : sExtraArg.nVersion = 1;
676 17 : sExtraArg.eResampleAlg = eResampleAlg;
677 17 : sExtraArg.pfnProgress = pfnProgress;
678 17 : sExtraArg.pProgressData = pProgressData;
679 17 : sExtraArg.bFloatingPointWindowValidity = true;
680 17 : sExtraArg.dfXOff = dfXOff;
681 17 : sExtraArg.dfYOff = dfYOff;
682 17 : sExtraArg.dfXSize = dfXSize;
683 17 : sExtraArg.dfYSize = dfYSize;
684 17 : const int nXOff = static_cast<int>(dfXOff);
685 17 : const int nYOff = static_cast<int>(dfYOff);
686 17 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
687 17 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
688 17 : if (nBufXSize == 0 && nBufYSize == 0)
689 : {
690 16 : if (static_cast<int>(dfXSize) == dfXSize &&
691 16 : static_cast<int>(dfYSize) == dfYSize)
692 : {
693 16 : nBufXSize = static_cast<int>(dfXSize);
694 16 : nBufYSize = static_cast<int>(dfYSize);
695 : }
696 : else
697 : {
698 0 : CPLError(CE_Failure, CPLE_AppDefined,
699 : "nBufXSize and nBufYSize must be provided if dfXSize or "
700 : "dfYSize is not an integer value");
701 0 : return CE_Failure;
702 : }
703 : }
704 17 : if (nBufXSize == 0 || nBufYSize == 0)
705 : {
706 0 : CPLDebug("GDAL",
707 : "RasterIO() skipped for odd window or buffer size.\n"
708 : " Window = (%d,%d)x%dx%d\n"
709 : " Buffer = %dx%d\n",
710 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
711 : static_cast<int>(nBufYSize));
712 :
713 0 : return CE_None;
714 : }
715 :
716 17 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
717 : {
718 1 : CPLError(CE_Failure, CPLE_AppDefined,
719 : "Provided array is not large enough");
720 1 : return CE_Failure;
721 : }
722 :
723 16 : constexpr GSpacing nPixelSpace = sizeof(T);
724 16 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
725 16 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
726 :
727 16 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
728 :
729 : const bool bCallLeaveReadWrite =
730 16 : CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
731 : CPLErr eErr;
732 : // coverity[identical_branches]
733 16 : if (bForceCachedIO)
734 0 : eErr = pThis->GDALRasterBand::IRasterIO(
735 : GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
736 : static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
737 : nPixelSpace, nLineSpace, &sExtraArg);
738 : else
739 16 : eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
740 : static_cast<int>(nBufXSize),
741 : static_cast<int>(nBufYSize), eBufType,
742 : nPixelSpace, nLineSpace, &sExtraArg);
743 :
744 16 : if (bCallLeaveReadWrite)
745 0 : pThis->LeaveReadWrite();
746 :
747 16 : return eErr;
748 : }
749 :
750 : //! @cond Doxygen_Suppress
751 :
752 : #define INSTANTIATE_READ_RASTER(T) \
753 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
754 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
755 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
756 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
757 : void *pProgressData) const;
758 :
759 : INSTANTIATE_READ_RASTER(uint8_t)
760 : INSTANTIATE_READ_RASTER(int8_t)
761 : INSTANTIATE_READ_RASTER(uint16_t)
762 : INSTANTIATE_READ_RASTER(int16_t)
763 : INSTANTIATE_READ_RASTER(uint32_t)
764 : INSTANTIATE_READ_RASTER(int32_t)
765 : INSTANTIATE_READ_RASTER(uint64_t)
766 : INSTANTIATE_READ_RASTER(int64_t)
767 : INSTANTIATE_READ_RASTER(float)
768 : INSTANTIATE_READ_RASTER(double)
769 : // Not allowed by C++ standard
770 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
771 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
772 : INSTANTIATE_READ_RASTER(std::complex<float>)
773 : INSTANTIATE_READ_RASTER(std::complex<double>)
774 :
775 : //! @endcond
776 :
777 : /************************************************************************/
778 : /* ReadRaster() */
779 : /************************************************************************/
780 :
781 : /** Read a region of image data for this band.
782 : *
783 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
784 : * for common use cases, like reading a whole band.
785 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
786 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
787 : * float, double, std::complex<float|double>.
788 : *
789 : * To read a whole band (assuming it fits into memory), as a vector of double:
790 : *
791 : \code
792 : std::vector<double> myArray;
793 : if (poBand->ReadRaster(myArray) == CE_None)
794 : {
795 : // do something
796 : }
797 : \endcode
798 : *
799 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
800 : *
801 : \code{.cpp}
802 : std::vector<double> myArray;
803 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
804 : {
805 : // do something
806 : }
807 : \endcode
808 : *
809 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
810 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
811 : * instance of this dataset) concurrently from several threads.
812 : *
813 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
814 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
815 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
816 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
817 : * Or use nLineSpace and a possibly shifted pData value.
818 : *
819 : * @param[out] vData The vector into which the data should be written.
820 : * The vector will be resized, if needed, to contain at least nBufXSize *
821 : * nBufYSize values. The values in the vector are organized in left to right,
822 : * top to bottom pixel order, and fully packed.
823 : * The type of the vector does not need to be the one of GetDataType(). The
824 : * method will perform data type translation (with potential rounding, clamping)
825 : * if needed.
826 : *
827 : * @param dfXOff The pixel offset to the top left corner of the region
828 : * of the band to be accessed. This would be zero to start from the left side.
829 : * Defaults to 0.
830 : *
831 : * @param dfYOff The line offset to the top left corner of the region
832 : * of the band to be accessed. This would be zero to start from the top.
833 : * Defaults to 0.
834 : *
835 : * @param dfXSize The width of the region of the band to be accessed in pixels.
836 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
837 : * dfXSize is set to the band width.
838 : *
839 : * @param dfYSize The height of the region of the band to be accessed in lines.
840 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
841 : * dfYSize is set to the band height.
842 : *
843 : * @param nBufXSize the width of the buffer image into which the desired region
844 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
845 : * then nBufXSize is initialized with dfXSize.
846 : *
847 : * @param nBufYSize the height of the buffer image into which the desired region
848 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
849 : * then nBufYSize is initialized with dfYSize.
850 : *
851 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
852 : *
853 : * @param pfnProgress Progress function. May be nullptr.
854 : *
855 : * @param pProgressData User data of pfnProgress. May be nullptr.
856 : *
857 : * @return CE_Failure if the access fails, otherwise CE_None.
858 : *
859 : * @see GDALRasterBand::RasterIO()
860 : * @since GDAL 3.10
861 : */
862 : template <class T>
863 21 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
864 : double dfYOff, double dfXSize, double dfYSize,
865 : size_t nBufXSize, size_t nBufYSize,
866 : GDALRIOResampleAlg eResampleAlg,
867 : GDALProgressFunc pfnProgress,
868 : void *pProgressData) const
869 : {
870 21 : if (((nBufXSize | nBufYSize) >> 31) != 0)
871 : {
872 2 : return CE_Failure;
873 : }
874 :
875 19 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
876 : {
877 12 : dfXSize = nRasterXSize;
878 12 : dfYSize = nRasterYSize;
879 : }
880 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
881 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
882 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
883 7 : dfYOff + dfYSize > INT_MAX)
884 : {
885 0 : return CE_Failure;
886 : }
887 :
888 : GDALRasterIOExtraArg sExtraArg;
889 19 : sExtraArg.nVersion = 1;
890 19 : sExtraArg.eResampleAlg = eResampleAlg;
891 19 : sExtraArg.pfnProgress = pfnProgress;
892 19 : sExtraArg.pProgressData = pProgressData;
893 19 : sExtraArg.bFloatingPointWindowValidity = true;
894 19 : sExtraArg.dfXOff = dfXOff;
895 19 : sExtraArg.dfYOff = dfYOff;
896 19 : sExtraArg.dfXSize = dfXSize;
897 19 : sExtraArg.dfYSize = dfYSize;
898 19 : const int nXOff = static_cast<int>(dfXOff);
899 19 : const int nYOff = static_cast<int>(dfYOff);
900 19 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
901 19 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
902 19 : if (nBufXSize == 0 && nBufYSize == 0)
903 : {
904 15 : if (static_cast<int>(dfXSize) == dfXSize &&
905 14 : static_cast<int>(dfYSize) == dfYSize)
906 : {
907 14 : nBufXSize = static_cast<int>(dfXSize);
908 14 : nBufYSize = static_cast<int>(dfYSize);
909 : }
910 : else
911 : {
912 1 : CPLError(CE_Failure, CPLE_AppDefined,
913 : "nBufXSize and nBufYSize must be provided if "
914 : "dfXSize or dfYSize is not an integer value");
915 1 : return CE_Failure;
916 : }
917 : }
918 18 : if (nBufXSize == 0 || nBufYSize == 0)
919 : {
920 0 : CPLDebug("GDAL",
921 : "RasterIO() skipped for odd window or buffer size.\n"
922 : " Window = (%d,%d)x%dx%d\n"
923 : " Buffer = %dx%d\n",
924 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
925 : static_cast<int>(nBufYSize));
926 :
927 0 : return CE_None;
928 : }
929 :
930 : if constexpr (SIZEOF_VOIDP < 8)
931 : {
932 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
933 : {
934 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
935 : return CE_Failure;
936 : }
937 : }
938 :
939 18 : if (vData.size() < nBufXSize * nBufYSize)
940 : {
941 : try
942 : {
943 16 : vData.resize(nBufXSize * nBufYSize);
944 : }
945 1 : catch (const std::exception &)
946 : {
947 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
948 1 : return CE_Failure;
949 : }
950 : }
951 :
952 17 : constexpr GSpacing nPixelSpace = sizeof(T);
953 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
954 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
955 :
956 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
957 :
958 : const bool bCallLeaveReadWrite =
959 17 : CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
960 :
961 : CPLErr eErr;
962 : // coverity[identical_branches]
963 17 : if (bForceCachedIO)
964 0 : eErr = pThis->GDALRasterBand::IRasterIO(
965 : GF_Read, nXOff, nYOff, nXSize, nYSize, vData.data(),
966 : static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
967 : nPixelSpace, nLineSpace, &sExtraArg);
968 : else
969 17 : eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
970 : vData.data(), static_cast<int>(nBufXSize),
971 : static_cast<int>(nBufYSize), eBufType,
972 : nPixelSpace, nLineSpace, &sExtraArg);
973 :
974 17 : if (bCallLeaveReadWrite)
975 0 : pThis->LeaveReadWrite();
976 :
977 17 : return eErr;
978 : }
979 :
980 : //! @cond Doxygen_Suppress
981 :
982 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
983 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
984 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
985 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
986 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
987 : void *pProgressData) const;
988 :
989 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
990 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
991 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
992 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
993 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
994 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
995 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
996 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
997 : INSTANTIATE_READ_RASTER_VECTOR(float)
998 : INSTANTIATE_READ_RASTER_VECTOR(double)
999 : // Not allowed by C++ standard
1000 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
1001 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
1002 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
1003 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
1004 :
1005 : //! @endcond
1006 :
1007 : /************************************************************************/
1008 : /* ReadBlock() */
1009 : /************************************************************************/
1010 :
1011 : /**
1012 : * \brief Read a block of image data efficiently.
1013 : *
1014 : * This method accesses a "natural" block from the raster band without
1015 : * resampling, or data type conversion. For a more generalized, but
1016 : * potentially less efficient access use RasterIO().
1017 : *
1018 : * This method is the same as the C GDALReadBlock() function.
1019 : *
1020 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1021 : * block oriented data without an extra copy into an application buffer.
1022 : *
1023 : * The following code would efficiently compute a histogram of eight bit
1024 : * raster data. Note that the final block may be partial ... data beyond
1025 : * the edge of the underlying raster band in these edge blocks is of an
1026 : * undetermined value.
1027 : *
1028 : \code{.cpp}
1029 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1030 :
1031 : {
1032 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1033 :
1034 : CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1035 :
1036 : int nXBlockSize, nYBlockSize;
1037 :
1038 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1039 : int nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
1040 : int nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
1041 :
1042 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1043 :
1044 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1045 : {
1046 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1047 : {
1048 : int nXValid, nYValid;
1049 :
1050 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1051 :
1052 : // Compute the portion of the block that is valid
1053 : // for partial edge blocks.
1054 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1055 :
1056 : // Collect the histogram counts.
1057 : for( int iY = 0; iY < nYValid; iY++ )
1058 : {
1059 : for( int iX = 0; iX < nXValid; iX++ )
1060 : {
1061 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1062 : }
1063 : }
1064 : }
1065 : }
1066 : }
1067 : \endcode
1068 : *
1069 : * @param nXBlockOff the horizontal block offset, with zero indicating
1070 : * the left most block, 1 the next block and so forth.
1071 : *
1072 : * @param nYBlockOff the vertical block offset, with zero indicating
1073 : * the top most block, 1 the next block and so forth.
1074 : *
1075 : * @param pImage the buffer into which the data will be read. The buffer
1076 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1077 : * of type GetRasterDataType().
1078 : *
1079 : * @return CE_None on success or CE_Failure on an error.
1080 : */
1081 :
1082 644 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1083 :
1084 : {
1085 : /* -------------------------------------------------------------------- */
1086 : /* Validate arguments. */
1087 : /* -------------------------------------------------------------------- */
1088 644 : CPLAssert(pImage != nullptr);
1089 :
1090 644 : if (!InitBlockInfo())
1091 0 : return CE_Failure;
1092 :
1093 644 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1094 : {
1095 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1096 : "Illegal nXBlockOff value (%d) in "
1097 : "GDALRasterBand::ReadBlock()\n",
1098 : nXBlockOff);
1099 :
1100 0 : return (CE_Failure);
1101 : }
1102 :
1103 644 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1104 : {
1105 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1106 : "Illegal nYBlockOff value (%d) in "
1107 : "GDALRasterBand::ReadBlock()\n",
1108 : nYBlockOff);
1109 :
1110 0 : return (CE_Failure);
1111 : }
1112 :
1113 : /* -------------------------------------------------------------------- */
1114 : /* Invoke underlying implementation method. */
1115 : /* -------------------------------------------------------------------- */
1116 :
1117 644 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1118 644 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1119 644 : if (bCallLeaveReadWrite)
1120 4 : LeaveReadWrite();
1121 644 : return eErr;
1122 : }
1123 :
1124 : /************************************************************************/
1125 : /* GDALReadBlock() */
1126 : /************************************************************************/
1127 :
1128 : /**
1129 : * \brief Read a block of image data efficiently.
1130 : *
1131 : * @see GDALRasterBand::ReadBlock()
1132 : */
1133 :
1134 67 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1135 : void *pData)
1136 :
1137 : {
1138 67 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1139 :
1140 67 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1141 67 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1142 : }
1143 :
1144 : /************************************************************************/
1145 : /* IReadBlock() */
1146 : /************************************************************************/
1147 :
1148 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1149 : * ) \brief Read a block of data.
1150 : *
1151 : * Default internal implementation ... to be overridden by
1152 : * subclasses that support reading.
1153 : * @param nBlockXOff Block X Offset
1154 : * @param nBlockYOff Block Y Offset
1155 : * @param pData Pixel buffer into which to place read data.
1156 : * @return CE_None on success or CE_Failure on an error.
1157 : */
1158 :
1159 : /************************************************************************/
1160 : /* IWriteBlock() */
1161 : /************************************************************************/
1162 :
1163 : /**
1164 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1165 : * Write a block of data.
1166 : *
1167 : * Default internal implementation ... to be overridden by
1168 : * subclasses that support writing.
1169 : * @param nBlockXOff Block X Offset
1170 : * @param nBlockYOff Block Y Offset
1171 : * @param pData Pixel buffer to write
1172 : * @return CE_None on success or CE_Failure on an error.
1173 : */
1174 :
1175 : /**/
1176 : /**/
1177 :
1178 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1179 : void * /*pData*/)
1180 :
1181 : {
1182 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1183 0 : ReportError(CE_Failure, CPLE_NotSupported,
1184 : "WriteBlock() not supported for this dataset.");
1185 :
1186 0 : return (CE_Failure);
1187 : }
1188 :
1189 : /************************************************************************/
1190 : /* WriteBlock() */
1191 : /************************************************************************/
1192 :
1193 : /**
1194 : * \brief Write a block of image data efficiently.
1195 : *
1196 : * This method accesses a "natural" block from the raster band without
1197 : * resampling, or data type conversion. For a more generalized, but
1198 : * potentially less efficient access use RasterIO().
1199 : *
1200 : * This method is the same as the C GDALWriteBlock() function.
1201 : *
1202 : * See ReadBlock() for an example of block oriented data access.
1203 : *
1204 : * @param nXBlockOff the horizontal block offset, with zero indicating
1205 : * the left most block, 1 the next block and so forth.
1206 : *
1207 : * @param nYBlockOff the vertical block offset, with zero indicating
1208 : * the left most block, 1 the next block and so forth.
1209 : *
1210 : * @param pImage the buffer from which the data will be written. The buffer
1211 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1212 : * of type GetRasterDataType(). Note that the content of the buffer might be
1213 : * temporarily modified during the execution of this method (and eventually
1214 : * restored back to its original content), so it is not safe to use a buffer
1215 : * stored in a read-only section of the calling program.
1216 : *
1217 : * @return CE_None on success or CE_Failure on an error.
1218 : */
1219 :
1220 4888 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1221 :
1222 : {
1223 : /* -------------------------------------------------------------------- */
1224 : /* Validate arguments. */
1225 : /* -------------------------------------------------------------------- */
1226 4888 : CPLAssert(pImage != nullptr);
1227 :
1228 4888 : if (!InitBlockInfo())
1229 0 : return CE_Failure;
1230 :
1231 4888 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1232 : {
1233 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1234 : "Illegal nXBlockOff value (%d) in "
1235 : "GDALRasterBand::WriteBlock()\n",
1236 : nXBlockOff);
1237 :
1238 0 : return (CE_Failure);
1239 : }
1240 :
1241 4888 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1242 : {
1243 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1244 : "Illegal nYBlockOff value (%d) in "
1245 : "GDALRasterBand::WriteBlock()\n",
1246 : nYBlockOff);
1247 :
1248 0 : return (CE_Failure);
1249 : }
1250 :
1251 4888 : if (eAccess == GA_ReadOnly)
1252 : {
1253 0 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1254 : "Attempt to write to read only dataset in"
1255 : "GDALRasterBand::WriteBlock().\n");
1256 :
1257 0 : return (CE_Failure);
1258 : }
1259 :
1260 4888 : if (eFlushBlockErr != CE_None)
1261 : {
1262 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1263 : "An error occurred while writing a dirty block "
1264 : "from GDALRasterBand::WriteBlock");
1265 0 : CPLErr eErr = eFlushBlockErr;
1266 0 : eFlushBlockErr = CE_None;
1267 0 : return eErr;
1268 : }
1269 :
1270 : /* -------------------------------------------------------------------- */
1271 : /* Invoke underlying implementation method. */
1272 : /* -------------------------------------------------------------------- */
1273 :
1274 4888 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1275 4888 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1276 4888 : if (bCallLeaveReadWrite)
1277 4888 : LeaveReadWrite();
1278 :
1279 4888 : return eErr;
1280 : }
1281 :
1282 : /************************************************************************/
1283 : /* GDALWriteBlock() */
1284 : /************************************************************************/
1285 :
1286 : /**
1287 : * \brief Write a block of image data efficiently.
1288 : *
1289 : * @see GDALRasterBand::WriteBlock()
1290 : */
1291 :
1292 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1293 : void *pData)
1294 :
1295 : {
1296 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1297 :
1298 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1299 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1300 : }
1301 :
1302 : /************************************************************************/
1303 : /* GetActualBlockSize() */
1304 : /************************************************************************/
1305 : /**
1306 : * \brief Fetch the actual block size for a given block offset.
1307 : *
1308 : * Handles partial blocks at the edges of the raster and returns the true
1309 : * number of pixels
1310 : *
1311 : * @param nXBlockOff the horizontal block offset for which to calculate the
1312 : * number of valid pixels, with zero indicating the left most block, 1 the next
1313 : * block and so forth.
1314 : *
1315 : * @param nYBlockOff the vertical block offset, with zero indicating
1316 : * the top most block, 1 the next block and so forth.
1317 : *
1318 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1319 : * the x direction will be stored
1320 : *
1321 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1322 : * the y direction will be stored
1323 : *
1324 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1325 : *
1326 : * @since GDAL 2.2
1327 : */
1328 47969 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1329 : int *pnXValid, int *pnYValid) const
1330 : {
1331 95937 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1332 95935 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1333 95931 : nYBlockOff < 0 || nBlockYSize == 0 ||
1334 47965 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1335 : {
1336 3 : return CE_Failure;
1337 : }
1338 :
1339 47966 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1340 47966 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1341 :
1342 47966 : *pnXValid = nBlockXSize;
1343 47966 : *pnYValid = nBlockYSize;
1344 :
1345 47966 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1346 : {
1347 46356 : *pnXValid = nRasterXSize - nXPixelOff;
1348 : }
1349 :
1350 47966 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1351 : {
1352 3435 : *pnYValid = nRasterYSize - nYPixelOff;
1353 : }
1354 :
1355 47966 : return CE_None;
1356 : }
1357 :
1358 : /************************************************************************/
1359 : /* GDALGetActualBlockSize() */
1360 : /************************************************************************/
1361 :
1362 : /**
1363 : * \brief Retrieve the actual block size for a given block offset.
1364 : *
1365 : * @see GDALRasterBand::GetActualBlockSize()
1366 : */
1367 :
1368 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1369 : int nYBlockOff, int *pnXValid,
1370 : int *pnYValid)
1371 :
1372 : {
1373 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1374 :
1375 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1376 : return (
1377 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1378 : }
1379 :
1380 : /************************************************************************/
1381 : /* GetSuggestedBlockAccessPattern() */
1382 : /************************************************************************/
1383 :
1384 : /**
1385 : * \brief Return the suggested/most efficient access pattern to blocks
1386 : * (for read operations).
1387 : *
1388 : * While all GDAL drivers have to expose a block size, not all can guarantee
1389 : * efficient random access (GSBAP_RANDOM) to any block.
1390 : * Some drivers for example decompress sequentially a compressed stream from
1391 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1392 : * case best performance will be achieved while reading blocks in that order.
1393 : * (accessing blocks in random access in such rasters typically causes the
1394 : * decoding to be re-initialized from the start if accessing blocks in
1395 : * a non-sequential order)
1396 : *
1397 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1398 : * returned by drivers that expose a somewhat artificial block size, because
1399 : * they can extract any part of a raster, but in a rather inefficient way.
1400 : *
1401 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1402 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1403 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1404 : * most efficient strategy is to read as many pixels as possible in the less
1405 : * RasterIO() operations.
1406 : *
1407 : * The return of this method is for example used to determine the swath size
1408 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1409 : *
1410 : * @since GDAL 3.6
1411 : */
1412 :
1413 : GDALSuggestedBlockAccessPattern
1414 2198 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1415 : {
1416 2198 : return GSBAP_UNKNOWN;
1417 : }
1418 :
1419 : /************************************************************************/
1420 : /* GetRasterDataType() */
1421 : /************************************************************************/
1422 :
1423 : /**
1424 : * \brief Fetch the pixel data type for this band.
1425 : *
1426 : * This method is the same as the C function GDALGetRasterDataType().
1427 : *
1428 : * @return the data type of pixels for this band.
1429 : */
1430 :
1431 7659680 : GDALDataType GDALRasterBand::GetRasterDataType() const
1432 :
1433 : {
1434 7659680 : return eDataType;
1435 : }
1436 :
1437 : /************************************************************************/
1438 : /* GDALGetRasterDataType() */
1439 : /************************************************************************/
1440 :
1441 : /**
1442 : * \brief Fetch the pixel data type for this band.
1443 : *
1444 : * @see GDALRasterBand::GetRasterDataType()
1445 : */
1446 :
1447 899692 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1448 :
1449 : {
1450 899692 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1451 :
1452 899692 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1453 899692 : return poBand->GetRasterDataType();
1454 : }
1455 :
1456 : /************************************************************************/
1457 : /* GetBlockSize() */
1458 : /************************************************************************/
1459 :
1460 : /**
1461 : * \brief Fetch the "natural" block size of this band.
1462 : *
1463 : * GDAL contains a concept of the natural block size of rasters so that
1464 : * applications can organized data access efficiently for some file formats.
1465 : * The natural block size is the block size that is most efficient for
1466 : * accessing the format. For many formats this is simple a whole scanline
1467 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1468 : *
1469 : * However, for tiled images this will typically be the tile size.
1470 : *
1471 : * Note that the X and Y block sizes don't have to divide the image size
1472 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1473 : * See ReadBlock() for an example of code dealing with these issues.
1474 : *
1475 : * This method is the same as the C function GDALGetBlockSize().
1476 : *
1477 : * @param pnXSize integer to put the X block size into or NULL.
1478 : *
1479 : * @param pnYSize integer to put the Y block size into or NULL.
1480 : */
1481 :
1482 5075260 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1483 :
1484 : {
1485 5075260 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1486 : {
1487 5055 : ReportError(CE_Failure, CPLE_AppDefined,
1488 5055 : "Invalid block dimension : %d * %d", nBlockXSize,
1489 5055 : nBlockYSize);
1490 0 : if (pnXSize != nullptr)
1491 0 : *pnXSize = 0;
1492 0 : if (pnYSize != nullptr)
1493 0 : *pnYSize = 0;
1494 : }
1495 : else
1496 : {
1497 5070200 : if (pnXSize != nullptr)
1498 5070070 : *pnXSize = nBlockXSize;
1499 5070200 : if (pnYSize != nullptr)
1500 5071950 : *pnYSize = nBlockYSize;
1501 : }
1502 5070200 : }
1503 :
1504 : /************************************************************************/
1505 : /* GDALGetBlockSize() */
1506 : /************************************************************************/
1507 :
1508 : /**
1509 : * \brief Fetch the "natural" block size of this band.
1510 : *
1511 : * @see GDALRasterBand::GetBlockSize()
1512 : */
1513 :
1514 40413 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1515 : int *pnYSize)
1516 :
1517 : {
1518 40413 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1519 :
1520 40413 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1521 40413 : poBand->GetBlockSize(pnXSize, pnYSize);
1522 : }
1523 :
1524 : /************************************************************************/
1525 : /* InitBlockInfo() */
1526 : /************************************************************************/
1527 :
1528 : //! @cond Doxygen_Suppress
1529 3335680 : int GDALRasterBand::InitBlockInfo()
1530 :
1531 : {
1532 3335680 : if (poBandBlockCache != nullptr)
1533 3301570 : return poBandBlockCache->IsInitOK();
1534 :
1535 : /* Do some validation of raster and block dimensions in case the driver */
1536 : /* would have neglected to do it itself */
1537 34109 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1538 : {
1539 66 : ReportError(CE_Failure, CPLE_AppDefined,
1540 : "Invalid block dimension : %d * %d", nBlockXSize,
1541 : nBlockYSize);
1542 0 : return FALSE;
1543 : }
1544 :
1545 34043 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1546 : {
1547 0 : ReportError(CE_Failure, CPLE_AppDefined,
1548 : "Invalid raster dimension : %d * %d", nRasterXSize,
1549 : nRasterYSize);
1550 0 : return FALSE;
1551 : }
1552 :
1553 34046 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1554 34077 : if (nDataTypeSize == 0)
1555 : {
1556 26 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1557 0 : return FALSE;
1558 : }
1559 :
1560 : #if SIZEOF_VOIDP == 4
1561 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1562 : {
1563 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1564 : * multiplication in other cases */
1565 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1566 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1567 : {
1568 : ReportError(CE_Failure, CPLE_NotSupported,
1569 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1570 : nBlockYSize);
1571 : return FALSE;
1572 : }
1573 : }
1574 : #endif
1575 :
1576 34051 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1577 34051 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1578 :
1579 : const char *pszBlockStrategy =
1580 34051 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1581 34114 : bool bUseArray = true;
1582 34114 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1583 : {
1584 34074 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1585 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1586 : {
1587 34055 : GUIntBig nBlockCount =
1588 34055 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1589 34055 : if (poDS != nullptr)
1590 33867 : nBlockCount *= poDS->GetRasterCount();
1591 34055 : bUseArray = (nBlockCount < 1024 * 1024);
1592 : }
1593 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1594 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1595 : {
1596 0 : bUseArray = false;
1597 34074 : }
1598 : }
1599 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1600 40 : bUseArray = false;
1601 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1602 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1603 : pszBlockStrategy);
1604 :
1605 34112 : if (bUseArray)
1606 34042 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1607 : else
1608 : {
1609 70 : if (nBand == 1)
1610 25 : CPLDebug("GDAL", "Use hashset band block cache");
1611 70 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1612 : }
1613 34102 : if (poBandBlockCache == nullptr)
1614 0 : return FALSE;
1615 34102 : return poBandBlockCache->Init();
1616 : }
1617 :
1618 : //! @endcond
1619 :
1620 : /************************************************************************/
1621 : /* FlushCache() */
1622 : /************************************************************************/
1623 :
1624 : /**
1625 : * \brief Flush raster data cache.
1626 : *
1627 : * This call will recover memory used to cache data blocks for this raster
1628 : * band, and ensure that new requests are referred to the underlying driver.
1629 : *
1630 : * This method is the same as the C function GDALFlushRasterCache().
1631 : *
1632 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1633 : * @return CE_None on success.
1634 : */
1635 :
1636 3873290 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1637 :
1638 : {
1639 3917960 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1640 44666 : poBandBlockCache)
1641 2102 : poBandBlockCache->DisableDirtyBlockWriting();
1642 :
1643 3873490 : CPLErr eGlobalErr = eFlushBlockErr;
1644 :
1645 3873490 : if (eFlushBlockErr != CE_None)
1646 : {
1647 0 : ReportError(
1648 : eFlushBlockErr, CPLE_AppDefined,
1649 : "An error occurred while writing a dirty block from FlushCache");
1650 0 : eFlushBlockErr = CE_None;
1651 : }
1652 :
1653 3873490 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1654 3722060 : return eGlobalErr;
1655 :
1656 151424 : return poBandBlockCache->FlushCache();
1657 : }
1658 :
1659 : /************************************************************************/
1660 : /* GDALFlushRasterCache() */
1661 : /************************************************************************/
1662 :
1663 : /**
1664 : * \brief Flush raster data cache.
1665 : *
1666 : * @see GDALRasterBand::FlushCache()
1667 : */
1668 :
1669 130 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1670 :
1671 : {
1672 130 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1673 :
1674 130 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1675 : }
1676 :
1677 : /************************************************************************/
1678 : /* DropCache() */
1679 : /************************************************************************/
1680 :
1681 : /**
1682 : * \brief Drop raster data cache : data in cache will be lost.
1683 : *
1684 : * This call will recover memory used to cache data blocks for this raster
1685 : * band, and ensure that new requests are referred to the underlying driver.
1686 : *
1687 : * This method is the same as the C function GDALDropRasterCache().
1688 : *
1689 : * @return CE_None on success.
1690 : * @since 3.9
1691 : */
1692 :
1693 1 : CPLErr GDALRasterBand::DropCache()
1694 :
1695 : {
1696 1 : CPLErr result = CE_None;
1697 :
1698 1 : if (poBandBlockCache)
1699 1 : poBandBlockCache->DisableDirtyBlockWriting();
1700 :
1701 1 : CPLErr eGlobalErr = eFlushBlockErr;
1702 :
1703 1 : if (eFlushBlockErr != CE_None)
1704 : {
1705 0 : ReportError(
1706 : eFlushBlockErr, CPLE_AppDefined,
1707 : "An error occurred while writing a dirty block from DropCache");
1708 0 : eFlushBlockErr = CE_None;
1709 : }
1710 :
1711 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1712 0 : result = eGlobalErr;
1713 : else
1714 1 : result = poBandBlockCache->FlushCache();
1715 :
1716 1 : if (poBandBlockCache)
1717 1 : poBandBlockCache->EnableDirtyBlockWriting();
1718 :
1719 1 : return result;
1720 : }
1721 :
1722 : /************************************************************************/
1723 : /* GDALDropRasterCache() */
1724 : /************************************************************************/
1725 :
1726 : /**
1727 : * \brief Drop raster data cache.
1728 : *
1729 : * @see GDALRasterBand::DropCache()
1730 : * @since 3.9
1731 : */
1732 :
1733 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1734 :
1735 : {
1736 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1737 :
1738 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1739 : }
1740 :
1741 : /************************************************************************/
1742 : /* UnreferenceBlock() */
1743 : /* */
1744 : /* Unreference the block from our array of blocks */
1745 : /* This method should only be called by */
1746 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1747 : /* the block cache mutex) */
1748 : /************************************************************************/
1749 :
1750 29617 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1751 : {
1752 : #ifdef notdef
1753 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1754 : {
1755 : if (poBandBlockCache == nullptr)
1756 : printf("poBandBlockCache == NULL\n"); /*ok*/
1757 : else
1758 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1759 : printf("caller = %s\n", pszCaller); /*ok*/
1760 : printf("GDALRasterBand: %p\n", this); /*ok*/
1761 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1762 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1763 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1764 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1765 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1766 : poBlock->DumpBlock();
1767 : if (GetDataset() != nullptr)
1768 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1769 : GDALRasterBlock::Verify();
1770 : abort();
1771 : }
1772 : #endif
1773 29617 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1774 29617 : return poBandBlockCache->UnreferenceBlock(poBlock);
1775 : }
1776 :
1777 : /************************************************************************/
1778 : /* AddBlockToFreeList() */
1779 : /* */
1780 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1781 : /* finished with a block about to be free'd, they pass it to that */
1782 : /* method. */
1783 : /************************************************************************/
1784 :
1785 : //! @cond Doxygen_Suppress
1786 29617 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1787 : {
1788 29617 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1789 29617 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1790 : }
1791 :
1792 : //! @endcond
1793 :
1794 : /************************************************************************/
1795 : /* FlushBlock() */
1796 : /************************************************************************/
1797 :
1798 : /** Flush a block out of the block cache.
1799 : * @param nXBlockOff block x offset
1800 : * @param nYBlockOff blocky offset
1801 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1802 : * @return CE_None in case of success, an error code otherwise.
1803 : */
1804 2302 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1805 : int bWriteDirtyBlock)
1806 :
1807 : {
1808 2302 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1809 0 : return (CE_Failure);
1810 :
1811 : /* -------------------------------------------------------------------- */
1812 : /* Validate the request */
1813 : /* -------------------------------------------------------------------- */
1814 2302 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1815 : {
1816 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1817 : "Illegal nBlockXOff value (%d) in "
1818 : "GDALRasterBand::FlushBlock()\n",
1819 : nXBlockOff);
1820 :
1821 0 : return (CE_Failure);
1822 : }
1823 :
1824 2302 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1825 : {
1826 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1827 : "Illegal nBlockYOff value (%d) in "
1828 : "GDALRasterBand::FlushBlock()\n",
1829 : nYBlockOff);
1830 :
1831 0 : return (CE_Failure);
1832 : }
1833 :
1834 2302 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1835 2302 : bWriteDirtyBlock);
1836 : }
1837 :
1838 : /************************************************************************/
1839 : /* TryGetLockedBlockRef() */
1840 : /************************************************************************/
1841 :
1842 : /**
1843 : * \brief Try fetching block ref.
1844 : *
1845 : * This method will returned the requested block (locked) if it is already
1846 : * in the block cache for the layer. If not, nullptr is returned.
1847 : *
1848 : * If a non-NULL value is returned, then a lock for the block will have been
1849 : * acquired on behalf of the caller. It is absolutely imperative that the
1850 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1851 : * severe problems may result.
1852 : *
1853 : * @param nXBlockOff the horizontal block offset, with zero indicating
1854 : * the left most block, 1 the next block and so forth.
1855 : *
1856 : * @param nYBlockOff the vertical block offset, with zero indicating
1857 : * the top most block, 1 the next block and so forth.
1858 : *
1859 : * @return NULL if block not available, or locked block pointer.
1860 : */
1861 :
1862 9991420 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1863 : int nYBlockOff)
1864 :
1865 : {
1866 9991420 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1867 66499 : return nullptr;
1868 :
1869 : /* -------------------------------------------------------------------- */
1870 : /* Validate the request */
1871 : /* -------------------------------------------------------------------- */
1872 9925520 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1873 : {
1874 1893 : ReportError(CE_Failure, CPLE_IllegalArg,
1875 : "Illegal nBlockXOff value (%d) in "
1876 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1877 : nXBlockOff);
1878 :
1879 0 : return (nullptr);
1880 : }
1881 :
1882 9923630 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1883 : {
1884 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1885 : "Illegal nBlockYOff value (%d) in "
1886 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1887 : nYBlockOff);
1888 :
1889 0 : return (nullptr);
1890 : }
1891 :
1892 9923740 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1893 : }
1894 :
1895 : /************************************************************************/
1896 : /* GetLockedBlockRef() */
1897 : /************************************************************************/
1898 :
1899 : /**
1900 : * \brief Fetch a pointer to an internally cached raster block.
1901 : *
1902 : * This method will returned the requested block (locked) if it is already
1903 : * in the block cache for the layer. If not, the block will be read from
1904 : * the driver, and placed in the layer block cached, then returned. If an
1905 : * error occurs reading the block from the driver, a NULL value will be
1906 : * returned.
1907 : *
1908 : * If a non-NULL value is returned, then a lock for the block will have been
1909 : * acquired on behalf of the caller. It is absolutely imperative that the
1910 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1911 : * severe problems may result.
1912 : *
1913 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1914 : * enable caching.
1915 : *
1916 : * @param nXBlockOff the horizontal block offset, with zero indicating
1917 : * the left most block, 1 the next block and so forth.
1918 : *
1919 : * @param nYBlockOff the vertical block offset, with zero indicating
1920 : * the top most block, 1 the next block and so forth.
1921 : *
1922 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1923 : * but not actually read from the source. This is useful when it will just
1924 : * be completely set and written back.
1925 : *
1926 : * @return pointer to the block object, or NULL on failure.
1927 : */
1928 :
1929 9788520 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1930 : int nYBlockOff,
1931 : int bJustInitialize)
1932 :
1933 : {
1934 : /* -------------------------------------------------------------------- */
1935 : /* Try and fetch from cache. */
1936 : /* -------------------------------------------------------------------- */
1937 9788520 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1938 :
1939 : /* -------------------------------------------------------------------- */
1940 : /* If we didn't find it in our memory cache, instantiate a */
1941 : /* block (potentially load from disk) and "adopt" it into the */
1942 : /* cache. */
1943 : /* -------------------------------------------------------------------- */
1944 9791930 : if (poBlock == nullptr)
1945 : {
1946 3158810 : if (!InitBlockInfo())
1947 0 : return (nullptr);
1948 :
1949 : /* --------------------------------------------------------------------
1950 : */
1951 : /* Validate the request */
1952 : /* --------------------------------------------------------------------
1953 : */
1954 3158840 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1955 : {
1956 44 : ReportError(CE_Failure, CPLE_IllegalArg,
1957 : "Illegal nBlockXOff value (%d) in "
1958 : "GDALRasterBand::GetLockedBlockRef()\n",
1959 : nXBlockOff);
1960 :
1961 0 : return (nullptr);
1962 : }
1963 :
1964 3158800 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1965 : {
1966 46 : ReportError(CE_Failure, CPLE_IllegalArg,
1967 : "Illegal nBlockYOff value (%d) in "
1968 : "GDALRasterBand::GetLockedBlockRef()\n",
1969 : nYBlockOff);
1970 :
1971 0 : return (nullptr);
1972 : }
1973 :
1974 3158750 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1975 3158860 : if (poBlock == nullptr)
1976 0 : return nullptr;
1977 :
1978 3158860 : poBlock->AddLock();
1979 :
1980 : /* We need to temporarily drop the read-write lock in the following */
1981 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
1982 : */
1983 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
1984 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
1985 : */
1986 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
1987 : */
1988 : /* called and attempt at taking the lock on T2 (already taken).
1989 : * Similarly */
1990 : /* for T2 with D1, hence a deadlock situation (#6163) */
1991 : /* But this may open the door to other problems... */
1992 3158860 : if (poDS)
1993 3158140 : poDS->TemporarilyDropReadWriteLock();
1994 : /* allocate data space */
1995 3158840 : CPLErr eErr = poBlock->Internalize();
1996 3158960 : if (poDS)
1997 3158200 : poDS->ReacquireReadWriteLock();
1998 3158930 : if (eErr != CE_None)
1999 : {
2000 0 : poBlock->DropLock();
2001 0 : delete poBlock;
2002 0 : return nullptr;
2003 : }
2004 :
2005 3158930 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2006 : {
2007 0 : poBlock->DropLock();
2008 0 : delete poBlock;
2009 0 : return nullptr;
2010 : }
2011 :
2012 3158900 : if (!bJustInitialize)
2013 : {
2014 2796270 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2015 2796240 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2016 2796220 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2017 2796270 : if (bCallLeaveReadWrite)
2018 130282 : LeaveReadWrite();
2019 2796250 : if (eErr != CE_None)
2020 : {
2021 1152 : poBlock->DropLock();
2022 1152 : FlushBlock(nXBlockOff, nYBlockOff);
2023 1152 : ReportError(CE_Failure, CPLE_AppDefined,
2024 : "IReadBlock failed at X offset %d, Y offset %d%s",
2025 : nXBlockOff, nYBlockOff,
2026 1152 : (nErrorCounter != CPLGetErrorCounter())
2027 1150 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2028 : : "");
2029 1152 : return nullptr;
2030 : }
2031 :
2032 2795100 : nBlockReads++;
2033 2795100 : if (static_cast<GIntBig>(nBlockReads) ==
2034 2795100 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2035 214 : 1 &&
2036 214 : nBand == 1 && poDS != nullptr)
2037 : {
2038 151 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2039 151 : poDS->GetDescription());
2040 : }
2041 : }
2042 : }
2043 :
2044 9790870 : return poBlock;
2045 : }
2046 :
2047 : /************************************************************************/
2048 : /* Fill() */
2049 : /************************************************************************/
2050 :
2051 : /**
2052 : * \brief Fill this band with a constant value.
2053 : *
2054 : * GDAL makes no guarantees
2055 : * about what values pixels in newly created files are set to, so this
2056 : * method can be used to clear a band to a specified "default" value.
2057 : * The fill value is passed in as a double but this will be converted
2058 : * to the underlying type before writing to the file. An optional
2059 : * second argument allows the imaginary component of a complex
2060 : * constant value to be specified.
2061 : *
2062 : * This method is the same as the C function GDALFillRaster().
2063 : *
2064 : * @param dfRealValue Real component of fill value
2065 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2066 : *
2067 : * @return CE_Failure if the write fails, otherwise CE_None
2068 : */
2069 169236 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2070 : {
2071 :
2072 : // General approach is to construct a source block of the file's
2073 : // native type containing the appropriate value and then copy this
2074 : // to each block in the image via the RasterBlock cache. Using
2075 : // the cache means we avoid file I/O if it is not necessary, at the
2076 : // expense of some extra memcpy's (since we write to the
2077 : // RasterBlock cache, which is then at some point written to the
2078 : // underlying file, rather than simply directly to the underlying
2079 : // file.)
2080 :
2081 : // Check we can write to the file.
2082 169236 : if (eAccess == GA_ReadOnly)
2083 : {
2084 2 : ReportError(CE_Failure, CPLE_NoWriteAccess,
2085 : "Attempt to write to read only dataset in "
2086 : "GDALRasterBand::Fill().");
2087 2 : return CE_Failure;
2088 : }
2089 :
2090 : // Make sure block parameters are set.
2091 169234 : if (!InitBlockInfo())
2092 0 : return CE_Failure;
2093 :
2094 : // Allocate the source block.
2095 169234 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2096 169234 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2097 169234 : auto blockByteSize = blockSize * elementSize;
2098 : unsigned char *srcBlock =
2099 169234 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2100 169234 : if (srcBlock == nullptr)
2101 : {
2102 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2103 : "GDALRasterBand::Fill(): Out of memory "
2104 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2105 : static_cast<GUIntBig>(blockByteSize));
2106 0 : return CE_Failure;
2107 : }
2108 :
2109 : // Initialize the source block.
2110 169234 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2111 169234 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2112 : elementSize, blockSize);
2113 :
2114 169234 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2115 :
2116 : // Write block to block cache
2117 637463 : for (int j = 0; j < nBlocksPerColumn; ++j)
2118 : {
2119 1230790 : for (int i = 0; i < nBlocksPerRow; ++i)
2120 : {
2121 762562 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2122 762562 : if (destBlock == nullptr)
2123 : {
2124 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2125 : "GDALRasterBand::Fill(): Error "
2126 : "while retrieving cache block.");
2127 0 : VSIFree(srcBlock);
2128 0 : return CE_Failure;
2129 : }
2130 762562 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2131 762562 : destBlock->MarkDirty();
2132 762562 : destBlock->DropLock();
2133 : }
2134 : }
2135 :
2136 169234 : if (bCallLeaveReadWrite)
2137 168757 : LeaveReadWrite();
2138 :
2139 : // Free up the source block
2140 169234 : VSIFree(srcBlock);
2141 :
2142 169234 : return CE_None;
2143 : }
2144 :
2145 : /************************************************************************/
2146 : /* GDALFillRaster() */
2147 : /************************************************************************/
2148 :
2149 : /**
2150 : * \brief Fill this band with a constant value.
2151 : *
2152 : * @see GDALRasterBand::Fill()
2153 : */
2154 169202 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2155 : double dfImaginaryValue)
2156 : {
2157 169202 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2158 :
2159 169202 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2160 169202 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2161 : }
2162 :
2163 : /************************************************************************/
2164 : /* GetAccess() */
2165 : /************************************************************************/
2166 :
2167 : /**
2168 : * \brief Find out if we have update permission for this band.
2169 : *
2170 : * This method is the same as the C function GDALGetRasterAccess().
2171 : *
2172 : * @return Either GA_Update or GA_ReadOnly.
2173 : */
2174 :
2175 2524 : GDALAccess GDALRasterBand::GetAccess()
2176 :
2177 : {
2178 2524 : return eAccess;
2179 : }
2180 :
2181 : /************************************************************************/
2182 : /* GDALGetRasterAccess() */
2183 : /************************************************************************/
2184 :
2185 : /**
2186 : * \brief Find out if we have update permission for this band.
2187 : *
2188 : * @see GDALRasterBand::GetAccess()
2189 : */
2190 :
2191 1878 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2192 :
2193 : {
2194 1878 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2195 :
2196 1878 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2197 1878 : return poBand->GetAccess();
2198 : }
2199 :
2200 : /************************************************************************/
2201 : /* GetCategoryNames() */
2202 : /************************************************************************/
2203 :
2204 : /**
2205 : * \brief Fetch the list of category names for this raster.
2206 : *
2207 : * The return list is a "StringList" in the sense of the CPL functions.
2208 : * That is a NULL terminated array of strings. Raster values without
2209 : * associated names will have an empty string in the returned list. The
2210 : * first entry in the list is for raster values of zero, and so on.
2211 : *
2212 : * The returned stringlist should not be altered or freed by the application.
2213 : * It may change on the next GDAL call, so please copy it if it is needed
2214 : * for any period of time.
2215 : *
2216 : * This method is the same as the C function GDALGetRasterCategoryNames().
2217 : *
2218 : * @return list of names, or NULL if none.
2219 : */
2220 :
2221 234 : char **GDALRasterBand::GetCategoryNames()
2222 :
2223 : {
2224 234 : return nullptr;
2225 : }
2226 :
2227 : /************************************************************************/
2228 : /* GDALGetRasterCategoryNames() */
2229 : /************************************************************************/
2230 :
2231 : /**
2232 : * \brief Fetch the list of category names for this raster.
2233 : *
2234 : * @see GDALRasterBand::GetCategoryNames()
2235 : */
2236 :
2237 175 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2238 :
2239 : {
2240 175 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2241 :
2242 175 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2243 175 : return poBand->GetCategoryNames();
2244 : }
2245 :
2246 : /************************************************************************/
2247 : /* SetCategoryNames() */
2248 : /************************************************************************/
2249 :
2250 : /**
2251 : * \fn GDALRasterBand::SetCategoryNames(char**)
2252 : * \brief Set the category names for this band.
2253 : *
2254 : * See the GetCategoryNames() method for more on the interpretation of
2255 : * category names.
2256 : *
2257 : * This method is the same as the C function GDALSetRasterCategoryNames().
2258 : *
2259 : * @param papszNames the NULL terminated StringList of category names. May
2260 : * be NULL to just clear the existing list.
2261 : *
2262 : * @return CE_None on success of CE_Failure on failure. If unsupported
2263 : * by the driver CE_Failure is returned, but no error message is reported.
2264 : */
2265 :
2266 : /**/
2267 : /**/
2268 :
2269 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2270 : {
2271 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2272 0 : ReportError(CE_Failure, CPLE_NotSupported,
2273 : "SetCategoryNames() not supported for this dataset.");
2274 :
2275 0 : return CE_Failure;
2276 : }
2277 :
2278 : /************************************************************************/
2279 : /* GDALSetCategoryNames() */
2280 : /************************************************************************/
2281 :
2282 : /**
2283 : * \brief Set the category names for this band.
2284 : *
2285 : * @see GDALRasterBand::SetCategoryNames()
2286 : */
2287 :
2288 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2289 : CSLConstList papszNames)
2290 :
2291 : {
2292 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2293 :
2294 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2295 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2296 : }
2297 :
2298 : /************************************************************************/
2299 : /* GetNoDataValue() */
2300 : /************************************************************************/
2301 :
2302 : /**
2303 : * \brief Fetch the no data value for this band.
2304 : *
2305 : * If there is no out of data value, an out of range value will generally
2306 : * be returned. The no data value for a band is generally a special marker
2307 : * value used to mark pixels that are not valid data. Such pixels should
2308 : * generally not be displayed, nor contribute to analysis operations.
2309 : *
2310 : * The no data value returned is 'raw', meaning that it has no offset and
2311 : * scale applied.
2312 : *
2313 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2314 : * lossy if the nodata value cannot exactly been represented by a double.
2315 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2316 : *
2317 : * This method is the same as the C function GDALGetRasterNoDataValue().
2318 : *
2319 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2320 : * is actually associated with this layer. May be NULL (default).
2321 : *
2322 : * @return the nodata value for this band.
2323 : */
2324 :
2325 31410 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2326 :
2327 : {
2328 31410 : if (pbSuccess != nullptr)
2329 31410 : *pbSuccess = FALSE;
2330 :
2331 31410 : return -1e10;
2332 : }
2333 :
2334 : /************************************************************************/
2335 : /* GDALGetRasterNoDataValue() */
2336 : /************************************************************************/
2337 :
2338 : /**
2339 : * \brief Fetch the no data value for this band.
2340 : *
2341 : * @see GDALRasterBand::GetNoDataValue()
2342 : */
2343 :
2344 413821 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2345 : int *pbSuccess)
2346 :
2347 : {
2348 413821 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2349 :
2350 413821 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2351 413821 : return poBand->GetNoDataValue(pbSuccess);
2352 : }
2353 :
2354 : /************************************************************************/
2355 : /* GetNoDataValueAsInt64() */
2356 : /************************************************************************/
2357 :
2358 : /**
2359 : * \brief Fetch the no data value for this band.
2360 : *
2361 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2362 : *
2363 : * If there is no out of data value, an out of range value will generally
2364 : * be returned. The no data value for a band is generally a special marker
2365 : * value used to mark pixels that are not valid data. Such pixels should
2366 : * generally not be displayed, nor contribute to analysis operations.
2367 : *
2368 : * The no data value returned is 'raw', meaning that it has no offset and
2369 : * scale applied.
2370 : *
2371 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2372 : *
2373 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2374 : * is actually associated with this layer. May be NULL (default).
2375 : *
2376 : * @return the nodata value for this band.
2377 : *
2378 : * @since GDAL 3.5
2379 : */
2380 :
2381 4 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2382 :
2383 : {
2384 4 : if (pbSuccess != nullptr)
2385 4 : *pbSuccess = FALSE;
2386 :
2387 4 : return std::numeric_limits<int64_t>::min();
2388 : }
2389 :
2390 : /************************************************************************/
2391 : /* GDALGetRasterNoDataValueAsInt64() */
2392 : /************************************************************************/
2393 :
2394 : /**
2395 : * \brief Fetch the no data value for this band.
2396 : *
2397 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2398 : *
2399 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2400 : *
2401 : * @since GDAL 3.5
2402 : */
2403 :
2404 23 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2405 : int *pbSuccess)
2406 :
2407 : {
2408 23 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2409 : std::numeric_limits<int64_t>::min());
2410 :
2411 23 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2412 23 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2413 : }
2414 :
2415 : /************************************************************************/
2416 : /* GetNoDataValueAsUInt64() */
2417 : /************************************************************************/
2418 :
2419 : /**
2420 : * \brief Fetch the no data value for this band.
2421 : *
2422 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2423 : *
2424 : * If there is no out of data value, an out of range value will generally
2425 : * be returned. The no data value for a band is generally a special marker
2426 : * value used to mark pixels that are not valid data. Such pixels should
2427 : * generally not be displayed, nor contribute to analysis operations.
2428 : *
2429 : * The no data value returned is 'raw', meaning that it has no offset and
2430 : * scale applied.
2431 : *
2432 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2433 : *
2434 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2435 : * is actually associated with this layer. May be NULL (default).
2436 : *
2437 : * @return the nodata value for this band.
2438 : *
2439 : * @since GDAL 3.5
2440 : */
2441 :
2442 3 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2443 :
2444 : {
2445 3 : if (pbSuccess != nullptr)
2446 3 : *pbSuccess = FALSE;
2447 :
2448 3 : return std::numeric_limits<uint64_t>::max();
2449 : }
2450 :
2451 : /************************************************************************/
2452 : /* GDALGetRasterNoDataValueAsUInt64() */
2453 : /************************************************************************/
2454 :
2455 : /**
2456 : * \brief Fetch the no data value for this band.
2457 : *
2458 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2459 : *
2460 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2461 : *
2462 : * @since GDAL 3.5
2463 : */
2464 :
2465 18 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2466 : int *pbSuccess)
2467 :
2468 : {
2469 18 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2470 : std::numeric_limits<uint64_t>::max());
2471 :
2472 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2473 18 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2474 : }
2475 :
2476 : /************************************************************************/
2477 : /* SetNoDataValue() */
2478 : /************************************************************************/
2479 :
2480 : /**
2481 : * \fn GDALRasterBand::SetNoDataValue(double)
2482 : * \brief Set the no data value for this band.
2483 : *
2484 : * Depending on drivers, changing the no data value may or may not have an
2485 : * effect on the pixel values of a raster that has just been created. It is
2486 : * thus advised to explicitly called Fill() if the intent is to initialize
2487 : * the raster to the nodata value.
2488 : * In any case, changing an existing no data value, when one already exists and
2489 : * the dataset exists or has been initialized, has no effect on the pixel whose
2490 : * value matched the previous nodata value.
2491 : *
2492 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2493 : * be represented by a double, use SetNoDataValueAsInt64() or
2494 : * SetNoDataValueAsUInt64() instead.
2495 : *
2496 : * To clear the nodata value, use DeleteNoDataValue().
2497 : *
2498 : * This method is the same as the C function GDALSetRasterNoDataValue().
2499 : *
2500 : * @param dfNoData the value to set.
2501 : *
2502 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2503 : * by the driver, CE_Failure is returned by no error message will have
2504 : * been emitted.
2505 : */
2506 :
2507 : /**/
2508 : /**/
2509 :
2510 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2511 :
2512 : {
2513 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2514 0 : ReportError(CE_Failure, CPLE_NotSupported,
2515 : "SetNoDataValue() not supported for this dataset.");
2516 :
2517 0 : return CE_Failure;
2518 : }
2519 :
2520 : /************************************************************************/
2521 : /* GDALSetRasterNoDataValue() */
2522 : /************************************************************************/
2523 :
2524 : /**
2525 : * \brief Set the no data value for this band.
2526 : *
2527 : * Depending on drivers, changing the no data value may or may not have an
2528 : * effect on the pixel values of a raster that has just been created. It is
2529 : * thus advised to explicitly called Fill() if the intent is to initialize
2530 : * the raster to the nodata value.
2531 : * In any case, changing an existing no data value, when one already exists and
2532 : * the dataset exists or has been initialized, has no effect on the pixel whose
2533 : * value matched the previous nodata value.
2534 : *
2535 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2536 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2537 : * GDALSetRasterNoDataValueAsUInt64() instead.
2538 : *
2539 : * @see GDALRasterBand::SetNoDataValue()
2540 : */
2541 :
2542 712 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2543 : double dfValue)
2544 :
2545 : {
2546 712 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2547 :
2548 712 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2549 712 : return poBand->SetNoDataValue(dfValue);
2550 : }
2551 :
2552 : /************************************************************************/
2553 : /* SetNoDataValueAsInt64() */
2554 : /************************************************************************/
2555 :
2556 : /**
2557 : * \brief Set the no data value for this band.
2558 : *
2559 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2560 : *
2561 : * Depending on drivers, changing the no data value may or may not have an
2562 : * effect on the pixel values of a raster that has just been created. It is
2563 : * thus advised to explicitly called Fill() if the intent is to initialize
2564 : * the raster to the nodata value.
2565 : * In ay case, changing an existing no data value, when one already exists and
2566 : * the dataset exists or has been initialized, has no effect on the pixel whose
2567 : * value matched the previous nodata value.
2568 : *
2569 : * To clear the nodata value, use DeleteNoDataValue().
2570 : *
2571 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2572 : *
2573 : * @param nNoDataValue the value to set.
2574 : *
2575 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2576 : * by the driver, CE_Failure is returned by no error message will have
2577 : * been emitted.
2578 : *
2579 : * @since GDAL 3.5
2580 : */
2581 :
2582 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2583 :
2584 : {
2585 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2586 0 : ReportError(CE_Failure, CPLE_NotSupported,
2587 : "SetNoDataValueAsInt64() not supported for this dataset.");
2588 :
2589 0 : return CE_Failure;
2590 : }
2591 :
2592 : /************************************************************************/
2593 : /* GDALSetRasterNoDataValueAsInt64() */
2594 : /************************************************************************/
2595 :
2596 : /**
2597 : * \brief Set the no data value for this band.
2598 : *
2599 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2600 : *
2601 : * Depending on drivers, changing the no data value may or may not have an
2602 : * effect on the pixel values of a raster that has just been created. It is
2603 : * thus advised to explicitly called Fill() if the intent is to initialize
2604 : * the raster to the nodata value.
2605 : * In ay case, changing an existing no data value, when one already exists and
2606 : * the dataset exists or has been initialized, has no effect on the pixel whose
2607 : * value matched the previous nodata value.
2608 : *
2609 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2610 : *
2611 : * @since GDAL 3.5
2612 : */
2613 :
2614 18 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2615 : int64_t nValue)
2616 :
2617 : {
2618 18 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2619 :
2620 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2621 18 : return poBand->SetNoDataValueAsInt64(nValue);
2622 : }
2623 :
2624 : /************************************************************************/
2625 : /* SetNoDataValueAsUInt64() */
2626 : /************************************************************************/
2627 :
2628 : /**
2629 : * \brief Set the no data value for this band.
2630 : *
2631 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2632 : *
2633 : * Depending on drivers, changing the no data value may or may not have an
2634 : * effect on the pixel values of a raster that has just been created. It is
2635 : * thus advised to explicitly called Fill() if the intent is to initialize
2636 : * the raster to the nodata value.
2637 : * In ay case, changing an existing no data value, when one already exists and
2638 : * the dataset exists or has been initialized, has no effect on the pixel whose
2639 : * value matched the previous nodata value.
2640 : *
2641 : * To clear the nodata value, use DeleteNoDataValue().
2642 : *
2643 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2644 : *
2645 : * @param nNoDataValue the value to set.
2646 : *
2647 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2648 : * by the driver, CE_Failure is returned by no error message will have
2649 : * been emitted.
2650 : *
2651 : * @since GDAL 3.5
2652 : */
2653 :
2654 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2655 :
2656 : {
2657 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2658 0 : ReportError(CE_Failure, CPLE_NotSupported,
2659 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2660 :
2661 0 : return CE_Failure;
2662 : }
2663 :
2664 : /************************************************************************/
2665 : /* GDALSetRasterNoDataValueAsUInt64() */
2666 : /************************************************************************/
2667 :
2668 : /**
2669 : * \brief Set the no data value for this band.
2670 : *
2671 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2672 : *
2673 : * Depending on drivers, changing the no data value may or may not have an
2674 : * effect on the pixel values of a raster that has just been created. It is
2675 : * thus advised to explicitly called Fill() if the intent is to initialize
2676 : * the raster to the nodata value.
2677 : * In ay case, changing an existing no data value, when one already exists and
2678 : * the dataset exists or has been initialized, has no effect on the pixel whose
2679 : * value matched the previous nodata value.
2680 : *
2681 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2682 : *
2683 : * @since GDAL 3.5
2684 : */
2685 :
2686 16 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2687 : uint64_t nValue)
2688 :
2689 : {
2690 16 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2691 :
2692 16 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2693 16 : return poBand->SetNoDataValueAsUInt64(nValue);
2694 : }
2695 :
2696 : /************************************************************************/
2697 : /* DeleteNoDataValue() */
2698 : /************************************************************************/
2699 :
2700 : /**
2701 : * \brief Remove the no data value for this band.
2702 : *
2703 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2704 : *
2705 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2706 : * by the driver, CE_Failure is returned by no error message will have
2707 : * been emitted.
2708 : *
2709 : * @since GDAL 2.1
2710 : */
2711 :
2712 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2713 :
2714 : {
2715 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2716 0 : ReportError(CE_Failure, CPLE_NotSupported,
2717 : "DeleteNoDataValue() not supported for this dataset.");
2718 :
2719 0 : return CE_Failure;
2720 : }
2721 :
2722 : /************************************************************************/
2723 : /* GDALDeleteRasterNoDataValue() */
2724 : /************************************************************************/
2725 :
2726 : /**
2727 : * \brief Remove the no data value for this band.
2728 : *
2729 : * @see GDALRasterBand::DeleteNoDataValue()
2730 : *
2731 : * @since GDAL 2.1
2732 : */
2733 :
2734 41 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2735 :
2736 : {
2737 41 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2738 :
2739 41 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2740 41 : return poBand->DeleteNoDataValue();
2741 : }
2742 :
2743 : /************************************************************************/
2744 : /* GetMaximum() */
2745 : /************************************************************************/
2746 :
2747 : /**
2748 : * \brief Fetch the maximum value for this band.
2749 : *
2750 : * For file formats that don't know this intrinsically, the maximum supported
2751 : * value for the data type will generally be returned.
2752 : *
2753 : * This method is the same as the C function GDALGetRasterMaximum().
2754 : *
2755 : * @param pbSuccess pointer to a boolean to use to indicate if the
2756 : * returned value is a tight maximum or not. May be NULL (default).
2757 : *
2758 : * @return the maximum raster value (excluding no data pixels)
2759 : */
2760 :
2761 492 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2762 :
2763 : {
2764 492 : const char *pszValue = nullptr;
2765 :
2766 492 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2767 : {
2768 46 : if (pbSuccess != nullptr)
2769 41 : *pbSuccess = TRUE;
2770 :
2771 46 : return CPLAtofM(pszValue);
2772 : }
2773 :
2774 446 : if (pbSuccess != nullptr)
2775 414 : *pbSuccess = FALSE;
2776 :
2777 446 : switch (eDataType)
2778 : {
2779 317 : case GDT_Byte:
2780 : {
2781 317 : EnablePixelTypeSignedByteWarning(false);
2782 : const char *pszPixelType =
2783 317 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2784 317 : EnablePixelTypeSignedByteWarning(true);
2785 317 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2786 0 : return 127;
2787 :
2788 317 : return 255;
2789 : }
2790 :
2791 0 : case GDT_Int8:
2792 0 : return 127;
2793 :
2794 19 : case GDT_UInt16:
2795 19 : return 65535;
2796 :
2797 24 : case GDT_Int16:
2798 : case GDT_CInt16:
2799 24 : return 32767;
2800 :
2801 17 : case GDT_Int32:
2802 : case GDT_CInt32:
2803 17 : return 2147483647.0;
2804 :
2805 13 : case GDT_UInt32:
2806 13 : return 4294967295.0;
2807 :
2808 0 : case GDT_Int64:
2809 0 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2810 :
2811 0 : case GDT_UInt64:
2812 0 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2813 :
2814 0 : case GDT_Float16:
2815 : case GDT_CFloat16:
2816 0 : return 65504.0;
2817 :
2818 32 : case GDT_Float32:
2819 : case GDT_CFloat32:
2820 32 : return 4294967295.0; // Not actually accurate.
2821 :
2822 24 : case GDT_Float64:
2823 : case GDT_CFloat64:
2824 24 : return 4294967295.0; // Not actually accurate.
2825 :
2826 0 : case GDT_Unknown:
2827 : case GDT_TypeCount:
2828 0 : break;
2829 : }
2830 0 : return 4294967295.0; // Not actually accurate.
2831 : }
2832 :
2833 : /************************************************************************/
2834 : /* GDALGetRasterMaximum() */
2835 : /************************************************************************/
2836 :
2837 : /**
2838 : * \brief Fetch the maximum value for this band.
2839 : *
2840 : * @see GDALRasterBand::GetMaximum()
2841 : */
2842 :
2843 248 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2844 :
2845 : {
2846 248 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2847 :
2848 248 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2849 248 : return poBand->GetMaximum(pbSuccess);
2850 : }
2851 :
2852 : /************************************************************************/
2853 : /* GetMinimum() */
2854 : /************************************************************************/
2855 :
2856 : /**
2857 : * \brief Fetch the minimum value for this band.
2858 : *
2859 : * For file formats that don't know this intrinsically, the minimum supported
2860 : * value for the data type will generally be returned.
2861 : *
2862 : * This method is the same as the C function GDALGetRasterMinimum().
2863 : *
2864 : * @param pbSuccess pointer to a boolean to use to indicate if the
2865 : * returned value is a tight minimum or not. May be NULL (default).
2866 : *
2867 : * @return the minimum raster value (excluding no data pixels)
2868 : */
2869 :
2870 500 : double GDALRasterBand::GetMinimum(int *pbSuccess)
2871 :
2872 : {
2873 500 : const char *pszValue = nullptr;
2874 :
2875 500 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
2876 : {
2877 51 : if (pbSuccess != nullptr)
2878 46 : *pbSuccess = TRUE;
2879 :
2880 51 : return CPLAtofM(pszValue);
2881 : }
2882 :
2883 449 : if (pbSuccess != nullptr)
2884 417 : *pbSuccess = FALSE;
2885 :
2886 449 : switch (eDataType)
2887 : {
2888 320 : case GDT_Byte:
2889 : {
2890 320 : EnablePixelTypeSignedByteWarning(false);
2891 : const char *pszPixelType =
2892 320 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2893 320 : EnablePixelTypeSignedByteWarning(true);
2894 320 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2895 0 : return -128;
2896 :
2897 320 : return 0;
2898 : }
2899 :
2900 0 : case GDT_Int8:
2901 0 : return -128;
2902 : break;
2903 :
2904 19 : case GDT_UInt16:
2905 19 : return 0;
2906 :
2907 24 : case GDT_Int16:
2908 : case GDT_CInt16:
2909 24 : return -32768;
2910 :
2911 17 : case GDT_Int32:
2912 : case GDT_CInt32:
2913 17 : return -2147483648.0;
2914 :
2915 13 : case GDT_UInt32:
2916 13 : return 0;
2917 :
2918 0 : case GDT_Int64:
2919 0 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
2920 :
2921 0 : case GDT_UInt64:
2922 0 : return 0;
2923 :
2924 0 : case GDT_Float16:
2925 : case GDT_CFloat16:
2926 0 : return -65504.0;
2927 :
2928 32 : case GDT_Float32:
2929 : case GDT_CFloat32:
2930 32 : return -4294967295.0; // Not actually accurate.
2931 :
2932 24 : case GDT_Float64:
2933 : case GDT_CFloat64:
2934 24 : return -4294967295.0; // Not actually accurate.
2935 :
2936 0 : case GDT_Unknown:
2937 : case GDT_TypeCount:
2938 0 : break;
2939 : }
2940 0 : return -4294967295.0; // Not actually accurate.
2941 : }
2942 :
2943 : /************************************************************************/
2944 : /* GDALGetRasterMinimum() */
2945 : /************************************************************************/
2946 :
2947 : /**
2948 : * \brief Fetch the minimum value for this band.
2949 : *
2950 : * @see GDALRasterBand::GetMinimum()
2951 : */
2952 :
2953 258 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
2954 :
2955 : {
2956 258 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
2957 :
2958 258 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2959 258 : return poBand->GetMinimum(pbSuccess);
2960 : }
2961 :
2962 : /************************************************************************/
2963 : /* GetColorInterpretation() */
2964 : /************************************************************************/
2965 :
2966 : /**
2967 : * \brief How should this band be interpreted as color?
2968 : *
2969 : * GCI_Undefined is returned when the format doesn't know anything
2970 : * about the color interpretation.
2971 : *
2972 : * This method is the same as the C function
2973 : * GDALGetRasterColorInterpretation().
2974 : *
2975 : * @return color interpretation value for band.
2976 : */
2977 :
2978 115 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
2979 :
2980 : {
2981 115 : return GCI_Undefined;
2982 : }
2983 :
2984 : /************************************************************************/
2985 : /* GDALGetRasterColorInterpretation() */
2986 : /************************************************************************/
2987 :
2988 : /**
2989 : * \brief How should this band be interpreted as color?
2990 : *
2991 : * @see GDALRasterBand::GetColorInterpretation()
2992 : */
2993 :
2994 : GDALColorInterp CPL_STDCALL
2995 5128 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
2996 :
2997 : {
2998 5128 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
2999 :
3000 5128 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3001 5128 : return poBand->GetColorInterpretation();
3002 : }
3003 :
3004 : /************************************************************************/
3005 : /* SetColorInterpretation() */
3006 : /************************************************************************/
3007 :
3008 : /**
3009 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3010 : * \brief Set color interpretation of a band.
3011 : *
3012 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3013 : *
3014 : * @param eColorInterp the new color interpretation to apply to this band.
3015 : *
3016 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3017 : */
3018 :
3019 : /**/
3020 : /**/
3021 :
3022 3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3023 :
3024 : {
3025 3 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3026 3 : ReportError(CE_Failure, CPLE_NotSupported,
3027 : "SetColorInterpretation() not supported for this dataset.");
3028 3 : return CE_Failure;
3029 : }
3030 :
3031 : /************************************************************************/
3032 : /* GDALSetRasterColorInterpretation() */
3033 : /************************************************************************/
3034 :
3035 : /**
3036 : * \brief Set color interpretation of a band.
3037 : *
3038 : * @see GDALRasterBand::SetColorInterpretation()
3039 : */
3040 :
3041 1765 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3042 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3043 :
3044 : {
3045 1765 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3046 :
3047 1765 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3048 1765 : return poBand->SetColorInterpretation(eColorInterp);
3049 : }
3050 :
3051 : /************************************************************************/
3052 : /* GetColorTable() */
3053 : /************************************************************************/
3054 :
3055 : /**
3056 : * \brief Fetch the color table associated with band.
3057 : *
3058 : * If there is no associated color table, the return result is NULL. The
3059 : * returned color table remains owned by the GDALRasterBand, and can't
3060 : * be depended on for long, nor should it ever be modified by the caller.
3061 : *
3062 : * This method is the same as the C function GDALGetRasterColorTable().
3063 : *
3064 : * @return internal color table, or NULL.
3065 : */
3066 :
3067 212 : GDALColorTable *GDALRasterBand::GetColorTable()
3068 :
3069 : {
3070 212 : return nullptr;
3071 : }
3072 :
3073 : /************************************************************************/
3074 : /* GDALGetRasterColorTable() */
3075 : /************************************************************************/
3076 :
3077 : /**
3078 : * \brief Fetch the color table associated with band.
3079 : *
3080 : * @see GDALRasterBand::GetColorTable()
3081 : */
3082 :
3083 1849 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3084 :
3085 : {
3086 1849 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3087 :
3088 1849 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3089 1849 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3090 : }
3091 :
3092 : /************************************************************************/
3093 : /* SetColorTable() */
3094 : /************************************************************************/
3095 :
3096 : /**
3097 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3098 : * \brief Set the raster color table.
3099 : *
3100 : * The driver will make a copy of all desired data in the colortable. It
3101 : * remains owned by the caller after the call.
3102 : *
3103 : * This method is the same as the C function GDALSetRasterColorTable().
3104 : *
3105 : * @param poCT the color table to apply. This may be NULL to clear the color
3106 : * table (where supported).
3107 : *
3108 : * @return CE_None on success, or CE_Failure on failure. If the action is
3109 : * unsupported by the driver, a value of CE_Failure is returned, but no
3110 : * error is issued.
3111 : */
3112 :
3113 : /**/
3114 : /**/
3115 :
3116 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3117 :
3118 : {
3119 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3120 0 : ReportError(CE_Failure, CPLE_NotSupported,
3121 : "SetColorTable() not supported for this dataset.");
3122 0 : return CE_Failure;
3123 : }
3124 :
3125 : /************************************************************************/
3126 : /* GDALSetRasterColorTable() */
3127 : /************************************************************************/
3128 :
3129 : /**
3130 : * \brief Set the raster color table.
3131 : *
3132 : * @see GDALRasterBand::SetColorTable()
3133 : */
3134 :
3135 76 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3136 : GDALColorTableH hCT)
3137 :
3138 : {
3139 76 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3140 :
3141 76 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3142 76 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3143 : }
3144 :
3145 : /************************************************************************/
3146 : /* HasArbitraryOverviews() */
3147 : /************************************************************************/
3148 :
3149 : /**
3150 : * \brief Check for arbitrary overviews.
3151 : *
3152 : * This returns TRUE if the underlying datastore can compute arbitrary
3153 : * overviews efficiently, such as is the case with OGDI over a network.
3154 : * Datastores with arbitrary overviews don't generally have any fixed
3155 : * overviews, but the RasterIO() method can be used in downsampling mode
3156 : * to get overview data efficiently.
3157 : *
3158 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3159 : *
3160 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3161 : * FALSE.
3162 : */
3163 :
3164 231 : int GDALRasterBand::HasArbitraryOverviews()
3165 :
3166 : {
3167 231 : return FALSE;
3168 : }
3169 :
3170 : /************************************************************************/
3171 : /* GDALHasArbitraryOverviews() */
3172 : /************************************************************************/
3173 :
3174 : /**
3175 : * \brief Check for arbitrary overviews.
3176 : *
3177 : * @see GDALRasterBand::HasArbitraryOverviews()
3178 : */
3179 :
3180 165 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3181 :
3182 : {
3183 165 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3184 :
3185 165 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3186 165 : return poBand->HasArbitraryOverviews();
3187 : }
3188 :
3189 : /************************************************************************/
3190 : /* GetOverviewCount() */
3191 : /************************************************************************/
3192 :
3193 : /**
3194 : * \brief Return the number of overview layers available.
3195 : *
3196 : * This method is the same as the C function GDALGetOverviewCount().
3197 : *
3198 : * @return overview count, zero if none.
3199 : */
3200 :
3201 660510 : int GDALRasterBand::GetOverviewCount()
3202 :
3203 : {
3204 1316130 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3205 655616 : poDS->AreOverviewsEnabled())
3206 655616 : return poDS->oOvManager.GetOverviewCount(nBand);
3207 :
3208 4894 : return 0;
3209 : }
3210 :
3211 : /************************************************************************/
3212 : /* GDALGetOverviewCount() */
3213 : /************************************************************************/
3214 :
3215 : /**
3216 : * \brief Return the number of overview layers available.
3217 : *
3218 : * @see GDALRasterBand::GetOverviewCount()
3219 : */
3220 :
3221 3189 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3222 :
3223 : {
3224 3189 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3225 :
3226 3189 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3227 3189 : return poBand->GetOverviewCount();
3228 : }
3229 :
3230 : /************************************************************************/
3231 : /* GetOverview() */
3232 : /************************************************************************/
3233 :
3234 : /**
3235 : * \brief Fetch overview raster band object.
3236 : *
3237 : * This method is the same as the C function GDALGetOverview().
3238 : *
3239 : * @param i overview index between 0 and GetOverviewCount()-1.
3240 : *
3241 : * @return overview GDALRasterBand.
3242 : */
3243 :
3244 791 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3245 :
3246 : {
3247 1527 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3248 736 : poDS->AreOverviewsEnabled())
3249 736 : return poDS->oOvManager.GetOverview(nBand, i);
3250 :
3251 55 : return nullptr;
3252 : }
3253 :
3254 : /************************************************************************/
3255 : /* GDALGetOverview() */
3256 : /************************************************************************/
3257 :
3258 : /**
3259 : * \brief Fetch overview raster band object.
3260 : *
3261 : * @see GDALRasterBand::GetOverview()
3262 : */
3263 :
3264 5587 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3265 :
3266 : {
3267 5587 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3268 :
3269 5587 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3270 5587 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3271 : }
3272 :
3273 : /************************************************************************/
3274 : /* GetRasterSampleOverview() */
3275 : /************************************************************************/
3276 :
3277 : /**
3278 : * \brief Fetch best sampling overview.
3279 : *
3280 : * Returns the most reduced overview of the given band that still satisfies
3281 : * the desired number of samples. This function can be used with zero
3282 : * as the number of desired samples to fetch the most reduced overview.
3283 : * The same band as was passed in will be returned if it has not overviews,
3284 : * or if none of the overviews have enough samples.
3285 : *
3286 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3287 : * and GDALGetRasterSampleOverviewEx().
3288 : *
3289 : * @param nDesiredSamples the returned band will have at least this many
3290 : * pixels.
3291 : *
3292 : * @return optimal overview or the band itself.
3293 : */
3294 :
3295 : GDALRasterBand *
3296 2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3297 :
3298 : {
3299 2006 : GDALRasterBand *poBestBand = this;
3300 :
3301 2006 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3302 :
3303 4023 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3304 : {
3305 2017 : GDALRasterBand *poOBand = GetOverview(iOverview);
3306 :
3307 2017 : if (poOBand == nullptr)
3308 0 : continue;
3309 :
3310 : const double dfOSamples =
3311 2017 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3312 :
3313 2017 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3314 : {
3315 2014 : dfBestSamples = dfOSamples;
3316 2014 : poBestBand = poOBand;
3317 : }
3318 : }
3319 :
3320 2006 : return poBestBand;
3321 : }
3322 :
3323 : /************************************************************************/
3324 : /* GDALGetRasterSampleOverview() */
3325 : /************************************************************************/
3326 :
3327 : /**
3328 : * \brief Fetch best sampling overview.
3329 : *
3330 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3331 : * billion samples.
3332 : *
3333 : * @see GDALRasterBand::GetRasterSampleOverview()
3334 : * @see GDALGetRasterSampleOverviewEx()
3335 : */
3336 :
3337 2000 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3338 : int nDesiredSamples)
3339 :
3340 : {
3341 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3342 :
3343 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3344 2000 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3345 4000 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3346 : }
3347 :
3348 : /************************************************************************/
3349 : /* GDALGetRasterSampleOverviewEx() */
3350 : /************************************************************************/
3351 :
3352 : /**
3353 : * \brief Fetch best sampling overview.
3354 : *
3355 : * @see GDALRasterBand::GetRasterSampleOverview()
3356 : * @since GDAL 2.0
3357 : */
3358 :
3359 : GDALRasterBandH CPL_STDCALL
3360 0 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3361 :
3362 : {
3363 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3364 :
3365 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3366 0 : return GDALRasterBand::ToHandle(
3367 0 : poBand->GetRasterSampleOverview(nDesiredSamples));
3368 : }
3369 :
3370 : /************************************************************************/
3371 : /* BuildOverviews() */
3372 : /************************************************************************/
3373 :
3374 : /**
3375 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3376 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3377 : *
3378 : * If the operation is unsupported for the indicated dataset, then
3379 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3380 : * CPLE_NotSupported.
3381 : *
3382 : * WARNING: Most formats don't support per-band overview computation, but
3383 : * require that overviews are computed for all bands of a dataset, using
3384 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3385 : * is the HFA driver which supports this method.
3386 : *
3387 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3388 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3389 : * applied.
3390 : * @param nOverviews number of overviews to build.
3391 : * @param panOverviewList the list of overview decimation factors to build.
3392 : * @param pfnProgress a function to call to report progress, or NULL.
3393 : * @param pProgressData application data to pass to the progress function.
3394 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3395 : * key=value pairs, or NULL
3396 : *
3397 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3398 : */
3399 :
3400 : /**/
3401 : /**/
3402 :
3403 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3404 : int /*nOverviews*/,
3405 : const int * /*panOverviewList*/,
3406 : GDALProgressFunc /*pfnProgress*/,
3407 : void * /*pProgressData*/,
3408 : CSLConstList /* papszOptions */)
3409 :
3410 : {
3411 0 : ReportError(CE_Failure, CPLE_NotSupported,
3412 : "BuildOverviews() not supported for this dataset.");
3413 :
3414 0 : return (CE_Failure);
3415 : }
3416 :
3417 : /************************************************************************/
3418 : /* GetOffset() */
3419 : /************************************************************************/
3420 :
3421 : /**
3422 : * \brief Fetch the raster value offset.
3423 : *
3424 : * This value (in combination with the GetScale() value) can be used to
3425 : * transform raw pixel values into the units returned by GetUnitType().
3426 : * For example this might be used to store elevations in GUInt16 bands
3427 : * with a precision of 0.1, and starting from -100.
3428 : *
3429 : * Units value = (raw value * scale) + offset
3430 : *
3431 : * Note that applying scale and offset is of the responsibility of the user,
3432 : * and is not done by methods such as RasterIO() or ReadBlock().
3433 : *
3434 : * For file formats that don't know this intrinsically a value of zero
3435 : * is returned.
3436 : *
3437 : * This method is the same as the C function GDALGetRasterOffset().
3438 : *
3439 : * @param pbSuccess pointer to a boolean to use to indicate if the
3440 : * returned value is meaningful or not. May be NULL (default).
3441 : *
3442 : * @return the raster offset.
3443 : */
3444 :
3445 390 : double GDALRasterBand::GetOffset(int *pbSuccess)
3446 :
3447 : {
3448 390 : if (pbSuccess != nullptr)
3449 322 : *pbSuccess = FALSE;
3450 :
3451 390 : return 0.0;
3452 : }
3453 :
3454 : /************************************************************************/
3455 : /* GDALGetRasterOffset() */
3456 : /************************************************************************/
3457 :
3458 : /**
3459 : * \brief Fetch the raster value offset.
3460 : *
3461 : * @see GDALRasterBand::GetOffset()
3462 : */
3463 :
3464 343 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3465 :
3466 : {
3467 343 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3468 :
3469 343 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3470 343 : return poBand->GetOffset(pbSuccess);
3471 : }
3472 :
3473 : /************************************************************************/
3474 : /* SetOffset() */
3475 : /************************************************************************/
3476 :
3477 : /**
3478 : * \fn GDALRasterBand::SetOffset(double)
3479 : * \brief Set scaling offset.
3480 : *
3481 : * Very few formats implement this method. When not implemented it will
3482 : * issue a CPLE_NotSupported error and return CE_Failure.
3483 : *
3484 : * This method is the same as the C function GDALSetRasterOffset().
3485 : *
3486 : * @param dfNewOffset the new offset.
3487 : *
3488 : * @return CE_None or success or CE_Failure on failure.
3489 : */
3490 :
3491 : /**/
3492 : /**/
3493 :
3494 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3495 : {
3496 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3497 0 : ReportError(CE_Failure, CPLE_NotSupported,
3498 : "SetOffset() not supported on this raster band.");
3499 :
3500 0 : return CE_Failure;
3501 : }
3502 :
3503 : /************************************************************************/
3504 : /* GDALSetRasterOffset() */
3505 : /************************************************************************/
3506 :
3507 : /**
3508 : * \brief Set scaling offset.
3509 : *
3510 : * @see GDALRasterBand::SetOffset()
3511 : */
3512 :
3513 65 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3514 : double dfNewOffset)
3515 :
3516 : {
3517 65 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3518 :
3519 65 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3520 65 : return poBand->SetOffset(dfNewOffset);
3521 : }
3522 :
3523 : /************************************************************************/
3524 : /* GetScale() */
3525 : /************************************************************************/
3526 :
3527 : /**
3528 : * \brief Fetch the raster value scale.
3529 : *
3530 : * This value (in combination with the GetOffset() value) can be used to
3531 : * transform raw pixel values into the units returned by GetUnitType().
3532 : * For example this might be used to store elevations in GUInt16 bands
3533 : * with a precision of 0.1, and starting from -100.
3534 : *
3535 : * Units value = (raw value * scale) + offset
3536 : *
3537 : * Note that applying scale and offset is of the responsibility of the user,
3538 : * and is not done by methods such as RasterIO() or ReadBlock().
3539 : *
3540 : * For file formats that don't know this intrinsically a value of one
3541 : * is returned.
3542 : *
3543 : * This method is the same as the C function GDALGetRasterScale().
3544 : *
3545 : * @param pbSuccess pointer to a boolean to use to indicate if the
3546 : * returned value is meaningful or not. May be NULL (default).
3547 : *
3548 : * @return the raster scale.
3549 : */
3550 :
3551 390 : double GDALRasterBand::GetScale(int *pbSuccess)
3552 :
3553 : {
3554 390 : if (pbSuccess != nullptr)
3555 322 : *pbSuccess = FALSE;
3556 :
3557 390 : return 1.0;
3558 : }
3559 :
3560 : /************************************************************************/
3561 : /* GDALGetRasterScale() */
3562 : /************************************************************************/
3563 :
3564 : /**
3565 : * \brief Fetch the raster value scale.
3566 : *
3567 : * @see GDALRasterBand::GetScale()
3568 : */
3569 :
3570 341 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3571 :
3572 : {
3573 341 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3574 :
3575 341 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3576 341 : return poBand->GetScale(pbSuccess);
3577 : }
3578 :
3579 : /************************************************************************/
3580 : /* SetScale() */
3581 : /************************************************************************/
3582 :
3583 : /**
3584 : * \fn GDALRasterBand::SetScale(double)
3585 : * \brief Set scaling ratio.
3586 : *
3587 : * Very few formats implement this method. When not implemented it will
3588 : * issue a CPLE_NotSupported error and return CE_Failure.
3589 : *
3590 : * This method is the same as the C function GDALSetRasterScale().
3591 : *
3592 : * @param dfNewScale the new scale.
3593 : *
3594 : * @return CE_None or success or CE_Failure on failure.
3595 : */
3596 :
3597 : /**/
3598 : /**/
3599 :
3600 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3601 :
3602 : {
3603 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3604 0 : ReportError(CE_Failure, CPLE_NotSupported,
3605 : "SetScale() not supported on this raster band.");
3606 :
3607 0 : return CE_Failure;
3608 : }
3609 :
3610 : /************************************************************************/
3611 : /* GDALSetRasterScale() */
3612 : /************************************************************************/
3613 :
3614 : /**
3615 : * \brief Set scaling ratio.
3616 : *
3617 : * @see GDALRasterBand::SetScale()
3618 : */
3619 :
3620 66 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3621 :
3622 : {
3623 66 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3624 :
3625 66 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3626 66 : return poBand->SetScale(dfNewOffset);
3627 : }
3628 :
3629 : /************************************************************************/
3630 : /* GetUnitType() */
3631 : /************************************************************************/
3632 :
3633 : /**
3634 : * \brief Return raster unit type.
3635 : *
3636 : * Return a name for the units of this raster's values. For instance, it
3637 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3638 : * units are available, a value of "" will be returned. The returned string
3639 : * should not be modified, nor freed by the calling application.
3640 : *
3641 : * This method is the same as the C function GDALGetRasterUnitType().
3642 : *
3643 : * @return unit name string.
3644 : */
3645 :
3646 155 : const char *GDALRasterBand::GetUnitType()
3647 :
3648 : {
3649 155 : return "";
3650 : }
3651 :
3652 : /************************************************************************/
3653 : /* GDALGetRasterUnitType() */
3654 : /************************************************************************/
3655 :
3656 : /**
3657 : * \brief Return raster unit type.
3658 : *
3659 : * @see GDALRasterBand::GetUnitType()
3660 : */
3661 :
3662 1344 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3663 :
3664 : {
3665 1344 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3666 :
3667 1344 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3668 1344 : return poBand->GetUnitType();
3669 : }
3670 :
3671 : /************************************************************************/
3672 : /* SetUnitType() */
3673 : /************************************************************************/
3674 :
3675 : /**
3676 : * \fn GDALRasterBand::SetUnitType(const char*)
3677 : * \brief Set unit type.
3678 : *
3679 : * Set the unit type for a raster band. Values should be one of
3680 : * "" (the default indicating it is unknown), "m" indicating meters,
3681 : * or "ft" indicating feet, though other nonstandard values are allowed.
3682 : *
3683 : * This method is the same as the C function GDALSetRasterUnitType().
3684 : *
3685 : * @param pszNewValue the new unit type value.
3686 : *
3687 : * @return CE_None on success or CE_Failure if not successful, or
3688 : * unsupported.
3689 : */
3690 :
3691 : /**/
3692 : /**/
3693 :
3694 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3695 :
3696 : {
3697 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3698 0 : ReportError(CE_Failure, CPLE_NotSupported,
3699 : "SetUnitType() not supported on this raster band.");
3700 0 : return CE_Failure;
3701 : }
3702 :
3703 : /************************************************************************/
3704 : /* GDALSetRasterUnitType() */
3705 : /************************************************************************/
3706 :
3707 : /**
3708 : * \brief Set unit type.
3709 : *
3710 : * @see GDALRasterBand::SetUnitType()
3711 : *
3712 : * @since GDAL 1.8.0
3713 : */
3714 :
3715 60 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3716 : const char *pszNewValue)
3717 :
3718 : {
3719 60 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3720 :
3721 60 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3722 60 : return poBand->SetUnitType(pszNewValue);
3723 : }
3724 :
3725 : /************************************************************************/
3726 : /* GetXSize() */
3727 : /************************************************************************/
3728 :
3729 : /**
3730 : * \brief Fetch XSize of raster.
3731 : *
3732 : * This method is the same as the C function GDALGetRasterBandXSize().
3733 : *
3734 : * @return the width in pixels of this band.
3735 : */
3736 :
3737 6787130 : int GDALRasterBand::GetXSize() const
3738 :
3739 : {
3740 6787130 : return nRasterXSize;
3741 : }
3742 :
3743 : /************************************************************************/
3744 : /* GDALGetRasterBandXSize() */
3745 : /************************************************************************/
3746 :
3747 : /**
3748 : * \brief Fetch XSize of raster.
3749 : *
3750 : * @see GDALRasterBand::GetXSize()
3751 : */
3752 :
3753 54250 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3754 :
3755 : {
3756 54250 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3757 :
3758 54250 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3759 54250 : return poBand->GetXSize();
3760 : }
3761 :
3762 : /************************************************************************/
3763 : /* GetYSize() */
3764 : /************************************************************************/
3765 :
3766 : /**
3767 : * \brief Fetch YSize of raster.
3768 : *
3769 : * This method is the same as the C function GDALGetRasterBandYSize().
3770 : *
3771 : * @return the height in pixels of this band.
3772 : */
3773 :
3774 3306210 : int GDALRasterBand::GetYSize() const
3775 :
3776 : {
3777 3306210 : return nRasterYSize;
3778 : }
3779 :
3780 : /************************************************************************/
3781 : /* GDALGetRasterBandYSize() */
3782 : /************************************************************************/
3783 :
3784 : /**
3785 : * \brief Fetch YSize of raster.
3786 : *
3787 : * @see GDALRasterBand::GetYSize()
3788 : */
3789 :
3790 53616 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3791 :
3792 : {
3793 53616 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3794 :
3795 53616 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3796 53616 : return poBand->GetYSize();
3797 : }
3798 :
3799 : /************************************************************************/
3800 : /* GetBand() */
3801 : /************************************************************************/
3802 :
3803 : /**
3804 : * \brief Fetch the band number.
3805 : *
3806 : * This method returns the band that this GDALRasterBand objects represents
3807 : * within its dataset. This method may return a value of 0 to indicate
3808 : * GDALRasterBand objects without an apparently relationship to a dataset,
3809 : * such as GDALRasterBands serving as overviews.
3810 : *
3811 : * This method is the same as the C function GDALGetBandNumber().
3812 : *
3813 : * @return band number (1+) or 0 if the band number isn't known.
3814 : */
3815 :
3816 19352 : int GDALRasterBand::GetBand() const
3817 :
3818 : {
3819 19352 : return nBand;
3820 : }
3821 :
3822 : /************************************************************************/
3823 : /* GDALGetBandNumber() */
3824 : /************************************************************************/
3825 :
3826 : /**
3827 : * \brief Fetch the band number.
3828 : *
3829 : * @see GDALRasterBand::GetBand()
3830 : */
3831 :
3832 147 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3833 :
3834 : {
3835 147 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3836 :
3837 147 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3838 147 : return poBand->GetBand();
3839 : }
3840 :
3841 : /************************************************************************/
3842 : /* GetDataset() */
3843 : /************************************************************************/
3844 :
3845 : /**
3846 : * \brief Fetch the owning dataset handle.
3847 : *
3848 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3849 : * such as overviews or other "freestanding" bands.
3850 : *
3851 : * This method is the same as the C function GDALGetBandDataset().
3852 : *
3853 : * @return the pointer to the GDALDataset to which this band belongs, or
3854 : * NULL if this cannot be determined.
3855 : */
3856 :
3857 3895100 : GDALDataset *GDALRasterBand::GetDataset() const
3858 :
3859 : {
3860 3895100 : return poDS;
3861 : }
3862 :
3863 : /************************************************************************/
3864 : /* GDALGetBandDataset() */
3865 : /************************************************************************/
3866 :
3867 : /**
3868 : * \brief Fetch the owning dataset handle.
3869 : *
3870 : * @see GDALRasterBand::GetDataset()
3871 : */
3872 :
3873 316 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
3874 :
3875 : {
3876 316 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
3877 :
3878 316 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3879 316 : return GDALDataset::ToHandle(poBand->GetDataset());
3880 : }
3881 :
3882 : /************************************************************************/
3883 : /* ComputeFloat16NoDataValue() */
3884 : /************************************************************************/
3885 :
3886 2038 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
3887 : double dfNoDataValue,
3888 : int &bGotNoDataValue,
3889 : GFloat16 &fNoDataValue,
3890 : bool &bGotFloat16NoDataValue)
3891 : {
3892 2038 : if (eDataType == GDT_Float16 && bGotNoDataValue)
3893 : {
3894 0 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
3895 0 : if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
3896 : {
3897 0 : fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
3898 0 : bGotFloat16NoDataValue = true;
3899 0 : bGotNoDataValue = false;
3900 : }
3901 : }
3902 2038 : }
3903 :
3904 : /************************************************************************/
3905 : /* ComputeFloatNoDataValue() */
3906 : /************************************************************************/
3907 :
3908 2038 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
3909 : double dfNoDataValue,
3910 : int &bGotNoDataValue,
3911 : float &fNoDataValue,
3912 : bool &bGotFloatNoDataValue)
3913 : {
3914 2038 : if (eDataType == GDT_Float32 && bGotNoDataValue)
3915 : {
3916 81 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
3917 81 : if (GDALIsValueInRange<float>(dfNoDataValue))
3918 : {
3919 81 : fNoDataValue = static_cast<float>(dfNoDataValue);
3920 81 : bGotFloatNoDataValue = true;
3921 81 : bGotNoDataValue = false;
3922 : }
3923 : }
3924 2038 : }
3925 :
3926 : /************************************************************************/
3927 : /* struct GDALNoDataValues */
3928 : /************************************************************************/
3929 :
3930 : /**
3931 : * \brief No-data-values for all types
3932 : *
3933 : * The functions below pass various no-data-values around. To avoid
3934 : * long argument lists, this struct collects the no-data-values for
3935 : * all types into a single, convenient place.
3936 : **/
3937 :
3938 : struct GDALNoDataValues
3939 : {
3940 : int bGotNoDataValue;
3941 : double dfNoDataValue;
3942 :
3943 : bool bGotFloatNoDataValue;
3944 : float fNoDataValue;
3945 :
3946 : bool bGotFloat16NoDataValue;
3947 : GFloat16 hfNoDataValue;
3948 :
3949 2038 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
3950 2038 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
3951 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
3952 2038 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
3953 : {
3954 2038 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
3955 2038 : bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
3956 :
3957 2038 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
3958 2038 : fNoDataValue, bGotFloatNoDataValue);
3959 :
3960 2038 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
3961 2038 : hfNoDataValue, bGotFloat16NoDataValue);
3962 2038 : }
3963 : };
3964 :
3965 : /************************************************************************/
3966 : /* GetHistogram() */
3967 : /************************************************************************/
3968 :
3969 : /**
3970 : * \brief Compute raster histogram.
3971 : *
3972 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
3973 : *
3974 : * For example to compute a simple 256 entry histogram of eight bit data,
3975 : * the following would be suitable. The unusual bounds are to ensure that
3976 : * bucket boundaries don't fall right on integer values causing possible errors
3977 : * due to rounding after scaling.
3978 : \code{.cpp}
3979 : GUIntBig anHistogram[256];
3980 :
3981 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
3982 : GDALDummyProgress, nullptr );
3983 : \endcode
3984 : *
3985 : * Note that setting bApproxOK will generally result in a subsampling of the
3986 : * file, and will utilize overviews if available. It should generally
3987 : * produce a representative histogram for the data that is suitable for use
3988 : * in generating histogram based luts for instance. Generally bApproxOK is
3989 : * much faster than an exactly computed histogram.
3990 : *
3991 : * This method is the same as the C functions GDALGetRasterHistogram() and
3992 : * GDALGetRasterHistogramEx().
3993 : *
3994 : * @param dfMin the lower bound of the histogram.
3995 : * @param dfMax the upper bound of the histogram.
3996 : * @param nBuckets the number of buckets in panHistogram.
3997 : * @param panHistogram array into which the histogram totals are placed.
3998 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
3999 : * mapped into panHistogram[0], and values above will be mapped into
4000 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4001 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4002 : * @param pfnProgress function to report progress to completion.
4003 : * @param pProgressData application data to pass to pfnProgress.
4004 : *
4005 : * @return CE_None on success, or CE_Failure if something goes wrong.
4006 : */
4007 :
4008 39 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4009 : GUIntBig *panHistogram,
4010 : int bIncludeOutOfRange, int bApproxOK,
4011 : GDALProgressFunc pfnProgress,
4012 : void *pProgressData)
4013 :
4014 : {
4015 39 : CPLAssert(nullptr != panHistogram);
4016 :
4017 39 : if (pfnProgress == nullptr)
4018 26 : pfnProgress = GDALDummyProgress;
4019 :
4020 : /* -------------------------------------------------------------------- */
4021 : /* If we have overviews, use them for the histogram. */
4022 : /* -------------------------------------------------------------------- */
4023 39 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4024 : {
4025 : // FIXME: should we use the most reduced overview here or use some
4026 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4027 : // does?
4028 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4029 :
4030 0 : if (poBestOverview != this)
4031 : {
4032 0 : return poBestOverview->GetHistogram(
4033 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4034 0 : bApproxOK, pfnProgress, pProgressData);
4035 : }
4036 : }
4037 :
4038 : /* -------------------------------------------------------------------- */
4039 : /* Read actual data and build histogram. */
4040 : /* -------------------------------------------------------------------- */
4041 39 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4042 : {
4043 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4044 0 : return CE_Failure;
4045 : }
4046 :
4047 : // Written this way to deal with NaN
4048 39 : if (!(dfMax > dfMin))
4049 : {
4050 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4051 : "dfMax should be strictly greater than dfMin");
4052 5 : return CE_Failure;
4053 : }
4054 :
4055 : GDALRasterIOExtraArg sExtraArg;
4056 34 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4057 :
4058 34 : const double dfScale = nBuckets / (dfMax - dfMin);
4059 34 : if (dfScale == 0 || !std::isfinite(dfScale))
4060 : {
4061 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4062 : "dfMin and dfMax should be finite values such that "
4063 : "nBuckets / (dfMax - dfMin) is non-zero");
4064 5 : return CE_Failure;
4065 : }
4066 29 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4067 :
4068 29 : GDALNoDataValues sNoDataValues(this, eDataType);
4069 29 : GDALRasterBand *poMaskBand = nullptr;
4070 29 : if (!sNoDataValues.bGotNoDataValue)
4071 : {
4072 28 : const int l_nMaskFlags = GetMaskFlags();
4073 29 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
4074 1 : GetColorInterpretation() != GCI_AlphaBand)
4075 : {
4076 1 : poMaskBand = GetMaskBand();
4077 : }
4078 : }
4079 :
4080 29 : bool bSignedByte = false;
4081 29 : if (eDataType == GDT_Byte)
4082 : {
4083 22 : EnablePixelTypeSignedByteWarning(false);
4084 : const char *pszPixelType =
4085 22 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4086 22 : EnablePixelTypeSignedByteWarning(true);
4087 22 : bSignedByte =
4088 22 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4089 : }
4090 :
4091 29 : if (bApproxOK && HasArbitraryOverviews())
4092 : {
4093 : /* --------------------------------------------------------------------
4094 : */
4095 : /* Figure out how much the image should be reduced to get an */
4096 : /* approximate value. */
4097 : /* --------------------------------------------------------------------
4098 : */
4099 : const double dfReduction =
4100 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4101 : GDALSTAT_APPROX_NUMSAMPLES);
4102 :
4103 0 : int nXReduced = nRasterXSize;
4104 0 : int nYReduced = nRasterYSize;
4105 0 : if (dfReduction > 1.0)
4106 : {
4107 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4108 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4109 :
4110 : // Catch the case of huge resizing ratios here
4111 0 : if (nXReduced == 0)
4112 0 : nXReduced = 1;
4113 0 : if (nYReduced == 0)
4114 0 : nYReduced = 1;
4115 : }
4116 :
4117 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4118 : nXReduced, nYReduced);
4119 0 : if (!pData)
4120 0 : return CE_Failure;
4121 :
4122 : const CPLErr eErr =
4123 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4124 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4125 0 : if (eErr != CE_None)
4126 : {
4127 0 : CPLFree(pData);
4128 0 : return eErr;
4129 : }
4130 :
4131 0 : GByte *pabyMaskData = nullptr;
4132 0 : if (poMaskBand)
4133 : {
4134 : pabyMaskData =
4135 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4136 0 : if (!pabyMaskData)
4137 : {
4138 0 : CPLFree(pData);
4139 0 : return CE_Failure;
4140 : }
4141 :
4142 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4143 : pabyMaskData, nXReduced, nYReduced,
4144 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
4145 : {
4146 0 : CPLFree(pData);
4147 0 : CPLFree(pabyMaskData);
4148 0 : return CE_Failure;
4149 : }
4150 : }
4151 :
4152 : // This isn't the fastest way to do this, but is easier for now.
4153 0 : for (int iY = 0; iY < nYReduced; iY++)
4154 : {
4155 0 : for (int iX = 0; iX < nXReduced; iX++)
4156 : {
4157 0 : const int iOffset = iX + iY * nXReduced;
4158 0 : double dfValue = 0.0;
4159 :
4160 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4161 0 : continue;
4162 :
4163 0 : switch (eDataType)
4164 : {
4165 0 : case GDT_Byte:
4166 : {
4167 0 : if (bSignedByte)
4168 0 : dfValue =
4169 0 : static_cast<signed char *>(pData)[iOffset];
4170 : else
4171 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4172 0 : break;
4173 : }
4174 0 : case GDT_Int8:
4175 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4176 0 : break;
4177 0 : case GDT_UInt16:
4178 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4179 0 : break;
4180 0 : case GDT_Int16:
4181 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4182 0 : break;
4183 0 : case GDT_UInt32:
4184 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4185 0 : break;
4186 0 : case GDT_Int32:
4187 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4188 0 : break;
4189 0 : case GDT_UInt64:
4190 0 : dfValue = static_cast<double>(
4191 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4192 0 : break;
4193 0 : case GDT_Int64:
4194 0 : dfValue = static_cast<double>(
4195 0 : static_cast<GInt64 *>(pData)[iOffset]);
4196 0 : break;
4197 0 : case GDT_Float16:
4198 : {
4199 0 : const GFloat16 hfValue =
4200 0 : static_cast<GFloat16 *>(pData)[iOffset];
4201 0 : if (CPLIsNan(hfValue) ||
4202 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4203 0 : ARE_REAL_EQUAL(hfValue,
4204 : sNoDataValues.hfNoDataValue)))
4205 0 : continue;
4206 0 : dfValue = hfValue;
4207 0 : break;
4208 : }
4209 0 : case GDT_Float32:
4210 : {
4211 0 : const float fValue =
4212 0 : static_cast<float *>(pData)[iOffset];
4213 0 : if (CPLIsNan(fValue) ||
4214 0 : (sNoDataValues.bGotFloatNoDataValue &&
4215 0 : ARE_REAL_EQUAL(fValue,
4216 : sNoDataValues.fNoDataValue)))
4217 0 : continue;
4218 0 : dfValue = fValue;
4219 0 : break;
4220 : }
4221 0 : case GDT_Float64:
4222 0 : dfValue = static_cast<double *>(pData)[iOffset];
4223 0 : if (std::isnan(dfValue))
4224 0 : continue;
4225 0 : break;
4226 0 : case GDT_CInt16:
4227 : {
4228 0 : const double dfReal =
4229 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4230 0 : const double dfImag =
4231 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4232 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4233 0 : continue;
4234 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4235 : }
4236 0 : break;
4237 0 : case GDT_CInt32:
4238 : {
4239 0 : const double dfReal =
4240 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4241 0 : const double dfImag =
4242 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4243 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4244 0 : continue;
4245 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4246 : }
4247 0 : break;
4248 0 : case GDT_CFloat16:
4249 : {
4250 : const double dfReal =
4251 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4252 : const double dfImag =
4253 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4254 0 : if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
4255 0 : continue;
4256 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4257 0 : break;
4258 : }
4259 0 : case GDT_CFloat32:
4260 : {
4261 0 : const double dfReal =
4262 0 : static_cast<float *>(pData)[iOffset * 2];
4263 0 : const double dfImag =
4264 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
4265 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4266 0 : continue;
4267 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4268 0 : break;
4269 : }
4270 0 : case GDT_CFloat64:
4271 : {
4272 0 : const double dfReal =
4273 0 : static_cast<double *>(pData)[iOffset * 2];
4274 0 : const double dfImag =
4275 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4276 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4277 0 : continue;
4278 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4279 0 : break;
4280 : }
4281 0 : case GDT_Unknown:
4282 : case GDT_TypeCount:
4283 0 : CPLAssert(false);
4284 : }
4285 :
4286 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4287 0 : sNoDataValues.bGotNoDataValue &&
4288 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4289 0 : continue;
4290 :
4291 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4292 : // finite, the result of the multiplication cannot be NaN
4293 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4294 :
4295 0 : if (dfIndex < 0)
4296 : {
4297 0 : if (bIncludeOutOfRange)
4298 0 : panHistogram[0]++;
4299 : }
4300 0 : else if (dfIndex >= nBuckets)
4301 : {
4302 0 : if (bIncludeOutOfRange)
4303 0 : ++panHistogram[nBuckets - 1];
4304 : }
4305 : else
4306 : {
4307 0 : ++panHistogram[static_cast<int>(dfIndex)];
4308 : }
4309 : }
4310 : }
4311 :
4312 0 : CPLFree(pData);
4313 0 : CPLFree(pabyMaskData);
4314 : }
4315 : else // No arbitrary overviews.
4316 : {
4317 29 : if (!InitBlockInfo())
4318 0 : return CE_Failure;
4319 :
4320 : /* --------------------------------------------------------------------
4321 : */
4322 : /* Figure out the ratio of blocks we will read to get an */
4323 : /* approximate value. */
4324 : /* --------------------------------------------------------------------
4325 : */
4326 :
4327 29 : int nSampleRate = 1;
4328 29 : if (bApproxOK)
4329 : {
4330 8 : nSampleRate = static_cast<int>(std::max(
4331 16 : 1.0,
4332 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4333 : // We want to avoid probing only the first column of blocks for
4334 : // a square shaped raster, because it is not unlikely that it may
4335 : // be padding only (#6378).
4336 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4337 2 : nSampleRate += 1;
4338 : }
4339 :
4340 29 : GByte *pabyMaskData = nullptr;
4341 29 : if (poMaskBand)
4342 : {
4343 : pabyMaskData = static_cast<GByte *>(
4344 1 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4345 1 : if (!pabyMaskData)
4346 : {
4347 0 : return CE_Failure;
4348 : }
4349 : }
4350 :
4351 : /* --------------------------------------------------------------------
4352 : */
4353 : /* Read the blocks, and add to histogram. */
4354 : /* --------------------------------------------------------------------
4355 : */
4356 29 : for (GIntBig iSampleBlock = 0;
4357 136 : iSampleBlock <
4358 136 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4359 107 : iSampleBlock += nSampleRate)
4360 : {
4361 107 : if (!pfnProgress(
4362 107 : static_cast<double>(iSampleBlock) /
4363 107 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4364 : "Compute Histogram", pProgressData))
4365 : {
4366 0 : CPLFree(pabyMaskData);
4367 0 : return CE_Failure;
4368 : }
4369 :
4370 107 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4371 107 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4372 :
4373 107 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4374 107 : if (poBlock == nullptr)
4375 : {
4376 0 : CPLFree(pabyMaskData);
4377 0 : return CE_Failure;
4378 : }
4379 :
4380 107 : void *pData = poBlock->GetDataRef();
4381 :
4382 107 : int nXCheck = 0, nYCheck = 0;
4383 107 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4384 :
4385 108 : if (poMaskBand &&
4386 1 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4387 1 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4388 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4389 1 : 0, nBlockXSize, nullptr) != CE_None)
4390 : {
4391 0 : CPLFree(pabyMaskData);
4392 0 : poBlock->DropLock();
4393 0 : return CE_Failure;
4394 : }
4395 :
4396 : // this is a special case for a common situation.
4397 107 : if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4398 85 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4399 82 : nXCheck == nBlockXSize && nBuckets == 256)
4400 : {
4401 82 : const GPtrDiff_t nPixels =
4402 82 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4403 82 : GByte *pabyData = static_cast<GByte *>(pData);
4404 :
4405 72134 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4406 : {
4407 72052 : if (pabyMaskData && pabyMaskData[i] == 0)
4408 0 : continue;
4409 72052 : if (!(sNoDataValues.bGotNoDataValue &&
4410 512 : (pabyData[i] ==
4411 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4412 : {
4413 71796 : panHistogram[pabyData[i]]++;
4414 : }
4415 : }
4416 :
4417 82 : poBlock->DropLock();
4418 82 : continue; // To next sample block.
4419 : }
4420 :
4421 : // This isn't the fastest way to do this, but is easier for now.
4422 721 : for (int iY = 0; iY < nYCheck; iY++)
4423 : {
4424 86017 : for (int iX = 0; iX < nXCheck; iX++)
4425 : {
4426 85321 : const GPtrDiff_t iOffset =
4427 85321 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4428 :
4429 85321 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4430 1 : continue;
4431 :
4432 85320 : double dfValue = 0.0;
4433 :
4434 85320 : switch (eDataType)
4435 : {
4436 19716 : case GDT_Byte:
4437 : {
4438 19716 : if (bSignedByte)
4439 0 : dfValue =
4440 0 : static_cast<signed char *>(pData)[iOffset];
4441 : else
4442 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4443 19716 : break;
4444 : }
4445 0 : case GDT_Int8:
4446 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4447 0 : break;
4448 65536 : case GDT_UInt16:
4449 65536 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4450 65536 : break;
4451 2 : case GDT_Int16:
4452 2 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4453 2 : break;
4454 0 : case GDT_UInt32:
4455 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4456 0 : break;
4457 60 : case GDT_Int32:
4458 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4459 60 : break;
4460 0 : case GDT_UInt64:
4461 0 : dfValue = static_cast<double>(
4462 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4463 0 : break;
4464 0 : case GDT_Int64:
4465 0 : dfValue = static_cast<double>(
4466 0 : static_cast<GInt64 *>(pData)[iOffset]);
4467 0 : break;
4468 0 : case GDT_Float16:
4469 : {
4470 0 : const GFloat16 hfValue =
4471 0 : static_cast<GFloat16 *>(pData)[iOffset];
4472 0 : if (CPLIsNan(hfValue) ||
4473 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4474 0 : ARE_REAL_EQUAL(hfValue,
4475 : sNoDataValues.hfNoDataValue)))
4476 0 : continue;
4477 0 : dfValue = hfValue;
4478 0 : break;
4479 : }
4480 4 : case GDT_Float32:
4481 : {
4482 4 : const float fValue =
4483 4 : static_cast<float *>(pData)[iOffset];
4484 8 : if (CPLIsNan(fValue) ||
4485 8 : (sNoDataValues.bGotFloatNoDataValue &&
4486 4 : ARE_REAL_EQUAL(fValue,
4487 : sNoDataValues.fNoDataValue)))
4488 1 : continue;
4489 3 : dfValue = fValue;
4490 3 : break;
4491 : }
4492 2 : case GDT_Float64:
4493 2 : dfValue = static_cast<double *>(pData)[iOffset];
4494 2 : if (std::isnan(dfValue))
4495 0 : continue;
4496 2 : break;
4497 0 : case GDT_CInt16:
4498 : {
4499 0 : double dfReal =
4500 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4501 0 : double dfImag =
4502 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4503 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4504 0 : break;
4505 : }
4506 0 : case GDT_CInt32:
4507 : {
4508 0 : double dfReal =
4509 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4510 0 : double dfImag =
4511 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4512 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4513 0 : break;
4514 : }
4515 0 : case GDT_CFloat16:
4516 : {
4517 : double dfReal =
4518 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4519 : double dfImag =
4520 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4521 0 : if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
4522 0 : continue;
4523 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4524 0 : break;
4525 : }
4526 0 : case GDT_CFloat32:
4527 : {
4528 0 : double dfReal =
4529 0 : static_cast<float *>(pData)[iOffset * 2];
4530 0 : double dfImag =
4531 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
4532 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4533 0 : continue;
4534 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4535 0 : break;
4536 : }
4537 0 : case GDT_CFloat64:
4538 : {
4539 0 : double dfReal =
4540 0 : static_cast<double *>(pData)[iOffset * 2];
4541 0 : double dfImag =
4542 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4543 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4544 0 : continue;
4545 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4546 0 : break;
4547 : }
4548 0 : case GDT_Unknown:
4549 : case GDT_TypeCount:
4550 0 : CPLAssert(false);
4551 : CPLFree(pabyMaskData);
4552 : return CE_Failure;
4553 : }
4554 :
4555 85319 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4556 170638 : sNoDataValues.bGotNoDataValue &&
4557 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4558 0 : continue;
4559 :
4560 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4561 : // and finite, the result of the multiplication cannot be
4562 : // NaN
4563 85319 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4564 :
4565 85319 : if (dfIndex < 0)
4566 : {
4567 1 : if (bIncludeOutOfRange)
4568 1 : panHistogram[0]++;
4569 : }
4570 85318 : else if (dfIndex >= nBuckets)
4571 : {
4572 7 : if (bIncludeOutOfRange)
4573 4 : ++panHistogram[nBuckets - 1];
4574 : }
4575 : else
4576 : {
4577 85311 : ++panHistogram[static_cast<int>(dfIndex)];
4578 : }
4579 : }
4580 : }
4581 :
4582 25 : poBlock->DropLock();
4583 : }
4584 :
4585 29 : CPLFree(pabyMaskData);
4586 : }
4587 :
4588 29 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4589 :
4590 29 : return CE_None;
4591 : }
4592 :
4593 : /************************************************************************/
4594 : /* GDALGetRasterHistogram() */
4595 : /************************************************************************/
4596 :
4597 : /**
4598 : * \brief Compute raster histogram.
4599 : *
4600 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4601 : * exceeding 2 billion.
4602 : *
4603 : * @see GDALRasterBand::GetHistogram()
4604 : * @see GDALGetRasterHistogramEx()
4605 : */
4606 :
4607 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4608 : double dfMax, int nBuckets,
4609 : int *panHistogram,
4610 : int bIncludeOutOfRange, int bApproxOK,
4611 : GDALProgressFunc pfnProgress,
4612 : void *pProgressData)
4613 :
4614 : {
4615 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4616 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4617 :
4618 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4619 :
4620 : GUIntBig *panHistogramTemp =
4621 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4622 0 : if (panHistogramTemp == nullptr)
4623 : {
4624 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4625 : "Out of memory in GDALGetRasterHistogram().");
4626 0 : return CE_Failure;
4627 : }
4628 :
4629 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4630 : bIncludeOutOfRange, bApproxOK,
4631 0 : pfnProgress, pProgressData);
4632 :
4633 0 : if (eErr == CE_None)
4634 : {
4635 0 : for (int i = 0; i < nBuckets; i++)
4636 : {
4637 0 : if (panHistogramTemp[i] > INT_MAX)
4638 : {
4639 0 : CPLError(CE_Warning, CPLE_AppDefined,
4640 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4641 : " exceeds maximum 32 bit value",
4642 0 : i, panHistogramTemp[i]);
4643 0 : panHistogram[i] = INT_MAX;
4644 : }
4645 : else
4646 : {
4647 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4648 : }
4649 : }
4650 : }
4651 :
4652 0 : CPLFree(panHistogramTemp);
4653 :
4654 0 : return eErr;
4655 : }
4656 :
4657 : /************************************************************************/
4658 : /* GDALGetRasterHistogramEx() */
4659 : /************************************************************************/
4660 :
4661 : /**
4662 : * \brief Compute raster histogram.
4663 : *
4664 : * @see GDALRasterBand::GetHistogram()
4665 : *
4666 : * @since GDAL 2.0
4667 : */
4668 :
4669 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4670 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4671 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4672 : GDALProgressFunc pfnProgress, void *pProgressData)
4673 :
4674 : {
4675 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4676 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4677 :
4678 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4679 :
4680 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4681 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4682 26 : pProgressData);
4683 : }
4684 :
4685 : /************************************************************************/
4686 : /* GetDefaultHistogram() */
4687 : /************************************************************************/
4688 :
4689 : /**
4690 : * \brief Fetch default raster histogram.
4691 : *
4692 : * The default method in GDALRasterBand will compute a default histogram. This
4693 : * method is overridden by derived classes (such as GDALPamRasterBand,
4694 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4695 : * stored histogram.
4696 : *
4697 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4698 : * GDALGetDefaultHistogramEx().
4699 : *
4700 : * @param pdfMin pointer to double value that will contain the lower bound of
4701 : * the histogram.
4702 : * @param pdfMax pointer to double value that will contain the upper bound of
4703 : * the histogram.
4704 : * @param pnBuckets pointer to int value that will contain the number of buckets
4705 : * in *ppanHistogram.
4706 : * @param ppanHistogram pointer to array into which the histogram totals are
4707 : * placed. To be freed with VSIFree
4708 : * @param bForce TRUE to force the computation. If FALSE and no default
4709 : * histogram is available, the method will return CE_Warning
4710 : * @param pfnProgress function to report progress to completion.
4711 : * @param pProgressData application data to pass to pfnProgress.
4712 : *
4713 : * @return CE_None on success, CE_Failure if something goes wrong, or
4714 : * CE_Warning if no default histogram is available.
4715 : */
4716 :
4717 22 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4718 : int *pnBuckets,
4719 : GUIntBig **ppanHistogram, int bForce,
4720 : GDALProgressFunc pfnProgress,
4721 : void *pProgressData)
4722 :
4723 : {
4724 22 : CPLAssert(nullptr != pnBuckets);
4725 22 : CPLAssert(nullptr != ppanHistogram);
4726 22 : CPLAssert(nullptr != pdfMin);
4727 22 : CPLAssert(nullptr != pdfMax);
4728 :
4729 22 : *pnBuckets = 0;
4730 22 : *ppanHistogram = nullptr;
4731 :
4732 22 : if (!bForce)
4733 6 : return CE_Warning;
4734 :
4735 16 : const int nBuckets = 256;
4736 :
4737 16 : bool bSignedByte = false;
4738 16 : if (eDataType == GDT_Byte)
4739 : {
4740 16 : EnablePixelTypeSignedByteWarning(false);
4741 : const char *pszPixelType =
4742 16 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4743 16 : EnablePixelTypeSignedByteWarning(true);
4744 16 : bSignedByte =
4745 16 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4746 : }
4747 :
4748 16 : if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4749 : {
4750 16 : *pdfMin = -0.5;
4751 16 : *pdfMax = 255.5;
4752 : }
4753 : else
4754 : {
4755 :
4756 : const CPLErr eErr =
4757 0 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4758 0 : const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4759 0 : *pdfMin -= dfHalfBucket;
4760 0 : *pdfMax += dfHalfBucket;
4761 :
4762 0 : if (eErr != CE_None)
4763 0 : return eErr;
4764 : }
4765 :
4766 16 : *ppanHistogram =
4767 16 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4768 16 : if (*ppanHistogram == nullptr)
4769 : {
4770 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4771 : "Out of memory in InitBlockInfo().");
4772 0 : return CE_Failure;
4773 : }
4774 :
4775 16 : *pnBuckets = nBuckets;
4776 32 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4777 16 : TRUE, FALSE, pfnProgress, pProgressData);
4778 16 : if (eErr != CE_None)
4779 : {
4780 0 : *pnBuckets = 0;
4781 : }
4782 16 : return eErr;
4783 : }
4784 :
4785 : /************************************************************************/
4786 : /* GDALGetDefaultHistogram() */
4787 : /************************************************************************/
4788 :
4789 : /**
4790 : * \brief Fetch default raster histogram.
4791 : *
4792 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4793 : * exceeding 2 billion.
4794 : *
4795 : * @see GDALRasterBand::GDALGetDefaultHistogram()
4796 : * @see GDALGetRasterHistogramEx()
4797 : */
4798 :
4799 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4800 : double *pdfMin, double *pdfMax,
4801 : int *pnBuckets, int **ppanHistogram,
4802 : int bForce,
4803 : GDALProgressFunc pfnProgress,
4804 : void *pProgressData)
4805 :
4806 : {
4807 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4808 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4809 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4810 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4811 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4812 :
4813 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4814 0 : GUIntBig *panHistogramTemp = nullptr;
4815 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
4816 : &panHistogramTemp, bForce,
4817 0 : pfnProgress, pProgressData);
4818 0 : if (eErr == CE_None)
4819 : {
4820 0 : const int nBuckets = *pnBuckets;
4821 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
4822 0 : if (*ppanHistogram == nullptr)
4823 : {
4824 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4825 : "Out of memory in GDALGetDefaultHistogram().");
4826 0 : VSIFree(panHistogramTemp);
4827 0 : return CE_Failure;
4828 : }
4829 :
4830 0 : for (int i = 0; i < nBuckets; ++i)
4831 : {
4832 0 : if (panHistogramTemp[i] > INT_MAX)
4833 : {
4834 0 : CPLError(CE_Warning, CPLE_AppDefined,
4835 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4836 : " exceeds maximum 32 bit value",
4837 0 : i, panHistogramTemp[i]);
4838 0 : (*ppanHistogram)[i] = INT_MAX;
4839 : }
4840 : else
4841 : {
4842 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
4843 : }
4844 : }
4845 :
4846 0 : CPLFree(panHistogramTemp);
4847 : }
4848 : else
4849 : {
4850 0 : *ppanHistogram = nullptr;
4851 : }
4852 :
4853 0 : return eErr;
4854 : }
4855 :
4856 : /************************************************************************/
4857 : /* GDALGetDefaultHistogramEx() */
4858 : /************************************************************************/
4859 :
4860 : /**
4861 : * \brief Fetch default raster histogram.
4862 : *
4863 : * @see GDALRasterBand::GetDefaultHistogram()
4864 : *
4865 : * @since GDAL 2.0
4866 : */
4867 :
4868 : CPLErr CPL_STDCALL
4869 28 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
4870 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
4871 : GDALProgressFunc pfnProgress, void *pProgressData)
4872 :
4873 : {
4874 28 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4875 28 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4876 28 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4877 28 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4878 28 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4879 :
4880 28 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4881 28 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
4882 28 : bForce, pfnProgress, pProgressData);
4883 : }
4884 :
4885 : /************************************************************************/
4886 : /* AdviseRead() */
4887 : /************************************************************************/
4888 :
4889 : /**
4890 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
4891 : * \brief Advise driver of upcoming read requests.
4892 : *
4893 : * Some GDAL drivers operate more efficiently if they know in advance what
4894 : * set of upcoming read requests will be made. The AdviseRead() method allows
4895 : * an application to notify the driver of the region of interest,
4896 : * and at what resolution the region will be read.
4897 : *
4898 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
4899 : * accelerate access via some drivers.
4900 : *
4901 : * Depending on call paths, drivers might receive several calls to
4902 : * AdviseRead() with the same parameters.
4903 : *
4904 : * @param nXOff The pixel offset to the top left corner of the region
4905 : * of the band to be accessed. This would be zero to start from the left side.
4906 : *
4907 : * @param nYOff The line offset to the top left corner of the region
4908 : * of the band to be accessed. This would be zero to start from the top.
4909 : *
4910 : * @param nXSize The width of the region of the band to be accessed in pixels.
4911 : *
4912 : * @param nYSize The height of the region of the band to be accessed in lines.
4913 : *
4914 : * @param nBufXSize the width of the buffer image into which the desired region
4915 : * is to be read, or from which it is to be written.
4916 : *
4917 : * @param nBufYSize the height of the buffer image into which the desired
4918 : * region is to be read, or from which it is to be written.
4919 : *
4920 : * @param eBufType the type of the pixel values in the pData data buffer. The
4921 : * pixel values will automatically be translated to/from the GDALRasterBand
4922 : * data type as needed.
4923 : *
4924 : * @param papszOptions a list of name=value strings with special control
4925 : * options. Normally this is NULL.
4926 : *
4927 : * @return CE_Failure if the request is invalid and CE_None if it works or
4928 : * is ignored.
4929 : */
4930 :
4931 : /**/
4932 : /**/
4933 :
4934 42316 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
4935 : int /*nYSize*/, int /*nBufXSize*/,
4936 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
4937 : char ** /*papszOptions*/)
4938 : {
4939 42316 : return CE_None;
4940 : }
4941 :
4942 : /************************************************************************/
4943 : /* GDALRasterAdviseRead() */
4944 : /************************************************************************/
4945 :
4946 : /**
4947 : * \brief Advise driver of upcoming read requests.
4948 : *
4949 : * @see GDALRasterBand::AdviseRead()
4950 : */
4951 :
4952 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
4953 : int nYOff, int nXSize, int nYSize,
4954 : int nBufXSize, int nBufYSize,
4955 : GDALDataType eDT,
4956 : CSLConstList papszOptions)
4957 :
4958 : {
4959 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
4960 :
4961 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4962 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
4963 : nBufYSize, eDT,
4964 2 : const_cast<char **>(papszOptions));
4965 : }
4966 :
4967 : /************************************************************************/
4968 : /* GetStatistics() */
4969 : /************************************************************************/
4970 :
4971 : /**
4972 : * \brief Fetch image statistics.
4973 : *
4974 : * Returns the minimum, maximum, mean and standard deviation of all
4975 : * pixel values in this band. If approximate statistics are sufficient,
4976 : * the bApproxOK flag can be set to true in which case overviews, or a
4977 : * subset of image tiles may be used in computing the statistics.
4978 : *
4979 : * If bForce is FALSE results will only be returned if it can be done
4980 : * quickly (i.e. without scanning the image, typically by using pre-existing
4981 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
4982 : * returned efficiently, the method will return CE_Warning but no warning will
4983 : * be issued. This is a non-standard use of the CE_Warning return value
4984 : * to indicate "nothing done".
4985 : *
4986 : * If bForce is TRUE, and results are quickly available without scanning the
4987 : * image, they will be used. If bForce is TRUE and results are not quickly
4988 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
4989 : * which will scan the image.
4990 : *
4991 : * To always force recomputation of statistics, use ComputeStatistics() instead
4992 : * of this method.
4993 : *
4994 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
4995 : * will generally cache statistics in the .pam file allowing fast fetch
4996 : * after the first request.
4997 : *
4998 : * This method is the same as the C function GDALGetRasterStatistics().
4999 : *
5000 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5001 : * or a subset of all tiles.
5002 : *
5003 : * @param bForce If FALSE statistics will only be returned if it can
5004 : * be done without rescanning the image. If TRUE, statistics computation will
5005 : * be forced if pre-existing values are not quickly available.
5006 : *
5007 : * @param pdfMin Location into which to load image minimum (may be NULL).
5008 : *
5009 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5010 : *
5011 : * @param pdfMean Location into which to load image mean (may be NULL).
5012 : *
5013 : * @param pdfStdDev Location into which to load image standard deviation
5014 : * (may be NULL).
5015 : *
5016 : * @return CE_None on success, CE_Warning if no values returned,
5017 : * CE_Failure if an error occurs.
5018 : */
5019 :
5020 611 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5021 : double *pdfMax, double *pdfMean,
5022 : double *pdfStdDev)
5023 :
5024 : {
5025 : /* -------------------------------------------------------------------- */
5026 : /* Do we already have metadata items for the requested values? */
5027 : /* -------------------------------------------------------------------- */
5028 1222 : if ((pdfMin == nullptr ||
5029 611 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5030 202 : (pdfMax == nullptr ||
5031 202 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5032 1424 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5033 202 : (pdfStdDev == nullptr ||
5034 202 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5035 : {
5036 202 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5037 : {
5038 195 : if (pdfMin != nullptr)
5039 195 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5040 195 : if (pdfMax != nullptr)
5041 195 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5042 195 : if (pdfMean != nullptr)
5043 195 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5044 195 : if (pdfStdDev != nullptr)
5045 195 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5046 :
5047 195 : return CE_None;
5048 : }
5049 : }
5050 :
5051 : /* -------------------------------------------------------------------- */
5052 : /* Does the driver already know the min/max? */
5053 : /* -------------------------------------------------------------------- */
5054 416 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5055 : {
5056 0 : int bSuccessMin = FALSE;
5057 0 : int bSuccessMax = FALSE;
5058 :
5059 0 : const double dfMin = GetMinimum(&bSuccessMin);
5060 0 : const double dfMax = GetMaximum(&bSuccessMax);
5061 :
5062 0 : if (bSuccessMin && bSuccessMax)
5063 : {
5064 0 : if (pdfMin != nullptr)
5065 0 : *pdfMin = dfMin;
5066 0 : if (pdfMax != nullptr)
5067 0 : *pdfMax = dfMax;
5068 0 : return CE_None;
5069 : }
5070 : }
5071 :
5072 : /* -------------------------------------------------------------------- */
5073 : /* Either return without results, or force computation. */
5074 : /* -------------------------------------------------------------------- */
5075 416 : if (!bForce)
5076 161 : return CE_Warning;
5077 : else
5078 255 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5079 255 : GDALDummyProgress, nullptr);
5080 : }
5081 :
5082 : /************************************************************************/
5083 : /* GDALGetRasterStatistics() */
5084 : /************************************************************************/
5085 :
5086 : /**
5087 : * \brief Fetch image statistics.
5088 : *
5089 : * @see GDALRasterBand::GetStatistics()
5090 : */
5091 :
5092 260 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5093 : int bForce, double *pdfMin,
5094 : double *pdfMax, double *pdfMean,
5095 : double *pdfStdDev)
5096 :
5097 : {
5098 260 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5099 :
5100 260 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5101 260 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5102 260 : pdfStdDev);
5103 : }
5104 :
5105 : /************************************************************************/
5106 : /* GDALUInt128 */
5107 : /************************************************************************/
5108 :
5109 : #ifdef HAVE_UINT128_T
5110 : class GDALUInt128
5111 : {
5112 : __uint128_t val;
5113 :
5114 630 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5115 : {
5116 630 : }
5117 :
5118 : public:
5119 420 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5120 : {
5121 : // Evaluates to just a single mul on x86_64
5122 420 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5123 : }
5124 :
5125 210 : GDALUInt128 operator-(const GDALUInt128 &other) const
5126 : {
5127 210 : return GDALUInt128(val - other.val);
5128 : }
5129 :
5130 201 : operator double() const
5131 : {
5132 201 : return static_cast<double>(val);
5133 : }
5134 : };
5135 : #else
5136 :
5137 : #if defined(_MSC_VER) && defined(_M_X64)
5138 : #include <intrin.h>
5139 : #endif
5140 :
5141 : class GDALUInt128
5142 : {
5143 : GUIntBig low, high;
5144 :
5145 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5146 : {
5147 : }
5148 :
5149 : public:
5150 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5151 : {
5152 : #if defined(_MSC_VER) && defined(_M_X64)
5153 : GUIntBig highRes;
5154 : GUIntBig lowRes = _umul128(first, second, &highRes);
5155 : return GDALUInt128(lowRes, highRes);
5156 : #else
5157 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5158 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5159 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5160 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5161 : GUIntBig highRes = 0;
5162 : const GUIntBig firstLowSecondHigh =
5163 : static_cast<GUIntBig>(firstLow) * secondHigh;
5164 : const GUIntBig firstHighSecondLow =
5165 : static_cast<GUIntBig>(firstHigh) * secondLow;
5166 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5167 : if (middleTerm < firstLowSecondHigh) // check for overflow
5168 : highRes += static_cast<GUIntBig>(1) << 32;
5169 : const GUIntBig firstLowSecondLow =
5170 : static_cast<GUIntBig>(firstLow) * secondLow;
5171 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5172 : if (lowRes < firstLowSecondLow) // check for overflow
5173 : highRes++;
5174 : highRes +=
5175 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5176 : return GDALUInt128(lowRes, highRes);
5177 : #endif
5178 : }
5179 :
5180 : GDALUInt128 operator-(const GDALUInt128 &other) const
5181 : {
5182 : GUIntBig highRes = high - other.high;
5183 : GUIntBig lowRes = low - other.low;
5184 : if (lowRes > low) // check for underflow
5185 : --highRes;
5186 : return GDALUInt128(lowRes, highRes);
5187 : }
5188 :
5189 : operator double() const
5190 : {
5191 : const double twoPow64 = 18446744073709551616.0;
5192 : return high * twoPow64 + low;
5193 : }
5194 : };
5195 : #endif
5196 :
5197 : /************************************************************************/
5198 : /* ComputeStatisticsInternal() */
5199 : /************************************************************************/
5200 :
5201 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5202 : // not needed.
5203 : #define static_cast_for_coverity_scan static_cast
5204 :
5205 : // The rationale for below optimizations is detailed in statistics.txt
5206 :
5207 : // Use with T = GByte or GUInt16 only !
5208 : template <class T, bool COMPUTE_OTHER_STATS>
5209 : struct ComputeStatisticsInternalGeneric
5210 : {
5211 182 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5212 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5213 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5214 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5215 : {
5216 : static_assert(std::is_same<T, GByte>::value ||
5217 : std::is_same<T, GUInt16>::value,
5218 : "bad type for T");
5219 182 : if (bHasNoData)
5220 : {
5221 : // General case
5222 386 : for (int iY = 0; iY < nYCheck; iY++)
5223 : {
5224 81751 : for (int iX = 0; iX < nXCheck; iX++)
5225 : {
5226 81468 : const GPtrDiff_t iOffset =
5227 81468 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5228 81468 : const GUInt32 nValue = pData[iOffset];
5229 81468 : if (nValue == nNoDataValue)
5230 175 : continue;
5231 81293 : if (nValue < nMin)
5232 26 : nMin = nValue;
5233 81293 : if (nValue > nMax)
5234 57 : nMax = nValue;
5235 : if constexpr (COMPUTE_OTHER_STATS)
5236 : {
5237 79657 : nValidCount++;
5238 79657 : nSum += nValue;
5239 79657 : nSumSquare +=
5240 79657 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5241 79657 : nValue;
5242 : }
5243 : }
5244 : }
5245 : if constexpr (COMPUTE_OTHER_STATS)
5246 : {
5247 20 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5248 : }
5249 : }
5250 88 : else if (nMin == std::numeric_limits<T>::lowest() &&
5251 9 : nMax == std::numeric_limits<T>::max())
5252 : {
5253 : if constexpr (COMPUTE_OTHER_STATS)
5254 : {
5255 : // Optimization when there is no nodata and we know we have already
5256 : // reached the min and max
5257 208 : for (int iY = 0; iY < nYCheck; iY++)
5258 : {
5259 : int iX;
5260 1002 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5261 : {
5262 800 : const GPtrDiff_t iOffset =
5263 800 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5264 800 : const GUIntBig nValue = pData[iOffset];
5265 800 : const GUIntBig nValue2 = pData[iOffset + 1];
5266 800 : const GUIntBig nValue3 = pData[iOffset + 2];
5267 800 : const GUIntBig nValue4 = pData[iOffset + 3];
5268 800 : nSum += nValue;
5269 800 : nSumSquare += nValue * nValue;
5270 800 : nSum += nValue2;
5271 800 : nSumSquare += nValue2 * nValue2;
5272 800 : nSum += nValue3;
5273 800 : nSumSquare += nValue3 * nValue3;
5274 800 : nSum += nValue4;
5275 800 : nSumSquare += nValue4 * nValue4;
5276 : }
5277 207 : for (; iX < nXCheck; ++iX)
5278 : {
5279 5 : const GPtrDiff_t iOffset =
5280 5 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5281 5 : const GUIntBig nValue = pData[iOffset];
5282 5 : nSum += nValue;
5283 5 : nSumSquare += nValue * nValue;
5284 : }
5285 : }
5286 6 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5287 6 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5288 : }
5289 : }
5290 : else
5291 : {
5292 3366 : for (int iY = 0; iY < nYCheck; iY++)
5293 : {
5294 : int iX;
5295 635062 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5296 : {
5297 631769 : const GPtrDiff_t iOffset =
5298 631769 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5299 631769 : const GUInt32 nValue = pData[iOffset];
5300 631769 : const GUInt32 nValue2 = pData[iOffset + 1];
5301 631769 : if (nValue < nValue2)
5302 : {
5303 2160 : if (nValue < nMin)
5304 48 : nMin = nValue;
5305 2160 : if (nValue2 > nMax)
5306 108 : nMax = nValue2;
5307 : }
5308 : else
5309 : {
5310 629609 : if (nValue2 < nMin)
5311 61 : nMin = nValue2;
5312 629609 : if (nValue > nMax)
5313 212 : nMax = nValue;
5314 : }
5315 : if constexpr (COMPUTE_OTHER_STATS)
5316 : {
5317 624719 : nSum += nValue;
5318 624719 : nSumSquare +=
5319 624719 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5320 624719 : nValue;
5321 624719 : nSum += nValue2;
5322 624719 : nSumSquare +=
5323 624719 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5324 624719 : nValue2;
5325 : }
5326 : }
5327 3293 : if (iX < nXCheck)
5328 : {
5329 9 : const GPtrDiff_t iOffset =
5330 9 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5331 9 : const GUInt32 nValue = pData[iOffset];
5332 9 : if (nValue < nMin)
5333 6 : nMin = nValue;
5334 9 : if (nValue > nMax)
5335 6 : nMax = nValue;
5336 : if (COMPUTE_OTHER_STATS)
5337 : {
5338 9 : nSum += nValue;
5339 9 : nSumSquare +=
5340 9 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5341 9 : nValue;
5342 : }
5343 : }
5344 : }
5345 : if constexpr (COMPUTE_OTHER_STATS)
5346 : {
5347 28 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5348 28 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5349 : }
5350 : }
5351 182 : }
5352 : };
5353 :
5354 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5355 : // using 64bit accumulators in internal loops. This also slightly helps in
5356 : // 64bit mode.
5357 : template <bool COMPUTE_OTHER_STATS>
5358 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5359 : {
5360 11771 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5361 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5362 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5363 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5364 : {
5365 11771 : int nOuterLoops = nXCheck / 65536;
5366 11771 : if (nXCheck % 65536)
5367 11771 : nOuterLoops++;
5368 :
5369 11771 : if (bHasNoData)
5370 : {
5371 : // General case
5372 19547 : for (int iY = 0; iY < nYCheck; iY++)
5373 : {
5374 10937 : int iX = 0;
5375 21874 : for (int k = 0; k < nOuterLoops; k++)
5376 : {
5377 10937 : int iMax = iX + 65536;
5378 10937 : if (iMax > nXCheck)
5379 10937 : iMax = nXCheck;
5380 10937 : GUInt32 nSum32bit = 0;
5381 10937 : GUInt32 nSumSquare32bit = 0;
5382 10937 : GUInt32 nValidCount32bit = 0;
5383 10937 : GUInt32 nSampleCount32bit = 0;
5384 16705735 : for (; iX < iMax; iX++)
5385 : {
5386 16694886 : const GPtrDiff_t iOffset =
5387 16694886 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5388 16694886 : const GUInt32 nValue = pData[iOffset];
5389 :
5390 16694886 : nSampleCount32bit++;
5391 16694886 : if (nValue == nNoDataValue)
5392 16353432 : continue;
5393 341399 : if (nValue < nMin)
5394 343 : nMin = nValue;
5395 341399 : if (nValue > nMax)
5396 828 : nMax = nValue;
5397 : if constexpr (COMPUTE_OTHER_STATS)
5398 : {
5399 16954 : nValidCount32bit++;
5400 16954 : nSum32bit += nValue;
5401 16954 : nSumSquare32bit += nValue * nValue;
5402 : }
5403 : }
5404 : if constexpr (COMPUTE_OTHER_STATS)
5405 : {
5406 649 : nSampleCount += nSampleCount32bit;
5407 649 : nValidCount += nValidCount32bit;
5408 649 : nSum += nSum32bit;
5409 649 : nSumSquare += nSumSquare32bit;
5410 : }
5411 : }
5412 : }
5413 : }
5414 3161 : else if (nMin == 0 && nMax == 255)
5415 : {
5416 : if constexpr (COMPUTE_OTHER_STATS)
5417 : {
5418 : // Optimization when there is no nodata and we know we have already
5419 : // reached the min and max
5420 2644 : for (int iY = 0; iY < nYCheck; iY++)
5421 : {
5422 2617 : int iX = 0;
5423 5234 : for (int k = 0; k < nOuterLoops; k++)
5424 : {
5425 2617 : int iMax = iX + 65536;
5426 2617 : if (iMax > nXCheck)
5427 2617 : iMax = nXCheck;
5428 2617 : GUInt32 nSum32bit = 0;
5429 2617 : GUInt32 nSumSquare32bit = 0;
5430 176297 : for (; iX + 3 < iMax; iX += 4)
5431 : {
5432 173680 : const GPtrDiff_t iOffset =
5433 173680 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5434 173680 : const GUInt32 nValue = pData[iOffset];
5435 173680 : const GUInt32 nValue2 = pData[iOffset + 1];
5436 173680 : const GUInt32 nValue3 = pData[iOffset + 2];
5437 173680 : const GUInt32 nValue4 = pData[iOffset + 3];
5438 173680 : nSum32bit += nValue;
5439 173680 : nSumSquare32bit += nValue * nValue;
5440 173680 : nSum32bit += nValue2;
5441 173680 : nSumSquare32bit += nValue2 * nValue2;
5442 173680 : nSum32bit += nValue3;
5443 173680 : nSumSquare32bit += nValue3 * nValue3;
5444 173680 : nSum32bit += nValue4;
5445 173680 : nSumSquare32bit += nValue4 * nValue4;
5446 : }
5447 2617 : nSum += nSum32bit;
5448 2617 : nSumSquare += nSumSquare32bit;
5449 : }
5450 2620 : for (; iX < nXCheck; ++iX)
5451 : {
5452 3 : const GPtrDiff_t iOffset =
5453 3 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5454 3 : const GUIntBig nValue = pData[iOffset];
5455 3 : nSum += nValue;
5456 3 : nSumSquare += nValue * nValue;
5457 : }
5458 : }
5459 27 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5460 27 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5461 27 : }
5462 : }
5463 : else
5464 : {
5465 7930 : for (int iY = 0; iY < nYCheck; iY++)
5466 : {
5467 4796 : int iX = 0;
5468 9592 : for (int k = 0; k < nOuterLoops; k++)
5469 : {
5470 4796 : int iMax = iX + 65536;
5471 4796 : if (iMax > nXCheck)
5472 4796 : iMax = nXCheck;
5473 4796 : GUInt32 nSum32bit = 0;
5474 4796 : GUInt32 nSumSquare32bit = 0;
5475 161815 : for (; iX + 1 < iMax; iX += 2)
5476 : {
5477 157019 : const GPtrDiff_t iOffset =
5478 157019 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5479 157019 : const GUInt32 nValue = pData[iOffset];
5480 157019 : const GUInt32 nValue2 = pData[iOffset + 1];
5481 157019 : if (nValue < nValue2)
5482 : {
5483 9010 : if (nValue < nMin)
5484 254 : nMin = nValue;
5485 9010 : if (nValue2 > nMax)
5486 241 : nMax = nValue2;
5487 : }
5488 : else
5489 : {
5490 148009 : if (nValue2 < nMin)
5491 301 : nMin = nValue2;
5492 148009 : if (nValue > nMax)
5493 863 : nMax = nValue;
5494 : }
5495 : if constexpr (COMPUTE_OTHER_STATS)
5496 : {
5497 132599 : nSum32bit += nValue;
5498 132599 : nSumSquare32bit += nValue * nValue;
5499 132599 : nSum32bit += nValue2;
5500 132599 : nSumSquare32bit += nValue2 * nValue2;
5501 : }
5502 : }
5503 : if constexpr (COMPUTE_OTHER_STATS)
5504 : {
5505 1626 : nSum += nSum32bit;
5506 1626 : nSumSquare += nSumSquare32bit;
5507 : }
5508 : }
5509 4796 : if (iX < nXCheck)
5510 : {
5511 1384 : const GPtrDiff_t iOffset =
5512 1384 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5513 1384 : const GUInt32 nValue = pData[iOffset];
5514 1384 : if (nValue < nMin)
5515 39 : nMin = nValue;
5516 1384 : if (nValue > nMax)
5517 48 : nMax = nValue;
5518 : if constexpr (COMPUTE_OTHER_STATS)
5519 : {
5520 312 : nSum += nValue;
5521 312 : nSumSquare +=
5522 312 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5523 312 : nValue;
5524 : }
5525 : }
5526 : }
5527 : if constexpr (COMPUTE_OTHER_STATS)
5528 : {
5529 922 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5530 922 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5531 : }
5532 : }
5533 11771 : }
5534 : };
5535 :
5536 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5537 : {
5538 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5539 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5540 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5541 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5542 : {
5543 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5544 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5545 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5546 : }
5547 : };
5548 :
5549 : #if (defined(__x86_64__) || defined(_M_X64)) && \
5550 : (defined(__GNUC__) || defined(_MSC_VER))
5551 :
5552 : #include "gdal_avx2_emulation.hpp"
5553 :
5554 : #define ZERO256 GDALmm256_setzero_si256()
5555 :
5556 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5557 : static void
5558 19033 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5559 : // assumed to be aligned on 256 bits
5560 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5561 : GUIntBig &nSum, GUIntBig &nSumSquare,
5562 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5563 : {
5564 : // 32-byte alignment may not be enforced by linker, so do it at hand
5565 : GByte
5566 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5567 19033 : GByte *paby32ByteAligned =
5568 : aby32ByteUnaligned +
5569 19033 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5570 19033 : GByte *pabyMin = paby32ByteAligned;
5571 19033 : GByte *pabyMax = paby32ByteAligned + 32;
5572 19033 : GUInt32 *panSum =
5573 : COMPUTE_OTHER_STATS
5574 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5575 : : nullptr;
5576 19033 : GUInt32 *panSumSquare =
5577 : COMPUTE_OTHER_STATS
5578 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5579 : : nullptr;
5580 :
5581 19033 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5582 :
5583 19033 : GPtrDiff_t i = 0;
5584 : // Make sure that sumSquare can fit on uint32
5585 : // * 8 since we can hold 8 sums per vector register
5586 19033 : const int nMaxIterationsPerInnerLoop =
5587 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5588 19033 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5589 19033 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5590 19033 : nOuterLoops++;
5591 :
5592 : GDALm256i ymm_min =
5593 19033 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5594 19033 : GDALm256i ymm_max = ymm_min;
5595 19033 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5596 :
5597 38066 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5598 : {
5599 19033 : const auto iMax =
5600 19033 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5601 :
5602 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5603 19033 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5604 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5605 19033 : ZERO256; // holds 8 uint32 sums
5606 641852 : for (; i + 31 < iMax; i += 32)
5607 : {
5608 622819 : const GDALm256i ymm = GDALmm256_load_si256(
5609 622819 : reinterpret_cast<const GDALm256i *>(pData + i));
5610 : if (COMPUTE_MIN)
5611 : {
5612 164884 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5613 : }
5614 : if (COMPUTE_MAX)
5615 : {
5616 531878 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5617 : }
5618 :
5619 : if constexpr (COMPUTE_OTHER_STATS)
5620 : {
5621 : // Extract even-8bit values
5622 : const GDALm256i ymm_even =
5623 493495 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5624 : // Compute square of those 16 values as 32 bit result
5625 : // and add adjacent pairs
5626 : const GDALm256i ymm_even_square =
5627 493495 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5628 : // Add to the sumsquare accumulator
5629 : ymm_sumsquare =
5630 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5631 :
5632 : // Extract odd-8bit values
5633 493495 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5634 : const GDALm256i ymm_odd_square =
5635 493495 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5636 : ymm_sumsquare =
5637 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5638 :
5639 : // Now compute the sums
5640 493495 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5641 : GDALmm256_sad_epu8(ymm, ZERO256));
5642 : }
5643 : }
5644 :
5645 : if constexpr (COMPUTE_OTHER_STATS)
5646 : {
5647 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5648 : ymm_sum);
5649 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5650 : ymm_sumsquare);
5651 :
5652 10649 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5653 10649 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5654 10649 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5655 10649 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5656 : panSumSquare[7];
5657 : }
5658 : }
5659 :
5660 : if constexpr (COMPUTE_MIN)
5661 : {
5662 6061 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5663 : }
5664 : if constexpr (COMPUTE_MAX)
5665 : {
5666 15036 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5667 : }
5668 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5669 : {
5670 513678 : for (int j = 0; j < 32; j++)
5671 : {
5672 : if constexpr (COMPUTE_MIN)
5673 : {
5674 193952 : if (pabyMin[j] < nMin)
5675 1264 : nMin = pabyMin[j];
5676 : }
5677 : if constexpr (COMPUTE_MAX)
5678 : {
5679 481152 : if (pabyMax[j] > nMax)
5680 1817 : nMax = pabyMax[j];
5681 : }
5682 : }
5683 : }
5684 :
5685 211583 : for (; i < nBlockPixels; i++)
5686 : {
5687 192550 : const GUInt32 nValue = pData[i];
5688 : if constexpr (COMPUTE_MIN)
5689 : {
5690 66110 : if (nValue < nMin)
5691 1 : nMin = nValue;
5692 : }
5693 : if constexpr (COMPUTE_MAX)
5694 : {
5695 189775 : if (nValue > nMax)
5696 1167 : nMax = nValue;
5697 : }
5698 : if constexpr (COMPUTE_OTHER_STATS)
5699 : {
5700 77195 : nSum += nValue;
5701 77195 : nSumSquare +=
5702 77195 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5703 : }
5704 : }
5705 :
5706 : if constexpr (COMPUTE_OTHER_STATS)
5707 : {
5708 10649 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5709 10649 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5710 : }
5711 19033 : }
5712 :
5713 : // SSE2/AVX2 optimization for GByte case
5714 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5715 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5716 : // there are strictly equivalent to 2 parallel SSE2 streams.
5717 : template <bool COMPUTE_OTHER_STATS>
5718 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5719 : {
5720 28117 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5721 : // assumed to be aligned on 256 bits
5722 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5723 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5724 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5725 : GUIntBig &nValidCount)
5726 : {
5727 28117 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5728 28117 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5729 9352 : nMin <= nMax)
5730 : {
5731 : // 32-byte alignment may not be enforced by linker, so do it at hand
5732 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5733 1240 : GByte *paby32ByteAligned =
5734 : aby32ByteUnaligned +
5735 1240 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5736 1240 : GByte *pabyMin = paby32ByteAligned;
5737 1240 : GByte *pabyMax = paby32ByteAligned + 32;
5738 1240 : GUInt32 *panSum =
5739 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5740 1240 : GUInt32 *panSumSquare =
5741 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5742 :
5743 1240 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5744 :
5745 1240 : GPtrDiff_t i = 0;
5746 : // Make sure that sumSquare can fit on uint32
5747 : // * 8 since we can hold 8 sums per vector register
5748 1240 : const int nMaxIterationsPerInnerLoop =
5749 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5750 1240 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5751 1240 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5752 1240 : nOuterLoops++;
5753 :
5754 : const GDALm256i ymm_nodata =
5755 1240 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5756 : // any non noData value in [min,max] would do.
5757 : const GDALm256i ymm_neutral =
5758 1240 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5759 1240 : GDALm256i ymm_min = ymm_neutral;
5760 1240 : GDALm256i ymm_max = ymm_neutral;
5761 : [[maybe_unused]] const auto ymm_mask_8bits =
5762 1240 : GDALmm256_set1_epi16(0xFF);
5763 :
5764 1240 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5765 1240 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5766 1240 : const bool bComputeMinMax =
5767 1240 : nMin > nMinThreshold || nMax < nMaxThreshold;
5768 :
5769 2480 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5770 : {
5771 1240 : const auto iMax =
5772 1240 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5773 :
5774 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5775 1240 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5776 : // holds 8 uint32 sums
5777 1240 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5778 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5779 1240 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5780 1240 : const auto iInit = i;
5781 13799 : for (; i + 31 < iMax; i += 32)
5782 : {
5783 12559 : const GDALm256i ymm = GDALmm256_load_si256(
5784 12559 : reinterpret_cast<const GDALm256i *>(pData + i));
5785 :
5786 : // Check which values are nodata
5787 : const GDALm256i ymm_eq_nodata =
5788 12559 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5789 : if constexpr (COMPUTE_OTHER_STATS)
5790 : {
5791 : // Count how many values are nodata (due to cmpeq
5792 : // putting 255 when condition is met, this will actually
5793 : // be 255 times the number of nodata value, spread in 4
5794 : // 64 bits words). We can use add_epi32 as the counter
5795 : // will not overflow uint32
5796 4514 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5797 : ymm_count_nodata_mul_255,
5798 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5799 : }
5800 : // Replace all nodata values by zero for the purpose of sum
5801 : // and sumquare.
5802 : const GDALm256i ymm_nodata_by_zero =
5803 12559 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5804 12559 : if (bComputeMinMax)
5805 : {
5806 : // Replace all nodata values by a neutral value for the
5807 : // purpose of min and max.
5808 : const GDALm256i ymm_nodata_by_neutral =
5809 8174 : GDALmm256_or_si256(
5810 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5811 : ymm_nodata_by_zero);
5812 :
5813 : ymm_min =
5814 8174 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5815 : ymm_max =
5816 8174 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
5817 : }
5818 :
5819 : if constexpr (COMPUTE_OTHER_STATS)
5820 : {
5821 : // Extract even-8bit values
5822 4514 : const GDALm256i ymm_even = GDALmm256_and_si256(
5823 : ymm_nodata_by_zero, ymm_mask_8bits);
5824 : // Compute square of those 16 values as 32 bit result
5825 : // and add adjacent pairs
5826 : const GDALm256i ymm_even_square =
5827 4514 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5828 : // Add to the sumsquare accumulator
5829 : ymm_sumsquare =
5830 4514 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5831 :
5832 : // Extract odd-8bit values
5833 : const GDALm256i ymm_odd =
5834 4514 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
5835 : const GDALm256i ymm_odd_square =
5836 4514 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5837 : ymm_sumsquare =
5838 4514 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5839 :
5840 : // Now compute the sums
5841 4514 : ymm_sum = GDALmm256_add_epi32(
5842 : ymm_sum,
5843 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
5844 : }
5845 : }
5846 :
5847 : if constexpr (COMPUTE_OTHER_STATS)
5848 : {
5849 33 : GUInt32 *panCoutNoDataMul255 = panSum;
5850 33 : GDALmm256_store_si256(
5851 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
5852 : ymm_count_nodata_mul_255);
5853 :
5854 33 : nSampleCount += (i - iInit);
5855 :
5856 33 : nValidCount +=
5857 33 : (i - iInit) -
5858 33 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
5859 33 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
5860 : 255;
5861 :
5862 33 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5863 : ymm_sum);
5864 33 : GDALmm256_store_si256(
5865 : reinterpret_cast<GDALm256i *>(panSumSquare),
5866 : ymm_sumsquare);
5867 33 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5868 33 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5869 33 : panSumSquare[1] + panSumSquare[2] +
5870 33 : panSumSquare[3] + panSumSquare[4] +
5871 33 : panSumSquare[5] + panSumSquare[6] +
5872 : panSumSquare[7];
5873 : }
5874 : }
5875 :
5876 1240 : if (bComputeMinMax)
5877 : {
5878 1209 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
5879 : ymm_min);
5880 1209 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
5881 : ymm_max);
5882 39897 : for (int j = 0; j < 32; j++)
5883 : {
5884 38688 : if (pabyMin[j] < nMin)
5885 32 : nMin = pabyMin[j];
5886 38688 : if (pabyMax[j] > nMax)
5887 157 : nMax = pabyMax[j];
5888 : }
5889 : }
5890 :
5891 : if constexpr (COMPUTE_OTHER_STATS)
5892 : {
5893 33 : nSampleCount += nBlockPixels - i;
5894 : }
5895 29810 : for (; i < nBlockPixels; i++)
5896 : {
5897 28570 : const GUInt32 nValue = pData[i];
5898 28570 : if (nValue == nNoDataValue)
5899 24923 : continue;
5900 3647 : if (nValue < nMin)
5901 1 : nMin = nValue;
5902 3647 : if (nValue > nMax)
5903 13 : nMax = nValue;
5904 : if constexpr (COMPUTE_OTHER_STATS)
5905 : {
5906 110 : nValidCount++;
5907 110 : nSum += nValue;
5908 110 : nSumSquare +=
5909 110 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5910 110 : nValue;
5911 : }
5912 1240 : }
5913 : }
5914 26877 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
5915 : {
5916 15077 : if (nMin > 0)
5917 : {
5918 2105 : if (nMax < 255)
5919 : {
5920 : ComputeStatisticsByteNoNodata<true, true,
5921 1575 : COMPUTE_OTHER_STATS>(
5922 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5923 : nSampleCount, nValidCount);
5924 : }
5925 : else
5926 : {
5927 : ComputeStatisticsByteNoNodata<true, false,
5928 530 : COMPUTE_OTHER_STATS>(
5929 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5930 : nSampleCount, nValidCount);
5931 : }
5932 : }
5933 : else
5934 : {
5935 12972 : if (nMax < 255)
5936 : {
5937 : ComputeStatisticsByteNoNodata<false, true,
5938 9505 : COMPUTE_OTHER_STATS>(
5939 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5940 : nSampleCount, nValidCount);
5941 : }
5942 : else
5943 : {
5944 : ComputeStatisticsByteNoNodata<false, false,
5945 3467 : COMPUTE_OTHER_STATS>(
5946 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5947 : nSampleCount, nValidCount);
5948 : }
5949 : }
5950 : }
5951 10533 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
5952 27 : (nBlockXSize % 32) == 0)
5953 : {
5954 3983 : for (int iY = 0; iY < nYCheck; iY++)
5955 : {
5956 3956 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
5957 3956 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
5958 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5959 27 : }
5960 : }
5961 : else
5962 : {
5963 11773 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
5964 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5965 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5966 : }
5967 28119 : }
5968 : };
5969 :
5970 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
5971 404 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
5972 : GUIntBig i)
5973 : {
5974 404 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
5975 404 : }
5976 :
5977 : // AVX2/SSE2 optimization for GUInt16 case
5978 : template <bool COMPUTE_OTHER_STATS>
5979 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
5980 : {
5981 1348 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5982 : // assumed to be aligned on 128 bits
5983 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
5984 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5985 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5986 : GUIntBig &nValidCount)
5987 : {
5988 1348 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5989 1348 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
5990 : {
5991 1166 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
5992 :
5993 1166 : GPtrDiff_t i = 0;
5994 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
5995 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
5996 : // Furthermore the shift is also needed to use madd_epi16
5997 1166 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
5998 1166 : GDALm256i ymm_min = GDALmm256_load_si256(
5999 1166 : reinterpret_cast<const GDALm256i *>(pData + i));
6000 1166 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6001 1166 : GDALm256i ymm_max = ymm_min;
6002 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6003 1166 : ZERO256; // holds 4 uint64 sums
6004 :
6005 : // Make sure that sum can fit on uint32
6006 : // * 8 since we can hold 8 sums per vector register
6007 1166 : const int nMaxIterationsPerInnerLoop =
6008 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6009 1166 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6010 1166 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6011 1166 : nOuterLoops++;
6012 :
6013 1166 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6014 : [[maybe_unused]] const auto ymm_mask_16bits =
6015 1166 : GDALmm256_set1_epi32(0xFFFF);
6016 : [[maybe_unused]] const auto ymm_mask_32bits =
6017 1166 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6018 :
6019 1166 : GUIntBig nSumThis = 0;
6020 2356 : for (int k = 0; k < nOuterLoops; k++)
6021 : {
6022 1190 : const auto iMax =
6023 1190 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6024 :
6025 : [[maybe_unused]] GDALm256i ymm_sum =
6026 1190 : ZERO256; // holds 8 uint32 sums
6027 959522 : for (; i + 15 < iMax; i += 16)
6028 : {
6029 958332 : const GDALm256i ymm = GDALmm256_load_si256(
6030 958332 : reinterpret_cast<const GDALm256i *>(pData + i));
6031 : const GDALm256i ymm_shifted =
6032 958332 : GDALmm256_add_epi16(ymm, ymm_m32768);
6033 958332 : if (bComputeMinMax)
6034 : {
6035 949313 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6036 949313 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6037 : }
6038 :
6039 : if constexpr (COMPUTE_OTHER_STATS)
6040 : {
6041 : // Note: the int32 range can overflow for (0-32768)^2 +
6042 : // (0-32768)^2 = 0x80000000, but as we know the result
6043 : // is positive, this is OK as we interpret is a uint32.
6044 : const GDALm256i ymm_square =
6045 99506 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6046 99506 : ymm_sumsquare = GDALmm256_add_epi64(
6047 : ymm_sumsquare,
6048 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6049 99506 : ymm_sumsquare = GDALmm256_add_epi64(
6050 : ymm_sumsquare,
6051 : GDALmm256_srli_epi64(ymm_square, 32));
6052 :
6053 : // Now compute the sums
6054 99506 : ymm_sum = GDALmm256_add_epi32(
6055 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6056 99506 : ymm_sum = GDALmm256_add_epi32(
6057 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6058 : }
6059 : }
6060 :
6061 : if constexpr (COMPUTE_OTHER_STATS)
6062 : {
6063 : GUInt32 anSum[8];
6064 404 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6065 : ymm_sum);
6066 404 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6067 404 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6068 404 : anSum[6] + anSum[7];
6069 : }
6070 : }
6071 :
6072 1166 : if (bComputeMinMax)
6073 : {
6074 : GUInt16 anMin[16];
6075 : GUInt16 anMax[16];
6076 :
6077 : // Unshift the result
6078 1125 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6079 1125 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6080 1125 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6081 : ymm_min);
6082 1125 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6083 : ymm_max);
6084 19125 : for (int j = 0; j < 16; j++)
6085 : {
6086 18000 : if (anMin[j] < nMin)
6087 344 : nMin = anMin[j];
6088 18000 : if (anMax[j] > nMax)
6089 482 : nMax = anMax[j];
6090 : }
6091 : }
6092 :
6093 : if constexpr (COMPUTE_OTHER_STATS)
6094 : {
6095 : GUIntBig anSumSquare[4];
6096 404 : GDALmm256_storeu_si256(
6097 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6098 404 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6099 : anSumSquare[3];
6100 :
6101 : // Unshift the sum of squares
6102 404 : UnshiftSumSquare(nSumSquare, nSumThis,
6103 : static_cast<GUIntBig>(i));
6104 :
6105 404 : nSum += nSumThis;
6106 :
6107 726 : for (; i < nBlockPixels; i++)
6108 : {
6109 322 : const GUInt32 nValue = pData[i];
6110 322 : if (nValue < nMin)
6111 1 : nMin = nValue;
6112 322 : if (nValue > nMax)
6113 1 : nMax = nValue;
6114 322 : nSum += nValue;
6115 322 : nSumSquare +=
6116 322 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6117 322 : nValue;
6118 : }
6119 :
6120 404 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6121 404 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6122 1166 : }
6123 : }
6124 : else
6125 : {
6126 182 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6127 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6128 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6129 : }
6130 1348 : }
6131 : };
6132 :
6133 : #endif
6134 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6135 : // defined(_MSC_VER))
6136 :
6137 : /************************************************************************/
6138 : /* GetPixelValue() */
6139 : /************************************************************************/
6140 :
6141 23166200 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6142 : const void *pData, GPtrDiff_t iOffset,
6143 : const GDALNoDataValues &sNoDataValues,
6144 : bool &bValid)
6145 : {
6146 23166200 : bValid = true;
6147 23166200 : double dfValue = 0;
6148 23166200 : switch (eDataType)
6149 : {
6150 1413680 : case GDT_Byte:
6151 : {
6152 1413680 : if (bSignedByte)
6153 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6154 : else
6155 1413490 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6156 1413680 : break;
6157 : }
6158 10405 : case GDT_Int8:
6159 10405 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6160 10405 : break;
6161 4000 : case GDT_UInt16:
6162 4000 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6163 4000 : break;
6164 60192 : case GDT_Int16:
6165 60192 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6166 60192 : break;
6167 27596 : case GDT_UInt32:
6168 27596 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6169 27596 : break;
6170 460170 : case GDT_Int32:
6171 460170 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6172 460170 : break;
6173 2598 : case GDT_UInt64:
6174 2598 : dfValue = static_cast<double>(
6175 2598 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6176 2598 : break;
6177 7398 : case GDT_Int64:
6178 7398 : dfValue = static_cast<double>(
6179 7398 : static_cast<const std::int64_t *>(pData)[iOffset]);
6180 7398 : break;
6181 0 : case GDT_Float16:
6182 : {
6183 0 : const GFloat16 hfValue =
6184 0 : static_cast<const GFloat16 *>(pData)[iOffset];
6185 0 : if (CPLIsNan(hfValue) ||
6186 0 : (sNoDataValues.bGotFloat16NoDataValue &&
6187 0 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6188 : {
6189 0 : bValid = false;
6190 0 : return 0.0;
6191 : }
6192 0 : dfValue = hfValue;
6193 0 : return dfValue;
6194 : }
6195 17483400 : case GDT_Float32:
6196 : {
6197 17483400 : const float fValue = static_cast<const float *>(pData)[iOffset];
6198 34939900 : if (CPLIsNan(fValue) ||
6199 30666600 : (sNoDataValues.bGotFloatNoDataValue &&
6200 13210000 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6201 : {
6202 119863 : bValid = false;
6203 119863 : return 0.0;
6204 : }
6205 17363500 : dfValue = fValue;
6206 17363500 : return dfValue;
6207 : }
6208 3679660 : case GDT_Float64:
6209 3679660 : dfValue = static_cast<const double *>(pData)[iOffset];
6210 3679660 : if (std::isnan(dfValue))
6211 : {
6212 52 : bValid = false;
6213 52 : return 0.0;
6214 : }
6215 3679600 : break;
6216 2692 : case GDT_CInt16:
6217 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6218 2692 : break;
6219 2692 : case GDT_CInt32:
6220 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6221 2692 : break;
6222 0 : case GDT_CFloat16:
6223 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6224 0 : if (isnan(dfValue))
6225 : {
6226 0 : bValid = false;
6227 0 : return 0.0;
6228 : }
6229 0 : break;
6230 5812 : case GDT_CFloat32:
6231 5812 : dfValue = static_cast<const float *>(pData)[iOffset * 2];
6232 5812 : if (std::isnan(dfValue))
6233 : {
6234 0 : bValid = false;
6235 0 : return 0.0;
6236 : }
6237 5812 : break;
6238 5892 : case GDT_CFloat64:
6239 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6240 5892 : if (std::isnan(dfValue))
6241 : {
6242 0 : bValid = false;
6243 0 : return 0.0;
6244 : }
6245 5892 : break;
6246 0 : case GDT_Unknown:
6247 : case GDT_TypeCount:
6248 0 : CPLAssert(false);
6249 : break;
6250 : }
6251 :
6252 9427180 : if (sNoDataValues.bGotNoDataValue &&
6253 3744450 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6254 : {
6255 3346220 : bValid = false;
6256 3346220 : return 0.0;
6257 : }
6258 2336510 : return dfValue;
6259 : }
6260 :
6261 : /************************************************************************/
6262 : /* SetValidPercent() */
6263 : /************************************************************************/
6264 :
6265 : //! @cond Doxygen_Suppress
6266 : /**
6267 : * \brief Set percentage of valid (not nodata) pixels.
6268 : *
6269 : * Stores the percentage of valid pixels in the metadata item
6270 : * STATISTICS_VALID_PERCENT
6271 : *
6272 : * @param nSampleCount Number of sampled pixels.
6273 : *
6274 : * @param nValidCount Number of valid pixels.
6275 : */
6276 :
6277 467 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6278 : GUIntBig nValidCount)
6279 : {
6280 467 : if (nValidCount == 0)
6281 : {
6282 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6283 : }
6284 455 : else if (nValidCount == nSampleCount)
6285 : {
6286 412 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6287 : }
6288 : else /* nValidCount < nSampleCount */
6289 : {
6290 43 : char szValue[128] = {0};
6291 :
6292 : /* percentage is only an indicator: limit precision */
6293 43 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6294 43 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6295 :
6296 43 : if (EQUAL(szValue, "100"))
6297 : {
6298 : /* don't set 100 percent valid
6299 : * because some of the sampled pixels were nodata */
6300 0 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6301 : }
6302 : else
6303 : {
6304 43 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6305 : }
6306 : }
6307 468 : }
6308 :
6309 : //! @endcond
6310 :
6311 : /************************************************************************/
6312 : /* ComputeStatistics() */
6313 : /************************************************************************/
6314 :
6315 : /**
6316 : * \brief Compute image statistics.
6317 : *
6318 : * Returns the minimum, maximum, mean and standard deviation of all
6319 : * pixel values in this band. If approximate statistics are sufficient,
6320 : * the bApproxOK flag can be set to true in which case overviews, or a
6321 : * subset of image tiles may be used in computing the statistics.
6322 : *
6323 : * Once computed, the statistics will generally be "set" back on the
6324 : * raster band using SetStatistics().
6325 : *
6326 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6327 : *
6328 : * This method is the same as the C function GDALComputeRasterStatistics().
6329 : *
6330 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6331 : * or a subset of all tiles.
6332 : *
6333 : * @param pdfMin Location into which to load image minimum (may be NULL).
6334 : *
6335 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6336 : *
6337 : * @param pdfMean Location into which to load image mean (may be NULL).
6338 : *
6339 : * @param pdfStdDev Location into which to load image standard deviation
6340 : * (may be NULL).
6341 : *
6342 : * @param pfnProgress a function to call to report progress, or NULL.
6343 : *
6344 : * @param pProgressData application data to pass to the progress function.
6345 : *
6346 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6347 : * is terminated by the user.
6348 : */
6349 :
6350 451 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6351 : double *pdfMax, double *pdfMean,
6352 : double *pdfStdDev,
6353 : GDALProgressFunc pfnProgress,
6354 : void *pProgressData)
6355 :
6356 : {
6357 451 : if (pfnProgress == nullptr)
6358 155 : pfnProgress = GDALDummyProgress;
6359 :
6360 : /* -------------------------------------------------------------------- */
6361 : /* If we have overview bands, use them for statistics. */
6362 : /* -------------------------------------------------------------------- */
6363 451 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6364 : {
6365 : GDALRasterBand *poBand =
6366 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6367 :
6368 3 : if (poBand != this)
6369 : {
6370 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6371 : pdfMean, pdfStdDev,
6372 3 : pfnProgress, pProgressData);
6373 3 : if (eErr == CE_None)
6374 : {
6375 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6376 : {
6377 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6378 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6379 : }
6380 :
6381 : /* transfer metadata from overview band to this */
6382 : const char *pszPercentValid =
6383 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6384 :
6385 3 : if (pszPercentValid != nullptr)
6386 : {
6387 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6388 3 : pszPercentValid);
6389 : }
6390 : }
6391 3 : return eErr;
6392 : }
6393 : }
6394 :
6395 448 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6396 : {
6397 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6398 0 : return CE_Failure;
6399 : }
6400 :
6401 : /* -------------------------------------------------------------------- */
6402 : /* Read actual data and compute statistics. */
6403 : /* -------------------------------------------------------------------- */
6404 : // Using Welford algorithm:
6405 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6406 : // to compute standard deviation in a more numerically robust way than
6407 : // the difference of the sum of square values with the square of the sum.
6408 : // dfMean and dfM2 are updated at each sample.
6409 : // dfM2 is the sum of square of differences to the current mean.
6410 448 : double dfMin = std::numeric_limits<double>::max();
6411 448 : double dfMax = -std::numeric_limits<double>::max();
6412 448 : double dfMean = 0.0;
6413 448 : double dfM2 = 0.0;
6414 :
6415 : GDALRasterIOExtraArg sExtraArg;
6416 448 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6417 :
6418 448 : GDALNoDataValues sNoDataValues(this, eDataType);
6419 448 : GDALRasterBand *poMaskBand = nullptr;
6420 448 : if (!sNoDataValues.bGotNoDataValue)
6421 : {
6422 423 : const int l_nMaskFlags = GetMaskFlags();
6423 439 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
6424 16 : GetColorInterpretation() != GCI_AlphaBand)
6425 : {
6426 16 : poMaskBand = GetMaskBand();
6427 : }
6428 : }
6429 :
6430 448 : bool bSignedByte = false;
6431 448 : if (eDataType == GDT_Byte)
6432 : {
6433 196 : EnablePixelTypeSignedByteWarning(false);
6434 : const char *pszPixelType =
6435 196 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6436 196 : EnablePixelTypeSignedByteWarning(true);
6437 196 : bSignedByte =
6438 196 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6439 : }
6440 :
6441 448 : GUIntBig nSampleCount = 0;
6442 448 : GUIntBig nValidCount = 0;
6443 :
6444 448 : if (bApproxOK && HasArbitraryOverviews())
6445 : {
6446 : /* --------------------------------------------------------------------
6447 : */
6448 : /* Figure out how much the image should be reduced to get an */
6449 : /* approximate value. */
6450 : /* --------------------------------------------------------------------
6451 : */
6452 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6453 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6454 :
6455 0 : int nXReduced = nRasterXSize;
6456 0 : int nYReduced = nRasterYSize;
6457 0 : if (dfReduction > 1.0)
6458 : {
6459 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6460 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6461 :
6462 : // Catch the case of huge resizing ratios here
6463 0 : if (nXReduced == 0)
6464 0 : nXReduced = 1;
6465 0 : if (nYReduced == 0)
6466 0 : nYReduced = 1;
6467 : }
6468 :
6469 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
6470 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6471 :
6472 : const CPLErr eErr =
6473 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6474 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6475 0 : if (eErr != CE_None)
6476 : {
6477 0 : CPLFree(pData);
6478 0 : return eErr;
6479 : }
6480 :
6481 0 : GByte *pabyMaskData = nullptr;
6482 0 : if (poMaskBand)
6483 : {
6484 : pabyMaskData =
6485 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6486 0 : if (!pabyMaskData)
6487 : {
6488 0 : CPLFree(pData);
6489 0 : return CE_Failure;
6490 : }
6491 :
6492 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6493 : pabyMaskData, nXReduced, nYReduced,
6494 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
6495 : {
6496 0 : CPLFree(pData);
6497 0 : CPLFree(pabyMaskData);
6498 0 : return CE_Failure;
6499 : }
6500 : }
6501 :
6502 : /* this isn't the fastest way to do this, but is easier for now */
6503 0 : for (int iY = 0; iY < nYReduced; iY++)
6504 : {
6505 0 : for (int iX = 0; iX < nXReduced; iX++)
6506 : {
6507 0 : const int iOffset = iX + iY * nXReduced;
6508 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6509 0 : continue;
6510 :
6511 0 : bool bValid = true;
6512 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
6513 0 : iOffset, sNoDataValues, bValid);
6514 0 : if (!bValid)
6515 0 : continue;
6516 :
6517 0 : dfMin = std::min(dfMin, dfValue);
6518 0 : dfMax = std::max(dfMax, dfValue);
6519 :
6520 0 : nValidCount++;
6521 0 : const double dfDelta = dfValue - dfMean;
6522 0 : dfMean += dfDelta / nValidCount;
6523 0 : dfM2 += dfDelta * (dfValue - dfMean);
6524 : }
6525 : }
6526 :
6527 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6528 :
6529 0 : CPLFree(pData);
6530 0 : CPLFree(pabyMaskData);
6531 : }
6532 :
6533 : else // No arbitrary overviews.
6534 : {
6535 448 : if (!InitBlockInfo())
6536 0 : return CE_Failure;
6537 :
6538 : /* --------------------------------------------------------------------
6539 : */
6540 : /* Figure out the ratio of blocks we will read to get an */
6541 : /* approximate value. */
6542 : /* --------------------------------------------------------------------
6543 : */
6544 448 : int nSampleRate = 1;
6545 448 : if (bApproxOK)
6546 : {
6547 41 : nSampleRate = static_cast<int>(std::max(
6548 82 : 1.0,
6549 41 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6550 : // We want to avoid probing only the first column of blocks for
6551 : // a square shaped raster, because it is not unlikely that it may
6552 : // be padding only (#6378)
6553 41 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6554 2 : nSampleRate += 1;
6555 : }
6556 448 : if (nSampleRate == 1)
6557 414 : bApproxOK = false;
6558 :
6559 : // Particular case for GDT_Byte that only use integral types for all
6560 : // intermediate computations. Only possible if the number of pixels
6561 : // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6562 : // can fit on a uint64. Should be 99.99999% of cases.
6563 : // For GUInt16, this limits to raster of 4 giga pixels
6564 448 : if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6565 181 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6566 181 : nSampleRate <
6567 181 : GUINTBIG_MAX / (255U * 255U) /
6568 181 : (static_cast<GUInt64>(nBlockXSize) *
6569 181 : static_cast<GUInt64>(nBlockYSize))) ||
6570 267 : (eDataType == GDT_UInt16 &&
6571 29 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6572 29 : nSampleRate <
6573 29 : GUINTBIG_MAX / (65535U * 65535U) /
6574 29 : (static_cast<GUInt64>(nBlockXSize) *
6575 29 : static_cast<GUInt64>(nBlockYSize))))
6576 : {
6577 210 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6578 210 : GUInt32 nMin = nMaxValueType;
6579 210 : GUInt32 nMax = 0;
6580 210 : GUIntBig nSum = 0;
6581 210 : GUIntBig nSumSquare = 0;
6582 : // If no valid nodata, map to invalid value (256 for Byte)
6583 210 : const GUInt32 nNoDataValue =
6584 231 : (sNoDataValues.bGotNoDataValue &&
6585 21 : sNoDataValues.dfNoDataValue >= 0 &&
6586 21 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
6587 21 : fabs(sNoDataValues.dfNoDataValue -
6588 21 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
6589 : 1e-10)) < 1e-10)
6590 231 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
6591 : : nMaxValueType + 1;
6592 :
6593 210 : for (GIntBig iSampleBlock = 0;
6594 12615 : iSampleBlock <
6595 12615 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6596 12405 : iSampleBlock += nSampleRate)
6597 : {
6598 12405 : const int iYBlock =
6599 12405 : static_cast<int>(iSampleBlock / nBlocksPerRow);
6600 12405 : const int iXBlock =
6601 12405 : static_cast<int>(iSampleBlock % nBlocksPerRow);
6602 :
6603 : GDALRasterBlock *const poBlock =
6604 12405 : GetLockedBlockRef(iXBlock, iYBlock);
6605 12407 : if (poBlock == nullptr)
6606 0 : return CE_Failure;
6607 :
6608 12407 : void *const pData = poBlock->GetDataRef();
6609 :
6610 12406 : int nXCheck = 0, nYCheck = 0;
6611 12406 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6612 :
6613 12405 : if (eDataType == GDT_Byte)
6614 : {
6615 : ComputeStatisticsInternal<
6616 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
6617 11947 : f(nXCheck, nBlockXSize, nYCheck,
6618 : static_cast<const GByte *>(pData),
6619 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6620 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6621 : }
6622 : else
6623 : {
6624 : ComputeStatisticsInternal<
6625 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6626 458 : f(nXCheck, nBlockXSize, nYCheck,
6627 : static_cast<const GUInt16 *>(pData),
6628 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6629 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6630 : }
6631 :
6632 12409 : poBlock->DropLock();
6633 :
6634 12406 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
6635 12408 : (static_cast<double>(nBlocksPerRow) *
6636 12408 : nBlocksPerColumn),
6637 : "Compute Statistics", pProgressData))
6638 : {
6639 1 : ReportError(CE_Failure, CPLE_UserInterrupt,
6640 : "User terminated");
6641 0 : return CE_Failure;
6642 : }
6643 : }
6644 :
6645 210 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6646 : {
6647 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6648 0 : return CE_Failure;
6649 : }
6650 :
6651 : /* --------------------------------------------------------------------
6652 : */
6653 : /* Save computed information. */
6654 : /* --------------------------------------------------------------------
6655 : */
6656 210 : if (nValidCount)
6657 201 : dfMean = static_cast<double>(nSum) / nValidCount;
6658 :
6659 : // To avoid potential precision issues when doing the difference,
6660 : // we need to do that computation on 128 bit rather than casting
6661 : // to double
6662 : const GDALUInt128 nTmpForStdDev(
6663 210 : GDALUInt128::Mul(nSumSquare, nValidCount) -
6664 420 : GDALUInt128::Mul(nSum, nSum));
6665 : const double dfStdDev =
6666 210 : nValidCount > 0
6667 210 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6668 210 : : 0.0;
6669 :
6670 210 : if (nValidCount > 0)
6671 : {
6672 200 : if (bApproxOK)
6673 : {
6674 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6675 : }
6676 176 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6677 : {
6678 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6679 : }
6680 201 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
6681 : }
6682 :
6683 211 : SetValidPercent(nSampleCount, nValidCount);
6684 :
6685 : /* --------------------------------------------------------------------
6686 : */
6687 : /* Record results. */
6688 : /* --------------------------------------------------------------------
6689 : */
6690 210 : if (pdfMin != nullptr)
6691 207 : *pdfMin = nValidCount ? nMin : 0;
6692 210 : if (pdfMax != nullptr)
6693 207 : *pdfMax = nValidCount ? nMax : 0;
6694 :
6695 210 : if (pdfMean != nullptr)
6696 203 : *pdfMean = dfMean;
6697 :
6698 210 : if (pdfStdDev != nullptr)
6699 203 : *pdfStdDev = dfStdDev;
6700 :
6701 210 : if (nValidCount > 0)
6702 201 : return CE_None;
6703 :
6704 9 : ReportError(CE_Failure, CPLE_AppDefined,
6705 : "Failed to compute statistics, no valid pixels found "
6706 : "in sampling.");
6707 9 : return CE_Failure;
6708 : }
6709 :
6710 238 : GByte *pabyMaskData = nullptr;
6711 238 : if (poMaskBand)
6712 : {
6713 : pabyMaskData = static_cast<GByte *>(
6714 16 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6715 16 : if (!pabyMaskData)
6716 : {
6717 0 : return CE_Failure;
6718 : }
6719 : }
6720 :
6721 238 : for (GIntBig iSampleBlock = 0;
6722 5489 : iSampleBlock <
6723 5489 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6724 5251 : iSampleBlock += nSampleRate)
6725 : {
6726 5251 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6727 5251 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6728 :
6729 : GDALRasterBlock *const poBlock =
6730 5251 : GetLockedBlockRef(iXBlock, iYBlock);
6731 5251 : if (poBlock == nullptr)
6732 : {
6733 0 : CPLFree(pabyMaskData);
6734 0 : return CE_Failure;
6735 : }
6736 :
6737 5251 : void *const pData = poBlock->GetDataRef();
6738 :
6739 5251 : int nXCheck = 0, nYCheck = 0;
6740 5251 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6741 :
6742 5352 : if (poMaskBand &&
6743 101 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6744 101 : iYBlock * nBlockYSize, nXCheck, nYCheck,
6745 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6746 101 : 0, nBlockXSize, nullptr) != CE_None)
6747 : {
6748 0 : CPLFree(pabyMaskData);
6749 0 : poBlock->DropLock();
6750 0 : return CE_Failure;
6751 : }
6752 :
6753 : // This isn't the fastest way to do this, but is easier for now.
6754 10686 : for (int iY = 0; iY < nYCheck; iY++)
6755 : {
6756 4342140 : for (int iX = 0; iX < nXCheck; iX++)
6757 : {
6758 4336710 : const GPtrDiff_t iOffset =
6759 4336710 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6760 4336710 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6761 109941 : continue;
6762 :
6763 4326840 : bool bValid = true;
6764 : double dfValue =
6765 4326840 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6766 4326840 : sNoDataValues, bValid);
6767 :
6768 4326840 : if (!bValid)
6769 100070 : continue;
6770 :
6771 4226770 : dfMin = std::min(dfMin, dfValue);
6772 4226770 : dfMax = std::max(dfMax, dfValue);
6773 :
6774 4226770 : nValidCount++;
6775 4226770 : const double dfDelta = dfValue - dfMean;
6776 4226770 : dfMean += dfDelta / nValidCount;
6777 4226770 : dfM2 += dfDelta * (dfValue - dfMean);
6778 : }
6779 : }
6780 :
6781 5251 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6782 :
6783 5251 : poBlock->DropLock();
6784 :
6785 5251 : if (!pfnProgress(
6786 5251 : static_cast<double>(iSampleBlock) /
6787 5251 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6788 : "Compute Statistics", pProgressData))
6789 : {
6790 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6791 0 : CPLFree(pabyMaskData);
6792 0 : return CE_Failure;
6793 : }
6794 : }
6795 :
6796 238 : CPLFree(pabyMaskData);
6797 : }
6798 :
6799 238 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6800 : {
6801 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6802 0 : return CE_Failure;
6803 : }
6804 :
6805 : /* -------------------------------------------------------------------- */
6806 : /* Save computed information. */
6807 : /* -------------------------------------------------------------------- */
6808 238 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
6809 :
6810 238 : if (nValidCount > 0)
6811 : {
6812 237 : if (bApproxOK)
6813 : {
6814 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6815 : }
6816 229 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6817 : {
6818 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6819 : }
6820 237 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6821 : }
6822 : else
6823 : {
6824 1 : dfMin = 0.0;
6825 1 : dfMax = 0.0;
6826 : }
6827 :
6828 238 : SetValidPercent(nSampleCount, nValidCount);
6829 :
6830 : /* -------------------------------------------------------------------- */
6831 : /* Record results. */
6832 : /* -------------------------------------------------------------------- */
6833 238 : if (pdfMin != nullptr)
6834 235 : *pdfMin = dfMin;
6835 238 : if (pdfMax != nullptr)
6836 235 : *pdfMax = dfMax;
6837 :
6838 238 : if (pdfMean != nullptr)
6839 233 : *pdfMean = dfMean;
6840 :
6841 238 : if (pdfStdDev != nullptr)
6842 233 : *pdfStdDev = dfStdDev;
6843 :
6844 238 : if (nValidCount > 0)
6845 237 : return CE_None;
6846 :
6847 1 : ReportError(
6848 : CE_Failure, CPLE_AppDefined,
6849 : "Failed to compute statistics, no valid pixels found in sampling.");
6850 1 : return CE_Failure;
6851 : }
6852 :
6853 : /************************************************************************/
6854 : /* GDALComputeRasterStatistics() */
6855 : /************************************************************************/
6856 :
6857 : /**
6858 : * \brief Compute image statistics.
6859 : *
6860 : * @see GDALRasterBand::ComputeStatistics()
6861 : */
6862 :
6863 142 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
6864 : int bApproxOK, double *pdfMin,
6865 : double *pdfMax, double *pdfMean,
6866 : double *pdfStdDev,
6867 : GDALProgressFunc pfnProgress,
6868 : void *pProgressData)
6869 :
6870 : {
6871 142 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
6872 :
6873 142 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6874 :
6875 142 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
6876 142 : pdfStdDev, pfnProgress, pProgressData);
6877 : }
6878 :
6879 : /************************************************************************/
6880 : /* SetStatistics() */
6881 : /************************************************************************/
6882 :
6883 : /**
6884 : * \brief Set statistics on band.
6885 : *
6886 : * This method can be used to store min/max/mean/standard deviation
6887 : * statistics on a raster band.
6888 : *
6889 : * The default implementation stores them as metadata, and will only work
6890 : * on formats that can save arbitrary metadata. This method cannot detect
6891 : * whether metadata will be properly saved and so may return CE_None even
6892 : * if the statistics will never be saved.
6893 : *
6894 : * This method is the same as the C function GDALSetRasterStatistics().
6895 : *
6896 : * @param dfMin minimum pixel value.
6897 : *
6898 : * @param dfMax maximum pixel value.
6899 : *
6900 : * @param dfMean mean (average) of all pixel values.
6901 : *
6902 : * @param dfStdDev Standard deviation of all pixel values.
6903 : *
6904 : * @return CE_None on success or CE_Failure on failure.
6905 : */
6906 :
6907 466 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
6908 : double dfStdDev)
6909 :
6910 : {
6911 466 : char szValue[128] = {0};
6912 :
6913 466 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
6914 465 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
6915 :
6916 466 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
6917 466 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
6918 :
6919 465 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
6920 466 : SetMetadataItem("STATISTICS_MEAN", szValue);
6921 :
6922 466 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
6923 466 : SetMetadataItem("STATISTICS_STDDEV", szValue);
6924 :
6925 466 : return CE_None;
6926 : }
6927 :
6928 : /************************************************************************/
6929 : /* GDALSetRasterStatistics() */
6930 : /************************************************************************/
6931 :
6932 : /**
6933 : * \brief Set statistics on band.
6934 : *
6935 : * @see GDALRasterBand::SetStatistics()
6936 : */
6937 :
6938 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
6939 : double dfMax, double dfMean,
6940 : double dfStdDev)
6941 :
6942 : {
6943 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
6944 :
6945 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6946 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6947 : }
6948 :
6949 : /************************************************************************/
6950 : /* ComputeRasterMinMax() */
6951 : /************************************************************************/
6952 :
6953 : template <class T, bool HAS_NODATA>
6954 134689 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
6955 : T *pMax)
6956 : {
6957 134689 : T min0 = *pMin;
6958 134689 : T max0 = *pMax;
6959 134689 : T min1 = *pMin;
6960 134689 : T max1 = *pMax;
6961 : size_t i;
6962 1017014 : for (i = 0; i + 1 < nElts; i += 2)
6963 : {
6964 869734 : if (!HAS_NODATA || buffer[i] != nodataValue)
6965 : {
6966 881141 : min0 = std::min(min0, buffer[i]);
6967 881141 : max0 = std::max(max0, buffer[i]);
6968 : }
6969 869734 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
6970 : {
6971 881354 : min1 = std::min(min1, buffer[i + 1]);
6972 881354 : max1 = std::max(max1, buffer[i + 1]);
6973 : }
6974 : }
6975 134689 : T min = std::min(min0, min1);
6976 134689 : T max = std::max(max0, max1);
6977 134689 : if (i < nElts)
6978 : {
6979 119260 : if (!HAS_NODATA || buffer[i] != nodataValue)
6980 : {
6981 119276 : min = std::min(min, buffer[i]);
6982 119276 : max = std::max(max, buffer[i]);
6983 : }
6984 : }
6985 134689 : *pMin = min;
6986 134689 : *pMax = max;
6987 134689 : }
6988 :
6989 : template <GDALDataType eDataType, bool bSignedByte>
6990 : static void
6991 11512 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
6992 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
6993 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
6994 : {
6995 11512 : double dfLocalMin = dfMin;
6996 11512 : double dfLocalMax = dfMax;
6997 :
6998 43491 : for (int iY = 0; iY < nYCheck; iY++)
6999 : {
7000 18965527 : for (int iX = 0; iX < nXCheck; iX++)
7001 : {
7002 18933565 : const GPtrDiff_t iOffset =
7003 18933565 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7004 18933565 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7005 3460307 : continue;
7006 18839324 : bool bValid = true;
7007 18839324 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7008 : iOffset, sNoDataValues, bValid);
7009 18839324 : if (!bValid)
7010 3366066 : continue;
7011 :
7012 15473217 : dfLocalMin = std::min(dfLocalMin, dfValue);
7013 15473217 : dfLocalMax = std::max(dfLocalMax, dfValue);
7014 : }
7015 : }
7016 :
7017 11512 : dfMin = dfLocalMin;
7018 11512 : dfMax = dfLocalMax;
7019 11512 : }
7020 :
7021 11512 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
7022 : bool bSignedByte, int nXCheck, int nYCheck,
7023 : int nBlockXSize,
7024 : const GDALNoDataValues &sNoDataValues,
7025 : const GByte *pabyMaskData, double &dfMin,
7026 : double &dfMax)
7027 : {
7028 11512 : switch (eDataType)
7029 : {
7030 0 : case GDT_Unknown:
7031 0 : CPLAssert(false);
7032 : break;
7033 672 : case GDT_Byte:
7034 672 : if (bSignedByte)
7035 : {
7036 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
7037 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7038 : pabyMaskData, dfMin, dfMax);
7039 : }
7040 : else
7041 : {
7042 669 : ComputeMinMaxGeneric<GDT_Byte, false>(
7043 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7044 : pabyMaskData, dfMin, dfMax);
7045 : }
7046 672 : break;
7047 102 : case GDT_Int8:
7048 102 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
7049 : nBlockXSize, sNoDataValues,
7050 : pabyMaskData, dfMin, dfMax);
7051 102 : break;
7052 200 : case GDT_UInt16:
7053 200 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
7054 : nBlockXSize, sNoDataValues,
7055 : pabyMaskData, dfMin, dfMax);
7056 200 : break;
7057 1 : case GDT_Int16:
7058 1 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
7059 : nBlockXSize, sNoDataValues,
7060 : pabyMaskData, dfMin, dfMax);
7061 1 : break;
7062 197 : case GDT_UInt32:
7063 197 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
7064 : nBlockXSize, sNoDataValues,
7065 : pabyMaskData, dfMin, dfMax);
7066 197 : break;
7067 1111 : case GDT_Int32:
7068 1111 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
7069 : nBlockXSize, sNoDataValues,
7070 : pabyMaskData, dfMin, dfMax);
7071 1111 : break;
7072 12 : case GDT_UInt64:
7073 12 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
7074 : nBlockXSize, sNoDataValues,
7075 : pabyMaskData, dfMin, dfMax);
7076 12 : break;
7077 24 : case GDT_Int64:
7078 24 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
7079 : nBlockXSize, sNoDataValues,
7080 : pabyMaskData, dfMin, dfMax);
7081 24 : break;
7082 0 : case GDT_Float16:
7083 0 : ComputeMinMaxGeneric<GDT_Float16, false>(
7084 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7085 : pabyMaskData, dfMin, dfMax);
7086 0 : break;
7087 5675 : case GDT_Float32:
7088 5675 : ComputeMinMaxGeneric<GDT_Float32, false>(
7089 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7090 : pabyMaskData, dfMin, dfMax);
7091 5675 : break;
7092 3408 : case GDT_Float64:
7093 3408 : ComputeMinMaxGeneric<GDT_Float64, false>(
7094 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7095 : pabyMaskData, dfMin, dfMax);
7096 3408 : break;
7097 9 : case GDT_CInt16:
7098 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
7099 : nBlockXSize, sNoDataValues,
7100 : pabyMaskData, dfMin, dfMax);
7101 9 : break;
7102 9 : case GDT_CInt32:
7103 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
7104 : nBlockXSize, sNoDataValues,
7105 : pabyMaskData, dfMin, dfMax);
7106 9 : break;
7107 0 : case GDT_CFloat16:
7108 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
7109 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7110 : pabyMaskData, dfMin, dfMax);
7111 0 : break;
7112 75 : case GDT_CFloat32:
7113 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
7114 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7115 : pabyMaskData, dfMin, dfMax);
7116 75 : break;
7117 17 : case GDT_CFloat64:
7118 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
7119 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7120 : pabyMaskData, dfMin, dfMax);
7121 17 : break;
7122 0 : case GDT_TypeCount:
7123 0 : CPLAssert(false);
7124 : break;
7125 : }
7126 11512 : }
7127 :
7128 704 : static bool ComputeMinMaxGenericIterBlocks(
7129 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
7130 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
7131 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
7132 : double &dfMin, double &dfMax)
7133 :
7134 : {
7135 704 : GByte *pabyMaskData = nullptr;
7136 : int nBlockXSize, nBlockYSize;
7137 704 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7138 :
7139 704 : if (poMaskBand)
7140 : {
7141 : pabyMaskData =
7142 40 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7143 40 : if (!pabyMaskData)
7144 : {
7145 0 : return false;
7146 : }
7147 : }
7148 :
7149 12216 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7150 11512 : iSampleBlock += nSampleRate)
7151 : {
7152 11512 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7153 11512 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7154 :
7155 11512 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7156 11512 : if (poBlock == nullptr)
7157 : {
7158 0 : CPLFree(pabyMaskData);
7159 0 : return false;
7160 : }
7161 :
7162 11512 : void *const pData = poBlock->GetDataRef();
7163 :
7164 11512 : int nXCheck = 0, nYCheck = 0;
7165 11512 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7166 :
7167 12383 : if (poMaskBand &&
7168 871 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7169 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7170 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7171 : nBlockXSize, nullptr) != CE_None)
7172 : {
7173 0 : poBlock->DropLock();
7174 0 : CPLFree(pabyMaskData);
7175 0 : return false;
7176 : }
7177 :
7178 11512 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7179 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
7180 : dfMax);
7181 :
7182 11512 : poBlock->DropLock();
7183 : }
7184 :
7185 704 : CPLFree(pabyMaskData);
7186 704 : return true;
7187 : }
7188 :
7189 : /**
7190 : * \brief Compute the min/max values for a band.
7191 : *
7192 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7193 : * be trusted. If it doesn't work, a subsample of blocks will be read to
7194 : * get an approximate min/max. If the band has a nodata value it will
7195 : * be excluded from the minimum and maximum.
7196 : *
7197 : * If bApprox is FALSE, then all pixels will be read and used to compute
7198 : * an exact range.
7199 : *
7200 : * This method is the same as the C function GDALComputeRasterMinMax().
7201 : *
7202 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7203 : * FALSE.
7204 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7205 : * maximum (adfMinMax[1]) are returned.
7206 : *
7207 : * @return CE_None on success or CE_Failure on failure.
7208 : */
7209 :
7210 1554 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7211 : {
7212 : /* -------------------------------------------------------------------- */
7213 : /* Does the driver already know the min/max? */
7214 : /* -------------------------------------------------------------------- */
7215 1554 : if (bApproxOK)
7216 : {
7217 12 : int bSuccessMin = FALSE;
7218 12 : int bSuccessMax = FALSE;
7219 :
7220 12 : double dfMin = GetMinimum(&bSuccessMin);
7221 12 : double dfMax = GetMaximum(&bSuccessMax);
7222 :
7223 12 : if (bSuccessMin && bSuccessMax)
7224 : {
7225 1 : adfMinMax[0] = dfMin;
7226 1 : adfMinMax[1] = dfMax;
7227 1 : return CE_None;
7228 : }
7229 : }
7230 :
7231 : /* -------------------------------------------------------------------- */
7232 : /* If we have overview bands, use them for min/max. */
7233 : /* -------------------------------------------------------------------- */
7234 : // cppcheck-suppress knownConditionTrueFalse
7235 1553 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7236 : {
7237 : GDALRasterBand *poBand =
7238 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7239 :
7240 0 : if (poBand != this)
7241 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7242 : }
7243 :
7244 : /* -------------------------------------------------------------------- */
7245 : /* Read actual data and compute minimum and maximum. */
7246 : /* -------------------------------------------------------------------- */
7247 1553 : GDALNoDataValues sNoDataValues(this, eDataType);
7248 1553 : GDALRasterBand *poMaskBand = nullptr;
7249 1553 : if (!sNoDataValues.bGotNoDataValue)
7250 : {
7251 1289 : const int l_nMaskFlags = GetMaskFlags();
7252 1329 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7253 40 : GetColorInterpretation() != GCI_AlphaBand)
7254 : {
7255 40 : poMaskBand = GetMaskBand();
7256 : }
7257 : }
7258 :
7259 1553 : bool bSignedByte = false;
7260 1553 : if (eDataType == GDT_Byte)
7261 : {
7262 638 : EnablePixelTypeSignedByteWarning(false);
7263 : const char *pszPixelType =
7264 638 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7265 638 : EnablePixelTypeSignedByteWarning(true);
7266 638 : bSignedByte =
7267 638 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7268 : }
7269 :
7270 : GDALRasterIOExtraArg sExtraArg;
7271 1553 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7272 :
7273 3106 : GUInt32 nMin = (eDataType == GDT_Byte)
7274 1553 : ? 255
7275 : : 65535; // used for GByte & GUInt16 cases
7276 1553 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
7277 1553 : GInt16 nMinInt16 =
7278 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
7279 1553 : GInt16 nMaxInt16 =
7280 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
7281 1553 : double dfMin =
7282 : std::numeric_limits<double>::max(); // used for generic code path
7283 1553 : double dfMax =
7284 : std::numeric_limits<double>::lowest(); // used for generic code path
7285 1553 : const bool bUseOptimizedPath =
7286 2459 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7287 906 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7288 :
7289 : const auto ComputeMinMaxForBlock =
7290 18582 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
7291 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
7292 241828 : int nYCheck)
7293 : {
7294 18582 : if (eDataType == GDT_Byte && !bSignedByte)
7295 : {
7296 : const bool bHasNoData =
7297 9501 : sNoDataValues.bGotNoDataValue &&
7298 25669 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
7299 9501 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
7300 9501 : sNoDataValues.dfNoDataValue;
7301 16168 : const GUInt32 nNoDataValue =
7302 16168 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
7303 : : 0;
7304 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7305 : ComputeStatisticsInternal<GByte,
7306 : /* COMPUTE_OTHER_STATS = */ false>::
7307 16168 : f(nXCheck, nBufferWidth, nYCheck,
7308 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7309 16168 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7310 : }
7311 2414 : else if (eDataType == GDT_UInt16)
7312 : {
7313 : const bool bHasNoData =
7314 83 : sNoDataValues.bGotNoDataValue &&
7315 973 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
7316 83 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
7317 83 : sNoDataValues.dfNoDataValue;
7318 890 : const GUInt32 nNoDataValue =
7319 890 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
7320 : : 0;
7321 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7322 : ComputeStatisticsInternal<GUInt16,
7323 : /* COMPUTE_OTHER_STATS = */ false>::
7324 890 : f(nXCheck, nBufferWidth, nYCheck,
7325 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7326 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7327 : }
7328 1524 : else if (eDataType == GDT_Int16)
7329 : {
7330 : const bool bHasNoData =
7331 1353 : sNoDataValues.bGotNoDataValue &&
7332 2877 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
7333 1353 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
7334 1353 : sNoDataValues.dfNoDataValue;
7335 1524 : if (bHasNoData)
7336 : {
7337 1353 : const int16_t nNoDataValue =
7338 1353 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
7339 134754 : for (int iY = 0; iY < nYCheck; iY++)
7340 : {
7341 133401 : ComputeMinMax<int16_t, true>(
7342 133401 : static_cast<const int16_t *>(pData) +
7343 133401 : static_cast<size_t>(iY) * nBufferWidth,
7344 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7345 : }
7346 : }
7347 : else
7348 : {
7349 1459 : for (int iY = 0; iY < nYCheck; iY++)
7350 : {
7351 1288 : ComputeMinMax<int16_t, false>(
7352 1288 : static_cast<const int16_t *>(pData) +
7353 1288 : static_cast<size_t>(iY) * nBufferWidth,
7354 : nXCheck, 0, &nMinInt16, &nMaxInt16);
7355 : }
7356 : }
7357 : }
7358 18582 : };
7359 :
7360 1553 : if (bApproxOK && HasArbitraryOverviews())
7361 : {
7362 : /* --------------------------------------------------------------------
7363 : */
7364 : /* Figure out how much the image should be reduced to get an */
7365 : /* approximate value. */
7366 : /* --------------------------------------------------------------------
7367 : */
7368 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7369 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7370 :
7371 0 : int nXReduced = nRasterXSize;
7372 0 : int nYReduced = nRasterYSize;
7373 0 : if (dfReduction > 1.0)
7374 : {
7375 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7376 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7377 :
7378 : // Catch the case of huge resizing ratios here
7379 0 : if (nXReduced == 0)
7380 0 : nXReduced = 1;
7381 0 : if (nYReduced == 0)
7382 0 : nYReduced = 1;
7383 : }
7384 :
7385 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
7386 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7387 :
7388 : const CPLErr eErr =
7389 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7390 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7391 0 : if (eErr != CE_None)
7392 : {
7393 0 : CPLFree(pData);
7394 0 : return eErr;
7395 : }
7396 :
7397 0 : GByte *pabyMaskData = nullptr;
7398 0 : if (poMaskBand)
7399 : {
7400 : pabyMaskData =
7401 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7402 0 : if (!pabyMaskData)
7403 : {
7404 0 : CPLFree(pData);
7405 0 : return CE_Failure;
7406 : }
7407 :
7408 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7409 : pabyMaskData, nXReduced, nYReduced,
7410 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
7411 : {
7412 0 : CPLFree(pData);
7413 0 : CPLFree(pabyMaskData);
7414 0 : return CE_Failure;
7415 : }
7416 : }
7417 :
7418 0 : if (bUseOptimizedPath)
7419 : {
7420 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7421 : }
7422 : else
7423 : {
7424 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
7425 : nYReduced, nXReduced, sNoDataValues,
7426 : pabyMaskData, dfMin, dfMax);
7427 : }
7428 :
7429 0 : CPLFree(pData);
7430 0 : CPLFree(pabyMaskData);
7431 : }
7432 :
7433 : else // No arbitrary overviews
7434 : {
7435 1553 : if (!InitBlockInfo())
7436 0 : return CE_Failure;
7437 :
7438 : /* --------------------------------------------------------------------
7439 : */
7440 : /* Figure out the ratio of blocks we will read to get an */
7441 : /* approximate value. */
7442 : /* --------------------------------------------------------------------
7443 : */
7444 1553 : int nSampleRate = 1;
7445 :
7446 1553 : if (bApproxOK)
7447 : {
7448 11 : nSampleRate = static_cast<int>(std::max(
7449 22 : 1.0,
7450 11 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7451 : // We want to avoid probing only the first column of blocks for
7452 : // a square shaped raster, because it is not unlikely that it may
7453 : // be padding only (#6378).
7454 11 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7455 0 : nSampleRate += 1;
7456 : }
7457 :
7458 1553 : if (bUseOptimizedPath)
7459 : {
7460 849 : for (GIntBig iSampleBlock = 0;
7461 19357 : iSampleBlock <
7462 19357 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7463 18508 : iSampleBlock += nSampleRate)
7464 : {
7465 18583 : const int iYBlock =
7466 18583 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7467 18583 : const int iXBlock =
7468 18583 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7469 :
7470 18583 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7471 18583 : if (poBlock == nullptr)
7472 1 : return CE_Failure;
7473 :
7474 18582 : void *const pData = poBlock->GetDataRef();
7475 :
7476 18582 : int nXCheck = 0, nYCheck = 0;
7477 18582 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7478 :
7479 18582 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7480 :
7481 18582 : poBlock->DropLock();
7482 :
7483 18582 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7484 4120 : nMax == 255)
7485 74 : break;
7486 : }
7487 : }
7488 : else
7489 : {
7490 704 : const GIntBig nTotalBlocks =
7491 704 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7492 704 : if (!ComputeMinMaxGenericIterBlocks(
7493 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7494 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
7495 : {
7496 0 : return CE_Failure;
7497 : }
7498 : }
7499 : }
7500 :
7501 1552 : if (bUseOptimizedPath)
7502 : {
7503 848 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7504 : {
7505 736 : dfMin = nMin;
7506 736 : dfMax = nMax;
7507 : }
7508 112 : else if (eDataType == GDT_Int16)
7509 : {
7510 112 : dfMin = nMinInt16;
7511 112 : dfMax = nMaxInt16;
7512 : }
7513 : }
7514 :
7515 1552 : if (dfMin > dfMax)
7516 : {
7517 4 : adfMinMax[0] = 0;
7518 4 : adfMinMax[1] = 0;
7519 4 : ReportError(
7520 : CE_Failure, CPLE_AppDefined,
7521 : "Failed to compute min/max, no valid pixels found in sampling.");
7522 4 : return CE_Failure;
7523 : }
7524 :
7525 1548 : adfMinMax[0] = dfMin;
7526 1548 : adfMinMax[1] = dfMax;
7527 :
7528 1548 : return CE_None;
7529 : }
7530 :
7531 : /************************************************************************/
7532 : /* GDALComputeRasterMinMax() */
7533 : /************************************************************************/
7534 :
7535 : /**
7536 : * \brief Compute the min/max values for a band.
7537 : *
7538 : * @see GDALRasterBand::ComputeRasterMinMax()
7539 : *
7540 : * @note Prior to GDAL 3.6, this function returned void
7541 : */
7542 :
7543 1476 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7544 : double adfMinMax[2])
7545 :
7546 : {
7547 1476 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7548 :
7549 1476 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7550 1476 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7551 : }
7552 :
7553 : /************************************************************************/
7554 : /* ComputeRasterMinMaxLocation() */
7555 : /************************************************************************/
7556 :
7557 : /**
7558 : * \brief Compute the min/max values for a band, and their location.
7559 : *
7560 : * Pixels whose value matches the nodata value or are masked by the mask
7561 : * band are ignored.
7562 : *
7563 : * If the minimum or maximum value is hit in several locations, it is not
7564 : * specified which one will be returned.
7565 : *
7566 : * @param[out] pdfMin Pointer to the minimum value.
7567 : * @param[out] pdfMax Pointer to the maximum value.
7568 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7569 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7570 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7571 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7572 : *
7573 : * @return CE_None in case of success, CE_Warning if there are no valid values,
7574 : * CE_Failure in case of error.
7575 : *
7576 : * @since GDAL 3.11
7577 : */
7578 :
7579 8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7580 : double *pdfMax, int *pnMinX,
7581 : int *pnMinY, int *pnMaxX,
7582 : int *pnMaxY)
7583 : {
7584 8 : int nMinX = -1;
7585 8 : int nMinY = -1;
7586 8 : int nMaxX = -1;
7587 8 : int nMaxY = -1;
7588 8 : double dfMin = std::numeric_limits<double>::infinity();
7589 8 : double dfMax = -std::numeric_limits<double>::infinity();
7590 8 : if (pdfMin)
7591 5 : *pdfMin = dfMin;
7592 8 : if (pdfMax)
7593 5 : *pdfMax = dfMax;
7594 8 : if (pnMinX)
7595 6 : *pnMinX = nMinX;
7596 8 : if (pnMinY)
7597 6 : *pnMinY = nMinY;
7598 8 : if (pnMaxX)
7599 6 : *pnMaxX = nMaxX;
7600 8 : if (pnMaxY)
7601 6 : *pnMaxY = nMaxY;
7602 :
7603 8 : if (GDALDataTypeIsComplex(eDataType))
7604 : {
7605 0 : CPLError(CE_Failure, CPLE_NotSupported,
7606 : "Complex data type not supported");
7607 0 : return CE_Failure;
7608 : }
7609 :
7610 8 : if (!InitBlockInfo())
7611 0 : return CE_Failure;
7612 :
7613 8 : GDALNoDataValues sNoDataValues(this, eDataType);
7614 8 : GDALRasterBand *poMaskBand = nullptr;
7615 8 : if (!sNoDataValues.bGotNoDataValue)
7616 : {
7617 8 : const int l_nMaskFlags = GetMaskFlags();
7618 9 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7619 1 : GetColorInterpretation() != GCI_AlphaBand)
7620 : {
7621 1 : poMaskBand = GetMaskBand();
7622 : }
7623 : }
7624 :
7625 8 : bool bSignedByte = false;
7626 8 : if (eDataType == GDT_Byte)
7627 : {
7628 7 : EnablePixelTypeSignedByteWarning(false);
7629 : const char *pszPixelType =
7630 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7631 7 : EnablePixelTypeSignedByteWarning(true);
7632 7 : bSignedByte =
7633 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7634 : }
7635 :
7636 8 : GByte *pabyMaskData = nullptr;
7637 8 : if (poMaskBand)
7638 : {
7639 : pabyMaskData =
7640 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7641 1 : if (!pabyMaskData)
7642 : {
7643 0 : return CE_Failure;
7644 : }
7645 : }
7646 :
7647 8 : const GIntBig nTotalBlocks =
7648 8 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7649 8 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7650 8 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7651 16 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7652 : {
7653 11 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7654 11 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7655 :
7656 11 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7657 11 : if (poBlock == nullptr)
7658 : {
7659 0 : CPLFree(pabyMaskData);
7660 0 : return CE_Failure;
7661 : }
7662 :
7663 11 : void *const pData = poBlock->GetDataRef();
7664 :
7665 11 : int nXCheck = 0, nYCheck = 0;
7666 11 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7667 :
7668 13 : if (poMaskBand &&
7669 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7670 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7671 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7672 2 : nBlockXSize, nullptr) != CE_None)
7673 : {
7674 0 : poBlock->DropLock();
7675 0 : CPLFree(pabyMaskData);
7676 0 : return CE_Failure;
7677 : }
7678 :
7679 11 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7680 : {
7681 4 : for (int iY = 0; iY < nYCheck; ++iY)
7682 : {
7683 6 : for (int iX = 0; iX < nXCheck; ++iX)
7684 : {
7685 4 : const GPtrDiff_t iOffset =
7686 4 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7687 4 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7688 2 : continue;
7689 2 : bool bValid = true;
7690 : double dfValue =
7691 2 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
7692 : sNoDataValues, bValid);
7693 2 : if (!bValid)
7694 0 : continue;
7695 2 : if (dfValue < dfMin)
7696 : {
7697 2 : dfMin = dfValue;
7698 2 : nMinX = iXBlock * nBlockXSize + iX;
7699 2 : nMinY = iYBlock * nBlockYSize + iY;
7700 : }
7701 2 : if (dfValue > dfMax)
7702 : {
7703 1 : dfMax = dfValue;
7704 1 : nMaxX = iXBlock * nBlockXSize + iX;
7705 1 : nMaxY = iYBlock * nBlockYSize + iY;
7706 : }
7707 : }
7708 2 : }
7709 : }
7710 : else
7711 : {
7712 9 : size_t pos_min = 0;
7713 9 : size_t pos_max = 0;
7714 9 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7715 9 : if (bNeedsMin && bNeedsMax)
7716 : {
7717 10 : std::tie(pos_min, pos_max) = gdal::minmax_element(
7718 5 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7719 5 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7720 10 : sNoDataValues.dfNoDataValue);
7721 : }
7722 4 : else if (bNeedsMin)
7723 : {
7724 1 : pos_min = gdal::min_element(
7725 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7726 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7727 : sNoDataValues.dfNoDataValue);
7728 : }
7729 3 : else if (bNeedsMax)
7730 : {
7731 2 : pos_max = gdal::max_element(
7732 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7733 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7734 : sNoDataValues.dfNoDataValue);
7735 : }
7736 :
7737 9 : if (bNeedsMin)
7738 : {
7739 6 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7740 6 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7741 6 : bool bValid = true;
7742 : const double dfMinValueBlock =
7743 6 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
7744 : sNoDataValues, bValid);
7745 6 : if (bValid && dfMinValueBlock < dfMin)
7746 : {
7747 5 : dfMin = dfMinValueBlock;
7748 5 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
7749 5 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
7750 : }
7751 : }
7752 :
7753 9 : if (bNeedsMax)
7754 : {
7755 7 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7756 7 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7757 7 : bool bValid = true;
7758 : const double dfMaxValueBlock =
7759 7 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
7760 : sNoDataValues, bValid);
7761 7 : if (bValid && dfMaxValueBlock > dfMax)
7762 : {
7763 5 : dfMax = dfMaxValueBlock;
7764 5 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7765 5 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7766 : }
7767 : }
7768 : }
7769 :
7770 11 : poBlock->DropLock();
7771 :
7772 11 : if (eDataType == GDT_Byte)
7773 : {
7774 10 : if (bNeedsMin && dfMin == 0)
7775 : {
7776 1 : bNeedsMin = false;
7777 : }
7778 10 : if (bNeedsMax && dfMax == 255)
7779 : {
7780 4 : bNeedsMax = false;
7781 : }
7782 10 : if (!bNeedsMin && !bNeedsMax)
7783 : {
7784 3 : break;
7785 : }
7786 : }
7787 : }
7788 :
7789 8 : CPLFree(pabyMaskData);
7790 :
7791 8 : if (pdfMin)
7792 5 : *pdfMin = dfMin;
7793 8 : if (pdfMax)
7794 5 : *pdfMax = dfMax;
7795 8 : if (pnMinX)
7796 6 : *pnMinX = nMinX;
7797 8 : if (pnMinY)
7798 6 : *pnMinY = nMinY;
7799 8 : if (pnMaxX)
7800 6 : *pnMaxX = nMaxX;
7801 8 : if (pnMaxY)
7802 6 : *pnMaxY = nMaxY;
7803 8 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
7804 8 : : CE_None;
7805 : }
7806 :
7807 : /************************************************************************/
7808 : /* GDALComputeRasterMinMaxLocation() */
7809 : /************************************************************************/
7810 :
7811 : /**
7812 : * \brief Compute the min/max values for a band, and their location.
7813 : *
7814 : * @see GDALRasterBand::ComputeRasterMinMax()
7815 : * @since GDAL 3.11
7816 : */
7817 :
7818 6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
7819 : double *pdfMax, int *pnMinX, int *pnMinY,
7820 : int *pnMaxX, int *pnMaxY)
7821 :
7822 : {
7823 6 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
7824 :
7825 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7826 6 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
7827 6 : pnMaxX, pnMaxY);
7828 : }
7829 :
7830 : /************************************************************************/
7831 : /* SetDefaultHistogram() */
7832 : /************************************************************************/
7833 :
7834 : /* FIXME : add proper documentation */
7835 : /**
7836 : * \brief Set default histogram.
7837 : *
7838 : * This method is the same as the C function GDALSetDefaultHistogram() and
7839 : * GDALSetDefaultHistogramEx()
7840 : */
7841 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
7842 : double /* dfMax */,
7843 : int /* nBuckets */,
7844 : GUIntBig * /* panHistogram */)
7845 :
7846 : {
7847 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
7848 0 : ReportError(CE_Failure, CPLE_NotSupported,
7849 : "SetDefaultHistogram() not implemented for this format.");
7850 :
7851 0 : return CE_Failure;
7852 : }
7853 :
7854 : /************************************************************************/
7855 : /* GDALSetDefaultHistogram() */
7856 : /************************************************************************/
7857 :
7858 : /**
7859 : * \brief Set default histogram.
7860 : *
7861 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
7862 : * 2 billion.
7863 : *
7864 : * @see GDALRasterBand::SetDefaultHistogram()
7865 : * @see GDALSetRasterHistogramEx()
7866 : */
7867 :
7868 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
7869 : double dfMax, int nBuckets,
7870 : int *panHistogram)
7871 :
7872 : {
7873 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
7874 :
7875 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7876 :
7877 : GUIntBig *panHistogramTemp =
7878 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
7879 0 : if (panHistogramTemp == nullptr)
7880 : {
7881 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
7882 : "Out of memory in GDALSetDefaultHistogram().");
7883 0 : return CE_Failure;
7884 : }
7885 :
7886 0 : for (int i = 0; i < nBuckets; ++i)
7887 : {
7888 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
7889 : }
7890 :
7891 : const CPLErr eErr =
7892 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
7893 :
7894 0 : CPLFree(panHistogramTemp);
7895 :
7896 0 : return eErr;
7897 : }
7898 :
7899 : /************************************************************************/
7900 : /* GDALSetDefaultHistogramEx() */
7901 : /************************************************************************/
7902 :
7903 : /**
7904 : * \brief Set default histogram.
7905 : *
7906 : * @see GDALRasterBand::SetDefaultHistogram()
7907 : *
7908 : * @since GDAL 2.0
7909 : */
7910 :
7911 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
7912 : double dfMin, double dfMax,
7913 : int nBuckets,
7914 : GUIntBig *panHistogram)
7915 :
7916 : {
7917 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
7918 :
7919 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7920 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
7921 : }
7922 :
7923 : /************************************************************************/
7924 : /* GetDefaultRAT() */
7925 : /************************************************************************/
7926 :
7927 : /**
7928 : * \brief Fetch default Raster Attribute Table.
7929 : *
7930 : * A RAT will be returned if there is a default one associated with the
7931 : * band, otherwise NULL is returned. The returned RAT is owned by the
7932 : * band and should not be deleted by the application.
7933 : *
7934 : * This method is the same as the C function GDALGetDefaultRAT().
7935 : *
7936 : * @return NULL, or a pointer to an internal RAT owned by the band.
7937 : */
7938 :
7939 112 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
7940 :
7941 : {
7942 112 : return nullptr;
7943 : }
7944 :
7945 : /************************************************************************/
7946 : /* GDALGetDefaultRAT() */
7947 : /************************************************************************/
7948 :
7949 : /**
7950 : * \brief Fetch default Raster Attribute Table.
7951 : *
7952 : * @see GDALRasterBand::GetDefaultRAT()
7953 : */
7954 :
7955 1000 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
7956 :
7957 : {
7958 1000 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
7959 :
7960 1000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7961 1000 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
7962 : }
7963 :
7964 : /************************************************************************/
7965 : /* SetDefaultRAT() */
7966 : /************************************************************************/
7967 :
7968 : /**
7969 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
7970 : * \brief Set default Raster Attribute Table.
7971 : *
7972 : * Associates a default RAT with the band. If not implemented for the
7973 : * format a CPLE_NotSupported error will be issued. If successful a copy
7974 : * of the RAT is made, the original remains owned by the caller.
7975 : *
7976 : * This method is the same as the C function GDALSetDefaultRAT().
7977 : *
7978 : * @param poRAT the RAT to assign to the band.
7979 : *
7980 : * @return CE_None on success or CE_Failure if unsupported or otherwise
7981 : * failing.
7982 : */
7983 :
7984 : /**/
7985 : /**/
7986 :
7987 : CPLErr
7988 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
7989 : {
7990 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
7991 : {
7992 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
7993 0 : ReportError(CE_Failure, CPLE_NotSupported,
7994 : "SetDefaultRAT() not implemented for this format.");
7995 0 : CPLPopErrorHandler();
7996 : }
7997 0 : return CE_Failure;
7998 : }
7999 :
8000 : /************************************************************************/
8001 : /* GDALSetDefaultRAT() */
8002 : /************************************************************************/
8003 :
8004 : /**
8005 : * \brief Set default Raster Attribute Table.
8006 : *
8007 : * @see GDALRasterBand::GDALSetDefaultRAT()
8008 : */
8009 :
8010 18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
8011 : GDALRasterAttributeTableH hRAT)
8012 :
8013 : {
8014 18 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
8015 :
8016 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8017 :
8018 18 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
8019 : }
8020 :
8021 : /************************************************************************/
8022 : /* GetMaskBand() */
8023 : /************************************************************************/
8024 :
8025 : /**
8026 : * \brief Return the mask band associated with the band.
8027 : *
8028 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8029 : * that returns one of four default implementations :
8030 : * <ul>
8031 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8032 : * </li>
8033 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8034 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8035 : * GMF_NODATA | GMF_PER_DATASET.
8036 : * </li>
8037 : * <li>If the band has a nodata value set, an instance of the new
8038 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8039 : * GMF_NODATA.
8040 : * </li>
8041 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
8042 : * to apply to this band (specific rules yet to be determined) and that is of
8043 : * type GDT_Byte then that alpha band will be returned, and the flags
8044 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8045 : * </li>
8046 : * <li>If neither of the above apply, an instance of the new
8047 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8048 : * pixels. The null flags will return GMF_ALL_VALID.
8049 : * </li>
8050 : * </ul>
8051 : *
8052 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
8053 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
8054 : *
8055 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8056 : * dataset, with the same name as the main dataset and suffixed with .msk,
8057 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8058 : * main dataset.
8059 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8060 : * level, where xx matches the band number of a band of the main dataset. The
8061 : * value of those items is a combination of the flags GMF_ALL_VALID,
8062 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8063 : * a band, then the other rules explained above will be used to generate a
8064 : * on-the-fly mask band.
8065 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8066 : *
8067 : * This method is the same as the C function GDALGetMaskBand().
8068 : *
8069 : * @return a valid mask band.
8070 : *
8071 : * @since GDAL 1.5.0
8072 : *
8073 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8074 : *
8075 : */
8076 743315 : GDALRasterBand *GDALRasterBand::GetMaskBand()
8077 :
8078 : {
8079 179013 : const auto HasNoData = [this]()
8080 : {
8081 59408 : int bHaveNoDataRaw = FALSE;
8082 59408 : bool bHaveNoData = false;
8083 59408 : if (eDataType == GDT_Int64)
8084 : {
8085 56 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
8086 56 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8087 : }
8088 59352 : else if (eDataType == GDT_UInt64)
8089 : {
8090 43 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
8091 43 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8092 : }
8093 : else
8094 : {
8095 59309 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
8096 59240 : if (bHaveNoDataRaw &&
8097 59240 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
8098 : {
8099 816 : bHaveNoData = true;
8100 : }
8101 : }
8102 59173 : return bHaveNoData;
8103 743315 : };
8104 :
8105 743315 : if (poMask != nullptr)
8106 : {
8107 705473 : if (poMask.IsOwned())
8108 : {
8109 327554 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
8110 : {
8111 31677 : if (HasNoData())
8112 : {
8113 9 : InvalidateMaskBand();
8114 : }
8115 : }
8116 297368 : else if (auto poNoDataMaskBand =
8117 297411 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
8118 : {
8119 182 : int bHaveNoDataRaw = FALSE;
8120 182 : bool bIsSame = false;
8121 182 : if (eDataType == GDT_Int64)
8122 9 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
8123 11 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
8124 2 : bHaveNoDataRaw;
8125 173 : else if (eDataType == GDT_UInt64)
8126 9 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8127 11 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8128 2 : bHaveNoDataRaw;
8129 : else
8130 : {
8131 : const double dfNoDataValue =
8132 164 : GetNoDataValue(&bHaveNoDataRaw);
8133 164 : if (bHaveNoDataRaw)
8134 : {
8135 161 : bIsSame =
8136 161 : std::isnan(dfNoDataValue)
8137 161 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8138 135 : : poNoDataMaskBand->m_dfNoDataValue ==
8139 : dfNoDataValue;
8140 : }
8141 : }
8142 182 : if (!bIsSame)
8143 23 : InvalidateMaskBand();
8144 : }
8145 : }
8146 :
8147 710853 : if (poMask)
8148 712500 : return poMask.get();
8149 : }
8150 :
8151 : /* -------------------------------------------------------------------- */
8152 : /* Check for a mask in a .msk file. */
8153 : /* -------------------------------------------------------------------- */
8154 27837 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8155 : {
8156 46 : poMask.reset(poDS->oOvManager.GetMaskBand(nBand), false);
8157 46 : if (poMask != nullptr)
8158 : {
8159 44 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8160 44 : return poMask.get();
8161 : }
8162 : }
8163 :
8164 : /* -------------------------------------------------------------------- */
8165 : /* Check for NODATA_VALUES metadata. */
8166 : /* -------------------------------------------------------------------- */
8167 27792 : if (poDS != nullptr)
8168 : {
8169 : const char *pszGDALNoDataValues =
8170 27777 : poDS->GetMetadataItem("NODATA_VALUES");
8171 27777 : if (pszGDALNoDataValues != nullptr)
8172 : {
8173 56 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
8174 : pszGDALNoDataValues, " ", FALSE, FALSE);
8175 :
8176 : // Make sure we have as many values as bands.
8177 112 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
8178 56 : poDS->GetRasterCount() != 0)
8179 : {
8180 : // Make sure that all bands have the same data type
8181 : // This is clearly not a fundamental condition, just a
8182 : // condition to make implementation easier.
8183 56 : GDALDataType eDT = GDT_Unknown;
8184 56 : int i = 0; // Used after for.
8185 224 : for (; i < poDS->GetRasterCount(); ++i)
8186 : {
8187 168 : if (i == 0)
8188 56 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8189 112 : else if (eDT !=
8190 112 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
8191 : {
8192 0 : break;
8193 : }
8194 : }
8195 56 : if (i == poDS->GetRasterCount())
8196 : {
8197 56 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8198 : try
8199 : {
8200 56 : poMask.reset(new GDALNoDataValuesMaskBand(poDS), true);
8201 : }
8202 0 : catch (const std::bad_alloc &)
8203 : {
8204 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8205 0 : poMask.reset();
8206 : }
8207 56 : CSLDestroy(papszGDALNoDataValues);
8208 56 : return poMask.get();
8209 : }
8210 : else
8211 : {
8212 0 : ReportError(CE_Warning, CPLE_AppDefined,
8213 : "All bands should have the same type in "
8214 : "order the NODATA_VALUES metadata item "
8215 : "to be used as a mask.");
8216 : }
8217 : }
8218 : else
8219 : {
8220 0 : ReportError(
8221 : CE_Warning, CPLE_AppDefined,
8222 : "NODATA_VALUES metadata item doesn't have the same number "
8223 : "of values as the number of bands. "
8224 : "Ignoring it for mask.");
8225 : }
8226 :
8227 0 : CSLDestroy(papszGDALNoDataValues);
8228 : }
8229 : }
8230 :
8231 : /* -------------------------------------------------------------------- */
8232 : /* Check for nodata case. */
8233 : /* -------------------------------------------------------------------- */
8234 27736 : if (HasNoData())
8235 : {
8236 838 : nMaskFlags = GMF_NODATA;
8237 : try
8238 : {
8239 838 : poMask.reset(new GDALNoDataMaskBand(this), true);
8240 : }
8241 0 : catch (const std::bad_alloc &)
8242 : {
8243 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8244 0 : poMask.reset();
8245 : }
8246 838 : return poMask.get();
8247 : }
8248 :
8249 : /* -------------------------------------------------------------------- */
8250 : /* Check for alpha case. */
8251 : /* -------------------------------------------------------------------- */
8252 26883 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8253 54318 : this == poDS->GetRasterBand(1) &&
8254 535 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8255 : {
8256 196 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8257 : {
8258 152 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8259 152 : poMask.reset(poDS->GetRasterBand(2), false);
8260 152 : return poMask.get();
8261 : }
8262 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8263 : {
8264 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8265 : try
8266 : {
8267 23 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(2)),
8268 : true);
8269 : }
8270 0 : catch (const std::bad_alloc &)
8271 : {
8272 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8273 0 : poMask.reset();
8274 : }
8275 23 : return poMask.get();
8276 : }
8277 : }
8278 :
8279 26708 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8280 2701 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8281 54073 : this == poDS->GetRasterBand(3)) &&
8282 2110 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8283 : {
8284 1224 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8285 : {
8286 1177 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8287 1177 : poMask.reset(poDS->GetRasterBand(4), false);
8288 1177 : return poMask.get();
8289 : }
8290 47 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8291 : {
8292 35 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8293 : try
8294 : {
8295 35 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(4)),
8296 : true);
8297 : }
8298 0 : catch (const std::bad_alloc &)
8299 : {
8300 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8301 0 : poMask.reset();
8302 : }
8303 35 : return poMask.get();
8304 : }
8305 : }
8306 :
8307 : /* -------------------------------------------------------------------- */
8308 : /* Fallback to all valid case. */
8309 : /* -------------------------------------------------------------------- */
8310 25512 : nMaskFlags = GMF_ALL_VALID;
8311 : try
8312 : {
8313 25512 : poMask.reset(new GDALAllValidMaskBand(this), true);
8314 : }
8315 0 : catch (const std::bad_alloc &)
8316 : {
8317 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8318 0 : poMask.reset();
8319 : }
8320 :
8321 25511 : return poMask.get();
8322 : }
8323 :
8324 : /************************************************************************/
8325 : /* GDALGetMaskBand() */
8326 : /************************************************************************/
8327 :
8328 : /**
8329 : * \brief Return the mask band associated with the band.
8330 : *
8331 : * @see GDALRasterBand::GetMaskBand()
8332 : */
8333 :
8334 10935 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8335 :
8336 : {
8337 10935 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8338 :
8339 10935 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8340 10935 : return poBand->GetMaskBand();
8341 : }
8342 :
8343 : /************************************************************************/
8344 : /* GetMaskFlags() */
8345 : /************************************************************************/
8346 :
8347 : /**
8348 : * \brief Return the status flags of the mask band associated with the band.
8349 : *
8350 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8351 : * the following available definitions that may be extended in the future:
8352 : * <ul>
8353 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8354 : * 255. When used this will normally be the only flag set.
8355 : * </li>
8356 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8357 : * dataset.
8358 : * </li>
8359 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8360 : * and may have values other than 0 and 255.
8361 : * </li>
8362 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8363 : * nodata values. (mutually exclusive of GMF_ALPHA)
8364 : * </li>
8365 : * </ul>
8366 : *
8367 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8368 : * that returns one of four default implementations:
8369 : * <ul>
8370 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8371 : * </li>
8372 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8373 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8374 : * GMF_NODATA | GMF_PER_DATASET.
8375 : * </li>
8376 : * <li>If the band has a nodata value set, an instance of the new
8377 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8378 : * GMF_NODATA.
8379 : * </li>
8380 : * <li>If there is no nodata value, but the dataset has an alpha band that
8381 : * seems to apply to this band (specific rules yet to be determined) and that is
8382 : * of type GDT_Byte then that alpha band will be returned, and the flags
8383 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8384 : * </li>
8385 : * <li>If neither of the above apply, an instance of the new
8386 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8387 : * pixels. The null flags will return GMF_ALL_VALID.
8388 : * </li>
8389 : * </ul>
8390 : *
8391 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8392 : * dataset, with the same name as the main dataset and suffixed with .msk,
8393 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8394 : * main dataset.
8395 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8396 : * level, where xx matches the band number of a band of the main dataset. The
8397 : * value of those items is a combination of the flags GMF_ALL_VALID,
8398 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8399 : * a band, then the other rules explained above will be used to generate a
8400 : * on-the-fly mask band.
8401 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8402 : *
8403 : * This method is the same as the C function GDALGetMaskFlags().
8404 : *
8405 : * @since GDAL 1.5.0
8406 : *
8407 : * @return a valid mask band.
8408 : *
8409 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8410 : *
8411 : */
8412 79295 : int GDALRasterBand::GetMaskFlags()
8413 :
8414 : {
8415 : // If we don't have a band yet, force this now so that the masks value
8416 : // will be initialized.
8417 :
8418 79295 : if (poMask == nullptr)
8419 26610 : GetMaskBand();
8420 :
8421 79296 : return nMaskFlags;
8422 : }
8423 :
8424 : /************************************************************************/
8425 : /* GDALGetMaskFlags() */
8426 : /************************************************************************/
8427 :
8428 : /**
8429 : * \brief Return the status flags of the mask band associated with the band.
8430 : *
8431 : * @see GDALRasterBand::GetMaskFlags()
8432 : */
8433 :
8434 6155 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8435 :
8436 : {
8437 6155 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8438 :
8439 6155 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8440 6155 : return poBand->GetMaskFlags();
8441 : }
8442 :
8443 : /************************************************************************/
8444 : /* InvalidateMaskBand() */
8445 : /************************************************************************/
8446 :
8447 : //! @cond Doxygen_Suppress
8448 1201350 : void GDALRasterBand::InvalidateMaskBand()
8449 : {
8450 1201350 : poMask.reset();
8451 1201320 : nMaskFlags = 0;
8452 1201320 : }
8453 :
8454 : //! @endcond
8455 :
8456 : /************************************************************************/
8457 : /* CreateMaskBand() */
8458 : /************************************************************************/
8459 :
8460 : /**
8461 : * \brief Adds a mask band to the current band
8462 : *
8463 : * The default implementation of the CreateMaskBand() method is implemented
8464 : * based on similar rules to the .ovr handling implemented using the
8465 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8466 : * be created with the same basename as the original file, and it will have
8467 : * as many bands as the original image (or just one for GMF_PER_DATASET).
8468 : * The mask images will be deflate compressed tiled images with the same
8469 : * block size as the original image if possible.
8470 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8471 : * level, where xx matches the band number of a band of the main dataset. The
8472 : * value of those items will be the one of the nFlagsIn parameter.
8473 : *
8474 : * Note that if you got a mask band with a previous call to GetMaskBand(),
8475 : * it might be invalidated by CreateMaskBand(). So you have to call
8476 : * GetMaskBand() again.
8477 : *
8478 : * This method is the same as the C function GDALCreateMaskBand().
8479 : *
8480 : * @since GDAL 1.5.0
8481 : *
8482 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8483 : *
8484 : * @return CE_None on success or CE_Failure on an error.
8485 : *
8486 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8487 : * @see GDALDataset::CreateMaskBand()
8488 : *
8489 : */
8490 :
8491 9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8492 :
8493 : {
8494 9 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8495 : {
8496 9 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8497 9 : if (eErr != CE_None)
8498 1 : return eErr;
8499 :
8500 8 : InvalidateMaskBand();
8501 :
8502 8 : return CE_None;
8503 : }
8504 :
8505 0 : ReportError(CE_Failure, CPLE_NotSupported,
8506 : "CreateMaskBand() not supported for this band.");
8507 :
8508 0 : return CE_Failure;
8509 : }
8510 :
8511 : /************************************************************************/
8512 : /* GDALCreateMaskBand() */
8513 : /************************************************************************/
8514 :
8515 : /**
8516 : * \brief Adds a mask band to the current band
8517 : *
8518 : * @see GDALRasterBand::CreateMaskBand()
8519 : */
8520 :
8521 33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8522 :
8523 : {
8524 33 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8525 :
8526 33 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8527 33 : return poBand->CreateMaskBand(nFlags);
8528 : }
8529 :
8530 : /************************************************************************/
8531 : /* IsMaskBand() */
8532 : /************************************************************************/
8533 :
8534 : /**
8535 : * \brief Returns whether a band is a mask band.
8536 : *
8537 : * Mask band must be understood in the broad term: it can be a per-dataset
8538 : * mask band, an alpha band, or an implicit mask band.
8539 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8540 : *
8541 : * This method is the same as the C function GDALIsMaskBand().
8542 : *
8543 : * @return true if the band is a mask band.
8544 : *
8545 : * @see GDALDataset::CreateMaskBand()
8546 : *
8547 : * @since GDAL 3.5.0
8548 : *
8549 : */
8550 :
8551 411 : bool GDALRasterBand::IsMaskBand() const
8552 : {
8553 : // The GeoTIFF driver, among others, override this method to
8554 : // also handle external .msk bands.
8555 411 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8556 411 : GCI_AlphaBand;
8557 : }
8558 :
8559 : /************************************************************************/
8560 : /* GDALIsMaskBand() */
8561 : /************************************************************************/
8562 :
8563 : /**
8564 : * \brief Returns whether a band is a mask band.
8565 : *
8566 : * Mask band must be understood in the broad term: it can be a per-dataset
8567 : * mask band, an alpha band, or an implicit mask band.
8568 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8569 : *
8570 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8571 : *
8572 : * @return true if the band is a mask band.
8573 : *
8574 : * @see GDALRasterBand::IsMaskBand()
8575 : *
8576 : * @since GDAL 3.5.0
8577 : *
8578 : */
8579 :
8580 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
8581 :
8582 : {
8583 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8584 :
8585 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8586 37 : return poBand->IsMaskBand();
8587 : }
8588 :
8589 : /************************************************************************/
8590 : /* GetMaskValueRange() */
8591 : /************************************************************************/
8592 :
8593 : /**
8594 : * \brief Returns the range of values that a mask band can take.
8595 : *
8596 : * @return the range of values that a mask band can take.
8597 : *
8598 : * @since GDAL 3.5.0
8599 : *
8600 : */
8601 :
8602 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8603 : {
8604 0 : return GMVR_UNKNOWN;
8605 : }
8606 :
8607 : /************************************************************************/
8608 : /* GetIndexColorTranslationTo() */
8609 : /************************************************************************/
8610 :
8611 : /**
8612 : * \brief Compute translation table for color tables.
8613 : *
8614 : * When the raster band has a palette index, it may be useful to compute
8615 : * the "translation" of this palette to the palette of another band.
8616 : * The translation tries to do exact matching first, and then approximate
8617 : * matching if no exact matching is possible.
8618 : * This method returns a table such that table[i] = j where i is an index
8619 : * of the 'this' rasterband and j the corresponding index for the reference
8620 : * rasterband.
8621 : *
8622 : * This method is thought as internal to GDAL and is used for drivers
8623 : * like RPFTOC.
8624 : *
8625 : * The implementation only supports 1-byte palette rasterbands.
8626 : *
8627 : * @param poReferenceBand the raster band
8628 : * @param pTranslationTable an already allocated translation table (at least 256
8629 : * bytes), or NULL to let the method allocate it
8630 : * @param pApproximateMatching a pointer to a flag that is set if the matching
8631 : * is approximate. May be NULL.
8632 : *
8633 : * @return a translation table if the two bands are palette index and that they
8634 : * do not match or NULL in other cases. The table must be freed with CPLFree if
8635 : * NULL was passed for pTranslationTable.
8636 : */
8637 :
8638 : unsigned char *
8639 5 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8640 : unsigned char *pTranslationTable,
8641 : int *pApproximateMatching)
8642 : {
8643 5 : if (poReferenceBand == nullptr)
8644 0 : return nullptr;
8645 :
8646 : // cppcheck-suppress knownConditionTrueFalse
8647 5 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8648 : // cppcheck-suppress knownConditionTrueFalse
8649 5 : GetColorInterpretation() == GCI_PaletteIndex &&
8650 15 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
8651 5 : GetRasterDataType() == GDT_Byte)
8652 : {
8653 5 : const GDALColorTable *srcColorTable = GetColorTable();
8654 5 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8655 5 : if (srcColorTable != nullptr && destColorTable != nullptr)
8656 : {
8657 5 : const int nEntries = srcColorTable->GetColorEntryCount();
8658 5 : const int nRefEntries = destColorTable->GetColorEntryCount();
8659 :
8660 5 : int bHasNoDataValueSrc = FALSE;
8661 5 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8662 5 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8663 4 : dfNoDataValueSrc <= 255 &&
8664 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8665 1 : bHasNoDataValueSrc = FALSE;
8666 5 : const int noDataValueSrc =
8667 5 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8668 :
8669 5 : int bHasNoDataValueRef = FALSE;
8670 : const double dfNoDataValueRef =
8671 5 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8672 5 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8673 3 : dfNoDataValueRef <= 255 &&
8674 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8675 2 : bHasNoDataValueRef = FALSE;
8676 5 : const int noDataValueRef =
8677 5 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8678 :
8679 5 : bool samePalette = false;
8680 :
8681 5 : if (pApproximateMatching)
8682 3 : *pApproximateMatching = FALSE;
8683 :
8684 5 : if (nEntries == nRefEntries &&
8685 4 : bHasNoDataValueSrc == bHasNoDataValueRef &&
8686 4 : (bHasNoDataValueSrc == FALSE ||
8687 : noDataValueSrc == noDataValueRef))
8688 : {
8689 4 : samePalette = true;
8690 911 : for (int i = 0; i < nEntries; ++i)
8691 : {
8692 907 : if (noDataValueSrc == i)
8693 4 : continue;
8694 : const GDALColorEntry *entry =
8695 903 : srcColorTable->GetColorEntry(i);
8696 : const GDALColorEntry *entryRef =
8697 903 : destColorTable->GetColorEntry(i);
8698 903 : if (entry->c1 != entryRef->c1 ||
8699 903 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8700 : {
8701 0 : samePalette = false;
8702 : }
8703 : }
8704 : }
8705 :
8706 5 : if (!samePalette)
8707 : {
8708 1 : if (pTranslationTable == nullptr)
8709 : {
8710 : pTranslationTable = static_cast<unsigned char *>(
8711 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8712 1 : if (pTranslationTable == nullptr)
8713 1 : return nullptr;
8714 : }
8715 :
8716 : // Trying to remap the product palette on the subdataset
8717 : // palette.
8718 5 : for (int i = 0; i < nEntries; ++i)
8719 : {
8720 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8721 : noDataValueSrc == i)
8722 0 : continue;
8723 : const GDALColorEntry *entry =
8724 4 : srcColorTable->GetColorEntry(i);
8725 4 : bool bMatchFound = false;
8726 13 : for (int j = 0; j < nRefEntries; ++j)
8727 : {
8728 10 : if (bHasNoDataValueRef && noDataValueRef == j)
8729 0 : continue;
8730 : const GDALColorEntry *entryRef =
8731 10 : destColorTable->GetColorEntry(j);
8732 10 : if (entry->c1 == entryRef->c1 &&
8733 2 : entry->c2 == entryRef->c2 &&
8734 2 : entry->c3 == entryRef->c3)
8735 : {
8736 1 : pTranslationTable[i] =
8737 : static_cast<unsigned char>(j);
8738 1 : bMatchFound = true;
8739 1 : break;
8740 : }
8741 : }
8742 4 : if (!bMatchFound)
8743 : {
8744 : // No exact match. Looking for closest color now.
8745 3 : int best_j = 0;
8746 3 : int best_distance = 0;
8747 3 : if (pApproximateMatching)
8748 0 : *pApproximateMatching = TRUE;
8749 12 : for (int j = 0; j < nRefEntries; ++j)
8750 : {
8751 : const GDALColorEntry *entryRef =
8752 9 : destColorTable->GetColorEntry(j);
8753 9 : int distance = (entry->c1 - entryRef->c1) *
8754 9 : (entry->c1 - entryRef->c1) +
8755 9 : (entry->c2 - entryRef->c2) *
8756 9 : (entry->c2 - entryRef->c2) +
8757 9 : (entry->c3 - entryRef->c3) *
8758 9 : (entry->c3 - entryRef->c3);
8759 9 : if (j == 0 || distance < best_distance)
8760 : {
8761 7 : best_j = j;
8762 7 : best_distance = distance;
8763 : }
8764 : }
8765 3 : pTranslationTable[i] =
8766 : static_cast<unsigned char>(best_j);
8767 : }
8768 : }
8769 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
8770 0 : pTranslationTable[noDataValueSrc] =
8771 : static_cast<unsigned char>(noDataValueRef);
8772 :
8773 1 : return pTranslationTable;
8774 : }
8775 : }
8776 : }
8777 4 : return nullptr;
8778 : }
8779 :
8780 : /************************************************************************/
8781 : /* SetFlushBlockErr() */
8782 : /************************************************************************/
8783 :
8784 : /**
8785 : * \brief Store that an error occurred while writing a dirty block.
8786 : *
8787 : * This function stores the fact that an error occurred while writing a dirty
8788 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8789 : * flushed when the block cache get full, it is not convenient/possible to
8790 : * report that a dirty block could not be written correctly. This function
8791 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8792 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8793 : * places where the user can easily match the error with the relevant dataset.
8794 : */
8795 :
8796 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8797 : {
8798 0 : eFlushBlockErr = eErr;
8799 0 : }
8800 :
8801 : /************************************************************************/
8802 : /* IncDirtyBlocks() */
8803 : /************************************************************************/
8804 :
8805 : /**
8806 : * \brief Increment/decrement the number of dirty blocks
8807 : */
8808 :
8809 520416 : void GDALRasterBand::IncDirtyBlocks(int nInc)
8810 : {
8811 520416 : if (poBandBlockCache)
8812 520415 : poBandBlockCache->IncDirtyBlocks(nInc);
8813 520434 : }
8814 :
8815 : /************************************************************************/
8816 : /* ReportError() */
8817 : /************************************************************************/
8818 :
8819 : #ifndef DOXYGEN_XML
8820 : /**
8821 : * \brief Emits an error related to a raster band.
8822 : *
8823 : * This function is a wrapper for regular CPLError(). The only difference
8824 : * with CPLError() is that it prepends the error message with the dataset
8825 : * name and the band number.
8826 : *
8827 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
8828 : * @param err_no the error number (CPLE_*) from cpl_error.h.
8829 : * @param fmt a printf() style format string. Any additional arguments
8830 : * will be treated as arguments to fill in this format in a manner
8831 : * similar to printf().
8832 : *
8833 : * @since GDAL 1.9.0
8834 : */
8835 :
8836 2448 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
8837 : const char *fmt, ...) const
8838 : {
8839 : va_list args;
8840 :
8841 2448 : va_start(args, fmt);
8842 :
8843 2448 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
8844 2448 : pszDSName = CPLGetFilename(pszDSName);
8845 2448 : if (pszDSName[0] != '\0')
8846 : {
8847 2392 : CPLError(eErrClass, err_no, "%s",
8848 4784 : CPLString()
8849 2392 : .Printf("%s, band %d: ", pszDSName, GetBand())
8850 4784 : .append(CPLString().vPrintf(fmt, args))
8851 : .c_str());
8852 : }
8853 : else
8854 : {
8855 56 : CPLErrorV(eErrClass, err_no, fmt, args);
8856 : }
8857 :
8858 2448 : va_end(args);
8859 2448 : }
8860 : #endif
8861 :
8862 : /************************************************************************/
8863 : /* GetVirtualMemAuto() */
8864 : /************************************************************************/
8865 :
8866 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
8867 : *
8868 : * Only supported on Linux and Unix systems with mmap() for now.
8869 : *
8870 : * This method allows creating a virtual memory object for a GDALRasterBand,
8871 : * that exposes the whole image data as a virtual array.
8872 : *
8873 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
8874 : * specialized implementation, such as for raw files, may also directly use
8875 : * mechanisms of the operating system to create a view of the underlying file
8876 : * into virtual memory ( CPLVirtualMemFileMapNew() )
8877 : *
8878 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
8879 : * offer a specialized implementation with direct file mapping, provided that
8880 : * some requirements are met :
8881 : * - for all drivers, the dataset must be backed by a "real" file in the file
8882 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
8883 : * must match the native ordering of the CPU.
8884 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
8885 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
8886 : * the file in sequential order, and be equally spaced (which is generally the
8887 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
8888 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
8889 : *
8890 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
8891 : * CPLVirtualMemFree() must be called before the raster band object is
8892 : * destroyed.
8893 : *
8894 : * If p is such a pointer and base_type the type matching
8895 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
8896 : * accessed with
8897 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
8898 : *
8899 : * This method is the same as the C GDALGetVirtualMemAuto() function.
8900 : *
8901 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
8902 : * read/write the band.
8903 : *
8904 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
8905 : * one pixel value in the buffer to the start of the next pixel value within a
8906 : * scanline.
8907 : *
8908 : * @param pnLineSpace Output parameter giving the byte offset from the start of
8909 : * one scanline in the buffer to the start of the next.
8910 : *
8911 : * @param papszOptions NULL terminated list of options.
8912 : * If a specialized implementation exists, defining
8913 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
8914 : * used. On the contrary, starting with GDAL 2.2, defining
8915 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
8916 : * being used (thus only allowing efficient implementations to be used). When
8917 : * requiring or falling back to the default implementation, the following
8918 : * options are available : CACHE_SIZE (in bytes, defaults to
8919 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
8920 : * to FALSE)
8921 : *
8922 : * @return a virtual memory object that must be unreferenced by
8923 : * CPLVirtualMemFree(), or NULL in case of failure.
8924 : *
8925 : * @since GDAL 1.11
8926 : */
8927 :
8928 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
8929 : int *pnPixelSpace,
8930 : GIntBig *pnLineSpace,
8931 : char **papszOptions)
8932 : {
8933 9 : const char *pszImpl = CSLFetchNameValueDef(
8934 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
8935 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
8936 8 : EQUAL(pszImpl, "FALSE"))
8937 : {
8938 1 : return nullptr;
8939 : }
8940 :
8941 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
8942 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
8943 8 : if (pnPixelSpace)
8944 8 : *pnPixelSpace = nPixelSpace;
8945 8 : if (pnLineSpace)
8946 8 : *pnLineSpace = nLineSpace;
8947 : const size_t nCacheSize =
8948 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
8949 : const size_t nPageSizeHint =
8950 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
8951 8 : const bool bSingleThreadUsage = CPLTestBool(
8952 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
8953 8 : return GDALRasterBandGetVirtualMem(
8954 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
8955 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
8956 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
8957 8 : papszOptions);
8958 : }
8959 :
8960 : /************************************************************************/
8961 : /* GDALGetVirtualMemAuto() */
8962 : /************************************************************************/
8963 :
8964 : /**
8965 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
8966 : *
8967 : * @see GDALRasterBand::GetVirtualMemAuto()
8968 : */
8969 :
8970 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
8971 : int *pnPixelSpace, GIntBig *pnLineSpace,
8972 : CSLConstList papszOptions)
8973 : {
8974 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
8975 :
8976 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8977 :
8978 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
8979 31 : const_cast<char **>(papszOptions));
8980 : }
8981 :
8982 : /************************************************************************/
8983 : /* GDALGetDataCoverageStatus() */
8984 : /************************************************************************/
8985 :
8986 : /**
8987 : * \brief Get the coverage status of a sub-window of the raster.
8988 : *
8989 : * Returns whether a sub-window of the raster contains only data, only empty
8990 : * blocks or a mix of both. This function can be used to determine quickly
8991 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
8992 : * be sparse.
8993 : *
8994 : * Empty blocks are blocks that are generally not physically present in the
8995 : * file, and when read through GDAL, contain only pixels whose value is the
8996 : * nodata value when it is set, or whose value is 0 when the nodata value is
8997 : * not set.
8998 : *
8999 : * The query is done in an efficient way without reading the actual pixel
9000 : * values. If not possible, or not implemented at all by the driver,
9001 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9002 : * be returned.
9003 : *
9004 : * The values that can be returned by the function are the following,
9005 : * potentially combined with the binary or operator :
9006 : * <ul>
9007 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9008 : * GetDataCoverageStatus(). This flag should be returned together with
9009 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9010 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9011 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9012 : * the queried window. This is typically identified by the concept of missing
9013 : * block in formats that supports it.
9014 : * </li>
9015 : * </ul>
9016 : *
9017 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9018 : * should be interpreted more as hint of potential presence of data. For example
9019 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9020 : * nodata value), instead of using the missing block mechanism,
9021 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9022 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9023 : *
9024 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9025 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9026 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9027 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9028 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9029 : * the function will exit, so that you can potentially refine the requested area
9030 : * to find which particular region(s) have missing blocks.
9031 : *
9032 : * @see GDALRasterBand::GetDataCoverageStatus()
9033 : *
9034 : * @param hBand raster band
9035 : *
9036 : * @param nXOff The pixel offset to the top left corner of the region
9037 : * of the band to be queried. This would be zero to start from the left side.
9038 : *
9039 : * @param nYOff The line offset to the top left corner of the region
9040 : * of the band to be queried. This would be zero to start from the top.
9041 : *
9042 : * @param nXSize The width of the region of the band to be queried in pixels.
9043 : *
9044 : * @param nYSize The height of the region of the band to be queried in lines.
9045 : *
9046 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9047 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9048 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9049 : * as the computation of the coverage matches the mask, the computation will be
9050 : * stopped. *pdfDataPct will not be valid in that case.
9051 : *
9052 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9053 : * to the (approximate) percentage in [0,100] of pixels in the queried
9054 : * sub-window that have valid values. The implementation might not always be
9055 : * able to compute it, in which case it will be set to a negative value.
9056 : *
9057 : * @return a binary-or'ed combination of possible values
9058 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9059 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9060 : *
9061 : * @note Added in GDAL 2.2
9062 : */
9063 :
9064 26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
9065 : int nYOff, int nXSize, int nYSize,
9066 : int nMaskFlagStop, double *pdfDataPct)
9067 : {
9068 26 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
9069 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
9070 :
9071 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9072 :
9073 26 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
9074 26 : nMaskFlagStop, pdfDataPct);
9075 : }
9076 :
9077 : /************************************************************************/
9078 : /* GetDataCoverageStatus() */
9079 : /************************************************************************/
9080 :
9081 : /**
9082 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
9083 : * int nYOff,
9084 : * int nXSize,
9085 : * int nYSize,
9086 : * int nMaskFlagStop,
9087 : * double* pdfDataPct)
9088 : * \brief Get the coverage status of a sub-window of the raster.
9089 : *
9090 : * Returns whether a sub-window of the raster contains only data, only empty
9091 : * blocks or a mix of both. This function can be used to determine quickly
9092 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9093 : * be sparse.
9094 : *
9095 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9096 : * value when it is set, or whose value is 0 when the nodata value is not set.
9097 : *
9098 : * The query is done in an efficient way without reading the actual pixel
9099 : * values. If not possible, or not implemented at all by the driver,
9100 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9101 : * be returned.
9102 : *
9103 : * The values that can be returned by the function are the following,
9104 : * potentially combined with the binary or operator :
9105 : * <ul>
9106 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9107 : * GetDataCoverageStatus(). This flag should be returned together with
9108 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9109 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9110 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9111 : * the queried window. This is typically identified by the concept of missing
9112 : * block in formats that supports it.
9113 : * </li>
9114 : * </ul>
9115 : *
9116 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9117 : * should be interpreted more as hint of potential presence of data. For example
9118 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9119 : * nodata value), instead of using the missing block mechanism,
9120 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9121 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9122 : *
9123 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9124 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9125 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9126 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9127 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9128 : * the function will exit, so that you can potentially refine the requested area
9129 : * to find which particular region(s) have missing blocks.
9130 : *
9131 : * @see GDALGetDataCoverageStatus()
9132 : *
9133 : * @param nXOff The pixel offset to the top left corner of the region
9134 : * of the band to be queried. This would be zero to start from the left side.
9135 : *
9136 : * @param nYOff The line offset to the top left corner of the region
9137 : * of the band to be queried. This would be zero to start from the top.
9138 : *
9139 : * @param nXSize The width of the region of the band to be queried in pixels.
9140 : *
9141 : * @param nYSize The height of the region of the band to be queried in lines.
9142 : *
9143 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9144 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9145 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9146 : * as the computation of the coverage matches the mask, the computation will be
9147 : * stopped. *pdfDataPct will not be valid in that case.
9148 : *
9149 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9150 : * to the (approximate) percentage in [0,100] of pixels in the queried
9151 : * sub-window that have valid values. The implementation might not always be
9152 : * able to compute it, in which case it will be set to a negative value.
9153 : *
9154 : * @return a binary-or'ed combination of possible values
9155 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9156 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9157 : *
9158 : * @note Added in GDAL 2.2
9159 : */
9160 :
9161 : /**
9162 : * \brief Get the coverage status of a sub-window of the raster.
9163 : *
9164 : * Returns whether a sub-window of the raster contains only data, only empty
9165 : * blocks or a mix of both. This function can be used to determine quickly
9166 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9167 : * be sparse.
9168 : *
9169 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9170 : * value when it is set, or whose value is 0 when the nodata value is not set.
9171 : *
9172 : * The query is done in an efficient way without reading the actual pixel
9173 : * values. If not possible, or not implemented at all by the driver,
9174 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9175 : * be returned.
9176 : *
9177 : * The values that can be returned by the function are the following,
9178 : * potentially combined with the binary or operator :
9179 : * <ul>
9180 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9181 : * GetDataCoverageStatus(). This flag should be returned together with
9182 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9183 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9184 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9185 : * the queried window. This is typically identified by the concept of missing
9186 : * block in formats that supports it.
9187 : * </li>
9188 : * </ul>
9189 : *
9190 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9191 : * should be interpreted more as hint of potential presence of data. For example
9192 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9193 : * nodata value), instead of using the missing block mechanism,
9194 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9195 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9196 : *
9197 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9198 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9199 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9200 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9201 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9202 : * the function will exit, so that you can potentially refine the requested area
9203 : * to find which particular region(s) have missing blocks.
9204 : *
9205 : * @see GDALGetDataCoverageStatus()
9206 : *
9207 : * @param nXOff The pixel offset to the top left corner of the region
9208 : * of the band to be queried. This would be zero to start from the left side.
9209 : *
9210 : * @param nYOff The line offset to the top left corner of the region
9211 : * of the band to be queried. This would be zero to start from the top.
9212 : *
9213 : * @param nXSize The width of the region of the band to be queried in pixels.
9214 : *
9215 : * @param nYSize The height of the region of the band to be queried in lines.
9216 : *
9217 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9218 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9219 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9220 : * as the computation of the coverage matches the mask, the computation will be
9221 : * stopped. *pdfDataPct will not be valid in that case.
9222 : *
9223 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9224 : * to the (approximate) percentage in [0,100] of pixels in the queried
9225 : * sub-window that have valid values. The implementation might not always be
9226 : * able to compute it, in which case it will be set to a negative value.
9227 : *
9228 : * @return a binary-or'ed combination of possible values
9229 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9230 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9231 : *
9232 : * @note Added in GDAL 2.2
9233 : */
9234 :
9235 2745 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9236 : int nYSize, int nMaskFlagStop,
9237 : double *pdfDataPct)
9238 : {
9239 2745 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9240 2745 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9241 2745 : nYOff + nYSize > nRasterYSize)
9242 : {
9243 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9244 0 : if (pdfDataPct)
9245 0 : *pdfDataPct = 0.0;
9246 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9247 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
9248 : }
9249 2745 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9250 2745 : pdfDataPct);
9251 : }
9252 :
9253 : /************************************************************************/
9254 : /* IGetDataCoverageStatus() */
9255 : /************************************************************************/
9256 :
9257 510 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9258 : int /*nXSize*/, int /*nYSize*/,
9259 : int /*nMaskFlagStop*/,
9260 : double *pdfDataPct)
9261 : {
9262 510 : if (pdfDataPct != nullptr)
9263 0 : *pdfDataPct = 100.0;
9264 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9265 510 : GDAL_DATA_COVERAGE_STATUS_DATA;
9266 : }
9267 :
9268 : //! @cond Doxygen_Suppress
9269 : /************************************************************************/
9270 : /* EnterReadWrite() */
9271 : /************************************************************************/
9272 :
9273 6914140 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9274 : {
9275 6914140 : if (poDS != nullptr)
9276 6157240 : return poDS->EnterReadWrite(eRWFlag);
9277 756903 : return FALSE;
9278 : }
9279 :
9280 : /************************************************************************/
9281 : /* LeaveReadWrite() */
9282 : /************************************************************************/
9283 :
9284 646523 : void GDALRasterBand::LeaveReadWrite()
9285 : {
9286 646523 : if (poDS != nullptr)
9287 646523 : poDS->LeaveReadWrite();
9288 646515 : }
9289 :
9290 : /************************************************************************/
9291 : /* InitRWLock() */
9292 : /************************************************************************/
9293 :
9294 3647580 : void GDALRasterBand::InitRWLock()
9295 : {
9296 3647580 : if (poDS != nullptr)
9297 3647180 : poDS->InitRWLock();
9298 3647580 : }
9299 :
9300 : //! @endcond
9301 :
9302 : // clang-format off
9303 :
9304 : /**
9305 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9306 : * \brief Set metadata.
9307 : *
9308 : * CAUTION: depending on the format, older values of the updated information
9309 : * might still be found in the file in a "ghost" state, even if no longer
9310 : * accessible through the GDAL API. This is for example the case of the GTiff
9311 : * format (this is not a exhaustive list)
9312 : *
9313 : * The C function GDALSetMetadata() does the same thing as this method.
9314 : *
9315 : * @param papszMetadata the metadata in name=value string list format to
9316 : * apply.
9317 : * @param pszDomain the domain of interest. Use "" or NULL for the default
9318 : * domain.
9319 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9320 : * metadata has been accepted, but is likely not maintained persistently
9321 : * by the underlying object between sessions.
9322 : */
9323 :
9324 : /**
9325 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9326 : * \brief Set single metadata item.
9327 : *
9328 : * CAUTION: depending on the format, older values of the updated information
9329 : * might still be found in the file in a "ghost" state, even if no longer
9330 : * accessible through the GDAL API. This is for example the case of the GTiff
9331 : * format (this is not a exhaustive list)
9332 : *
9333 : * The C function GDALSetMetadataItem() does the same thing as this method.
9334 : *
9335 : * @param pszName the key for the metadata item to fetch.
9336 : * @param pszValue the value to assign to the key.
9337 : * @param pszDomain the domain to set within, use NULL for the default domain.
9338 : *
9339 : * @return CE_None on success, or an error code on failure.
9340 : */
9341 :
9342 : // clang-format on
9343 :
9344 : //! @cond Doxygen_Suppress
9345 : /************************************************************************/
9346 : /* EnablePixelTypeSignedByteWarning() */
9347 : /************************************************************************/
9348 :
9349 28064 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9350 : {
9351 28064 : m_bEnablePixelTypeSignedByteWarning = b;
9352 28064 : }
9353 :
9354 8416 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9355 : {
9356 8416 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9357 8416 : }
9358 :
9359 : //! @endcond
9360 :
9361 : /************************************************************************/
9362 : /* GetMetadataItem() */
9363 : /************************************************************************/
9364 :
9365 61713 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9366 : const char *pszDomain)
9367 : {
9368 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9369 61713 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9370 36976 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9371 28059 : EQUAL(pszName, "PIXELTYPE"))
9372 : {
9373 2 : CPLError(CE_Warning, CPLE_AppDefined,
9374 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9375 : "used to signal signed 8-bit raster. Change your code to "
9376 : "test for the new GDT_Int8 data type instead.");
9377 : }
9378 61713 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9379 : }
9380 :
9381 : /************************************************************************/
9382 : /* GDALMDArrayFromRasterBand */
9383 : /************************************************************************/
9384 :
9385 : class GDALMDArrayFromRasterBand final : public GDALMDArray
9386 : {
9387 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9388 :
9389 : GDALDataset *m_poDS;
9390 : GDALRasterBand *m_poBand;
9391 : GDALExtendedDataType m_dt;
9392 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9393 : std::string m_osUnit;
9394 : std::vector<GByte> m_pabyNoData{};
9395 : std::shared_ptr<GDALMDArray> m_varX{};
9396 : std::shared_ptr<GDALMDArray> m_varY{};
9397 : std::string m_osFilename{};
9398 :
9399 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9400 : const size_t *count, const GInt64 *arrayStep,
9401 : const GPtrDiff_t *bufferStride,
9402 : const GDALExtendedDataType &bufferDataType,
9403 : void *pBuffer) const;
9404 :
9405 : protected:
9406 23 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9407 46 : : GDALAbstractMDArray(std::string(),
9408 46 : std::string(poDS->GetDescription()) +
9409 : CPLSPrintf(" band %d", poBand->GetBand())),
9410 46 : GDALMDArray(std::string(),
9411 46 : std::string(poDS->GetDescription()) +
9412 : CPLSPrintf(" band %d", poBand->GetBand())),
9413 : m_poDS(poDS), m_poBand(poBand),
9414 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9415 115 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9416 : {
9417 23 : m_poDS->Reference();
9418 :
9419 23 : int bHasNoData = false;
9420 23 : if (m_poBand->GetRasterDataType() == GDT_Int64)
9421 : {
9422 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9423 0 : if (bHasNoData)
9424 : {
9425 0 : m_pabyNoData.resize(m_dt.GetSize());
9426 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9427 : m_dt.GetNumericDataType(), 0, 1);
9428 : }
9429 : }
9430 23 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9431 : {
9432 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9433 0 : if (bHasNoData)
9434 : {
9435 0 : m_pabyNoData.resize(m_dt.GetSize());
9436 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9437 : m_dt.GetNumericDataType(), 0, 1);
9438 : }
9439 : }
9440 : else
9441 : {
9442 23 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9443 23 : if (bHasNoData)
9444 : {
9445 1 : m_pabyNoData.resize(m_dt.GetSize());
9446 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9447 : m_dt.GetNumericDataType(), 0, 1);
9448 : }
9449 : }
9450 :
9451 23 : const int nXSize = poBand->GetXSize();
9452 23 : const int nYSize = poBand->GetYSize();
9453 :
9454 23 : auto poSRS = m_poDS->GetSpatialRef();
9455 46 : std::string osTypeY;
9456 46 : std::string osTypeX;
9457 46 : std::string osDirectionY;
9458 46 : std::string osDirectionX;
9459 23 : if (poSRS && poSRS->GetAxesCount() == 2)
9460 : {
9461 21 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9462 21 : OGRAxisOrientation eOrientation1 = OAO_Other;
9463 21 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
9464 21 : OGRAxisOrientation eOrientation2 = OAO_Other;
9465 21 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
9466 21 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9467 : {
9468 5 : if (mapping == std::vector<int>{1, 2})
9469 : {
9470 5 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9471 5 : osDirectionY = "NORTH";
9472 5 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9473 5 : osDirectionX = "EAST";
9474 : }
9475 : }
9476 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9477 : {
9478 16 : if (mapping == std::vector<int>{2, 1})
9479 : {
9480 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9481 16 : osDirectionY = "NORTH";
9482 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9483 16 : osDirectionX = "EAST";
9484 : }
9485 : }
9486 : }
9487 :
9488 115 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9489 : "/", "Y", osTypeY, osDirectionY, nYSize),
9490 46 : std::make_shared<GDALDimensionWeakIndexingVar>(
9491 69 : "/", "X", osTypeX, osDirectionX, nXSize)};
9492 :
9493 : double adfGeoTransform[6];
9494 23 : if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
9495 23 : adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
9496 : {
9497 44 : m_varX = GDALMDArrayRegularlySpaced::Create(
9498 22 : "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
9499 22 : 0.5);
9500 22 : m_dims[1]->SetIndexingVariable(m_varX);
9501 :
9502 44 : m_varY = GDALMDArrayRegularlySpaced::Create(
9503 22 : "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
9504 22 : 0.5);
9505 22 : m_dims[0]->SetIndexingVariable(m_varY);
9506 : }
9507 23 : }
9508 :
9509 31 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9510 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9511 : const GDALExtendedDataType &bufferDataType,
9512 : void *pDstBuffer) const override
9513 : {
9514 31 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9515 31 : bufferDataType, pDstBuffer);
9516 : }
9517 :
9518 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9519 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9520 : const GDALExtendedDataType &bufferDataType,
9521 : const void *pSrcBuffer) override
9522 : {
9523 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9524 : bufferStride, bufferDataType,
9525 1 : const_cast<void *>(pSrcBuffer));
9526 : }
9527 :
9528 : public:
9529 46 : ~GDALMDArrayFromRasterBand()
9530 23 : {
9531 23 : m_poDS->ReleaseRef();
9532 46 : }
9533 :
9534 23 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9535 : GDALRasterBand *poBand)
9536 : {
9537 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9538 46 : new GDALMDArrayFromRasterBand(poDS, poBand)));
9539 23 : array->SetSelf(array);
9540 46 : return array;
9541 : }
9542 :
9543 2 : bool IsWritable() const override
9544 : {
9545 2 : return m_poDS->GetAccess() == GA_Update;
9546 : }
9547 :
9548 97 : const std::string &GetFilename() const override
9549 : {
9550 97 : return m_osFilename;
9551 : }
9552 :
9553 : const std::vector<std::shared_ptr<GDALDimension>> &
9554 299 : GetDimensions() const override
9555 : {
9556 299 : return m_dims;
9557 : }
9558 :
9559 138 : const GDALExtendedDataType &GetDataType() const override
9560 : {
9561 138 : return m_dt;
9562 : }
9563 :
9564 3 : const std::string &GetUnit() const override
9565 : {
9566 3 : return m_osUnit;
9567 : }
9568 :
9569 29 : const void *GetRawNoDataValue() const override
9570 : {
9571 29 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9572 : }
9573 :
9574 2 : double GetOffset(bool *pbHasOffset,
9575 : GDALDataType *peStorageType) const override
9576 : {
9577 2 : int bHasOffset = false;
9578 2 : double dfRes = m_poBand->GetOffset(&bHasOffset);
9579 2 : if (pbHasOffset)
9580 2 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9581 2 : if (peStorageType)
9582 1 : *peStorageType = GDT_Unknown;
9583 2 : return dfRes;
9584 : }
9585 :
9586 2 : double GetScale(bool *pbHasScale,
9587 : GDALDataType *peStorageType) const override
9588 : {
9589 2 : int bHasScale = false;
9590 2 : double dfRes = m_poBand->GetScale(&bHasScale);
9591 2 : if (pbHasScale)
9592 2 : *pbHasScale = CPL_TO_BOOL(bHasScale);
9593 2 : if (peStorageType)
9594 1 : *peStorageType = GDT_Unknown;
9595 2 : return dfRes;
9596 : }
9597 :
9598 84 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9599 : {
9600 84 : auto poSrcSRS = m_poDS->GetSpatialRef();
9601 84 : if (!poSrcSRS)
9602 2 : return nullptr;
9603 164 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9604 :
9605 164 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9606 82 : constexpr int iYDim = 0;
9607 82 : constexpr int iXDim = 1;
9608 246 : for (auto &m : axisMapping)
9609 : {
9610 164 : if (m == 1)
9611 82 : m = iXDim + 1;
9612 82 : else if (m == 2)
9613 82 : m = iYDim + 1;
9614 : else
9615 0 : m = 0;
9616 : }
9617 82 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9618 82 : return poSRS;
9619 : }
9620 :
9621 29 : std::vector<GUInt64> GetBlockSize() const override
9622 : {
9623 29 : int nBlockXSize = 0;
9624 29 : int nBlockYSize = 0;
9625 29 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9626 29 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9627 29 : static_cast<GUInt64>(nBlockXSize)};
9628 : }
9629 :
9630 : class MDIAsAttribute : public GDALAttribute
9631 : {
9632 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9633 : const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
9634 : std::string m_osValue;
9635 :
9636 : public:
9637 2 : MDIAsAttribute(const std::string &name, const std::string &value)
9638 2 : : GDALAbstractMDArray(std::string(), name),
9639 4 : GDALAttribute(std::string(), name), m_osValue(value)
9640 : {
9641 2 : }
9642 :
9643 : const std::vector<std::shared_ptr<GDALDimension>> &
9644 3 : GetDimensions() const override
9645 : {
9646 3 : return m_dims;
9647 : }
9648 :
9649 2 : const GDALExtendedDataType &GetDataType() const override
9650 : {
9651 2 : return m_dt;
9652 : }
9653 :
9654 1 : bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
9655 : const GPtrDiff_t *,
9656 : const GDALExtendedDataType &bufferDataType,
9657 : void *pDstBuffer) const override
9658 : {
9659 1 : const char *pszStr = m_osValue.c_str();
9660 1 : GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
9661 : bufferDataType);
9662 1 : return true;
9663 : }
9664 : };
9665 :
9666 : std::vector<std::shared_ptr<GDALAttribute>>
9667 14 : GetAttributes(CSLConstList) const override
9668 : {
9669 14 : std::vector<std::shared_ptr<GDALAttribute>> res;
9670 14 : auto papszMD = m_poBand->GetMetadata();
9671 16 : for (auto iter = papszMD; iter && iter[0]; ++iter)
9672 : {
9673 2 : char *pszKey = nullptr;
9674 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9675 2 : if (pszKey && pszValue)
9676 : {
9677 : res.emplace_back(
9678 2 : std::make_shared<MDIAsAttribute>(pszKey, pszValue));
9679 : }
9680 2 : CPLFree(pszKey);
9681 : }
9682 14 : return res;
9683 : }
9684 : };
9685 :
9686 : /************************************************************************/
9687 : /* ReadWrite() */
9688 : /************************************************************************/
9689 :
9690 32 : bool GDALMDArrayFromRasterBand::ReadWrite(
9691 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
9692 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9693 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
9694 : {
9695 32 : constexpr size_t iDimX = 1;
9696 32 : constexpr size_t iDimY = 0;
9697 32 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
9698 : arrayStartIdx, count, arrayStep, bufferStride,
9699 32 : bufferDataType, pBuffer);
9700 : }
9701 :
9702 : /************************************************************************/
9703 : /* GDALMDRasterIOFromBand() */
9704 : /************************************************************************/
9705 :
9706 65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
9707 : size_t iDimX, size_t iDimY,
9708 : const GUInt64 *arrayStartIdx, const size_t *count,
9709 : const GInt64 *arrayStep,
9710 : const GPtrDiff_t *bufferStride,
9711 : const GDALExtendedDataType &bufferDataType,
9712 : void *pBuffer)
9713 : {
9714 65 : const auto eDT(bufferDataType.GetNumericDataType());
9715 65 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
9716 65 : const int nX =
9717 65 : arrayStep[iDimX] > 0
9718 65 : ? static_cast<int>(arrayStartIdx[iDimX])
9719 2 : : static_cast<int>(arrayStartIdx[iDimX] -
9720 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
9721 65 : const int nY =
9722 65 : arrayStep[iDimY] > 0
9723 65 : ? static_cast<int>(arrayStartIdx[iDimY])
9724 2 : : static_cast<int>(arrayStartIdx[iDimY] -
9725 2 : (count[iDimY] - 1) * -arrayStep[iDimY]);
9726 65 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
9727 65 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
9728 65 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
9729 65 : int nStrideXSign = 1;
9730 65 : if (arrayStep[iDimX] < 0)
9731 : {
9732 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
9733 2 : nStrideXSign = -1;
9734 : }
9735 65 : int nStrideYSign = 1;
9736 65 : if (arrayStep[iDimY] < 0)
9737 : {
9738 2 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
9739 2 : nStrideYSign = -1;
9740 : }
9741 :
9742 130 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
9743 65 : static_cast<int>(count[iDimX]),
9744 65 : static_cast<int>(count[iDimY]), eDT,
9745 : static_cast<GSpacing>(
9746 65 : nStrideXSign * bufferStride[iDimX] * nDTSize),
9747 : static_cast<GSpacing>(
9748 65 : nStrideYSign * bufferStride[iDimY] * nDTSize),
9749 65 : nullptr) == CE_None;
9750 : }
9751 :
9752 : /************************************************************************/
9753 : /* AsMDArray() */
9754 : /************************************************************************/
9755 :
9756 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
9757 : *
9758 : * The band must be linked to a GDALDataset. If this dataset is not already
9759 : * marked as shared, it will be, so that the returned array holds a reference
9760 : * to it.
9761 : *
9762 : * If the dataset has a geotransform attached, the X and Y dimensions of the
9763 : * returned array will have an associated indexing variable.
9764 : *
9765 : * This is the same as the C function GDALRasterBandAsMDArray().
9766 : *
9767 : * The "reverse" method is GDALMDArray::AsClassicDataset().
9768 : *
9769 : * @return a new array, or nullptr.
9770 : *
9771 : * @since GDAL 3.1
9772 : */
9773 23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
9774 : {
9775 23 : if (!poDS)
9776 : {
9777 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
9778 0 : return nullptr;
9779 : }
9780 23 : if (!poDS->GetShared())
9781 : {
9782 23 : poDS->MarkAsShared();
9783 : }
9784 : return GDALMDArrayFromRasterBand::Create(
9785 23 : poDS, const_cast<GDALRasterBand *>(this));
9786 : }
9787 :
9788 : /************************************************************************/
9789 : /* InterpolateAtPoint() */
9790 : /************************************************************************/
9791 :
9792 : /**
9793 : * \brief Interpolates the value between pixels using a resampling algorithm,
9794 : * taking pixel/line coordinates as input.
9795 : *
9796 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
9797 : * @param dfLine line coordinate as a double, where interpolation should be done.
9798 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
9799 : * @param pdfRealValue pointer to real part of interpolated value
9800 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
9801 : *
9802 : * @return CE_None on success, or an error code on failure.
9803 : * @since GDAL 3.10
9804 : */
9805 :
9806 124 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
9807 : GDALRIOResampleAlg eInterpolation,
9808 : double *pdfRealValue,
9809 : double *pdfImagValue) const
9810 : {
9811 124 : if (eInterpolation != GRIORA_NearestNeighbour &&
9812 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
9813 : eInterpolation != GRIORA_CubicSpline)
9814 : {
9815 2 : CPLError(CE_Failure, CPLE_AppDefined,
9816 : "Only nearest, bilinear, cubic and cubicspline interpolation "
9817 : "methods "
9818 : "allowed");
9819 :
9820 2 : return CE_Failure;
9821 : }
9822 :
9823 122 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
9824 122 : if (!m_poPointsCache)
9825 52 : m_poPointsCache = new GDALDoublePointsCache();
9826 :
9827 : const bool res =
9828 122 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
9829 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
9830 :
9831 122 : return res ? CE_None : CE_Failure;
9832 : }
9833 :
9834 : /************************************************************************/
9835 : /* GDALRasterInterpolateAtPoint() */
9836 : /************************************************************************/
9837 :
9838 : /**
9839 : * \brief Interpolates the value between pixels using
9840 : * a resampling algorithm
9841 : *
9842 : * @see GDALRasterBand::InterpolateAtPoint()
9843 : * @since GDAL 3.10
9844 : */
9845 :
9846 106 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
9847 : double dfLine,
9848 : GDALRIOResampleAlg eInterpolation,
9849 : double *pdfRealValue, double *pdfImagValue)
9850 : {
9851 106 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
9852 :
9853 106 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9854 106 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
9855 106 : pdfRealValue, pdfImagValue);
9856 : }
9857 :
9858 : /************************************************************************/
9859 : /* InterpolateAtGeolocation() */
9860 : /************************************************************************/
9861 :
9862 : /**
9863 : * \brief Interpolates the value between pixels using a resampling algorithm,
9864 : * taking georeferenced coordinates as input.
9865 : *
9866 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
9867 : * must be in the "natural" SRS of the dataset, that is the one returned by
9868 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
9869 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
9870 : * array (generally WGS 84) if there is a geolocation array.
9871 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
9872 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
9873 : * be a easting, and dfGeolocY a northing.
9874 : *
9875 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
9876 : * expressed in that CRS, and that tuple must be conformant with the
9877 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
9878 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
9879 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
9880 : * before calling this method, and in that case, dfGeolocX must be a longitude
9881 : * or an easting value, and dfGeolocX a latitude or a northing value.
9882 : *
9883 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
9884 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
9885 : * it for details on how that transformation is done.
9886 : *
9887 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
9888 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
9889 : * where interpolation should be done.
9890 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
9891 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
9892 : * where interpolation should be done.
9893 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
9894 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
9895 : * @param pdfRealValue pointer to real part of interpolated value
9896 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
9897 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
9898 : *
9899 : * @return CE_None on success, or an error code on failure.
9900 : * @since GDAL 3.11
9901 : */
9902 :
9903 10 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
9904 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
9905 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
9906 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
9907 : {
9908 : double dfPixel;
9909 : double dfLine;
9910 10 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
9911 : &dfLine,
9912 10 : papszTransformerOptions) != CE_None)
9913 : {
9914 1 : return CE_Failure;
9915 : }
9916 9 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
9917 9 : pdfImagValue);
9918 : }
9919 :
9920 : /************************************************************************/
9921 : /* GDALRasterInterpolateAtGeolocation() */
9922 : /************************************************************************/
9923 :
9924 : /**
9925 : * \brief Interpolates the value between pixels using a resampling algorithm,
9926 : * taking georeferenced coordinates as input.
9927 : *
9928 : * @see GDALRasterBand::InterpolateAtGeolocation()
9929 : * @since GDAL 3.11
9930 : */
9931 :
9932 10 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
9933 : double dfGeolocX, double dfGeolocY,
9934 : OGRSpatialReferenceH hSRS,
9935 : GDALRIOResampleAlg eInterpolation,
9936 : double *pdfRealValue,
9937 : double *pdfImagValue,
9938 : CSLConstList papszTransformerOptions)
9939 : {
9940 10 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
9941 :
9942 10 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9943 10 : return poBand->InterpolateAtGeolocation(
9944 10 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
9945 10 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
9946 : }
|