Coverage Report

Created: 2025-06-22 06:59

/src/gdal/gcore/gdalrasterband.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Base class for format specific band class implementation.  This
5
 *           base class provides default implementation for many methods.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 1998, Frank Warmerdam
10
 * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14
15
#include "cpl_port.h"
16
#include "cpl_float.h"
17
#include "gdal_priv.h"
18
19
#include <climits>
20
#include <cmath>
21
#include <cstdarg>
22
#include <cstddef>
23
#include <cstdio>
24
#include <cstdlib>
25
#include <cstring>
26
#include <algorithm>
27
#include <limits>
28
#include <memory>
29
#include <new>
30
#include <type_traits>
31
32
#include "cpl_conv.h"
33
#include "cpl_error.h"
34
#include "cpl_float.h"
35
#include "cpl_progress.h"
36
#include "cpl_string.h"
37
#include "cpl_virtualmem.h"
38
#include "cpl_vsi.h"
39
#include "gdal.h"
40
#include "gdal_rat.h"
41
#include "gdal_priv_templates.hpp"
42
#include "gdal_interpolateatpoint.h"
43
#include "gdal_minmax_element.hpp"
44
45
/************************************************************************/
46
/*                           GDALRasterBand()                           */
47
/************************************************************************/
48
49
/*! Constructor. Applications should never create GDALRasterBands directly. */
50
51
GDALRasterBand::GDALRasterBand()
52
0
    : GDALRasterBand(
53
0
          CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
54
0
{
55
0
}
56
57
/** Constructor. Applications should never create GDALRasterBands directly.
58
 * @param bForceCachedIOIn Whether cached IO should be forced.
59
 */
60
GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
61
0
    : bForceCachedIO(bForceCachedIOIn)
62
63
0
{
64
0
}
65
66
/************************************************************************/
67
/*                          ~GDALRasterBand()                           */
68
/************************************************************************/
69
70
/*! Destructor. Applications should never destroy GDALRasterBands directly,
71
    instead destroy the GDALDataset. */
72
73
GDALRasterBand::~GDALRasterBand()
74
75
0
{
76
0
    if (poDS && poDS->IsMarkedSuppressOnClose())
77
0
    {
78
0
        if (poBandBlockCache)
79
0
            poBandBlockCache->DisableDirtyBlockWriting();
80
0
    }
81
0
    GDALRasterBand::FlushCache(true);
82
83
0
    delete poBandBlockCache;
84
85
0
    if (static_cast<GIntBig>(nBlockReads) >
86
0
            static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
87
0
        nBand == 1 && poDS != nullptr)
88
0
    {
89
0
        CPLDebug(
90
0
            "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
91
0
            nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
92
0
            poDS->GetDescription());
93
0
    }
94
95
0
    InvalidateMaskBand();
96
0
    nBand = -nBand;
97
98
0
    delete m_poPointsCache;
99
0
}
100
101
/************************************************************************/
102
/*                              RasterIO()                              */
103
/************************************************************************/
104
105
/**
106
 * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
107
 *                                int nXOff, int nYOff, int nXSize, int nYSize,
108
 *                                void * pData, int nBufXSize, int nBufYSize,
109
 *                                GDALDataType eBufType,
110
 *                                GSpacing nPixelSpace,
111
 *                                GSpacing nLineSpace,
112
 *                                GDALRasterIOExtraArg* psExtraArg )
113
 * \brief Read/write a region of image data for this band.
114
 *
115
 * This method allows reading a region of a GDALRasterBand into a buffer,
116
 * or writing data from a buffer into a region of a GDALRasterBand. It
117
 * automatically takes care of data type translation if the data type
118
 * (eBufType) of the buffer is different than that of the GDALRasterBand.
119
 * The method also takes care of image decimation / replication if the
120
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
121
 * region being accessed (nXSize x nYSize).
122
 *
123
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
124
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
125
 * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
126
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
127
 * Or use nLineSpace and a possibly shifted pData value.
128
 *
129
 * The nPixelSpace and nLineSpace parameters allow reading into or
130
 * writing from unusually organized buffers. This is primarily used
131
 * for buffers containing more than one bands raster data in interleaved
132
 * format.
133
 *
134
 * Some formats may efficiently implement decimation into a buffer by
135
 * reading from lower resolution overview images. The logic of the default
136
 * implementation in the base class GDALRasterBand is the following one. It
137
 * computes a target_downscaling_factor from the window of interest and buffer
138
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
139
 * It then walks through overviews and will select the first one whose
140
 * downscaling factor is greater than target_downscaling_factor / 1.2.
141
 *
142
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
143
 * The relationship between target_downscaling_factor and the select overview
144
 * level is the following one:
145
 *
146
 * target_downscaling_factor  | selected_overview
147
 * -------------------------  | -----------------
148
 * ]0,       2 / 1.2]         | full resolution band
149
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
150
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
151
 * ]8 / 1.2, infinity[        | 8x downsampled band
152
 *
153
 * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
154
 * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
155
 * option. Also note that starting with GDAL 3.9, when the resampling algorithm
156
 * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
157
 * this oversampling threshold defaults to 1. Consequently if there are overviews
158
 * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
159
 * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
160
 *
161
 * For highest performance full resolution data access, read and write
162
 * on "block boundaries" as returned by GetBlockSize(), or use the
163
 * ReadBlock() and WriteBlock() methods.
164
 *
165
 * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
166
 * functions.
167
 *
168
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
169
 * write a region of data.
170
 *
171
 * @param nXOff The pixel offset to the top left corner of the region
172
 * of the band to be accessed. This would be zero to start from the left side.
173
 *
174
 * @param nYOff The line offset to the top left corner of the region
175
 * of the band to be accessed. This would be zero to start from the top.
176
 *
177
 * @param nXSize The width of the region of the band to be accessed in pixels.
178
 *
179
 * @param nYSize The height of the region of the band to be accessed in lines.
180
 *
181
 * @param pData The buffer into which the data should be read, or from which
182
 * it should be written. This buffer must contain at least nBufXSize *
183
 * nBufYSize words of type eBufType. It is organized in left to right,
184
 * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
185
 * and nLineSpace parameters.
186
 * Note that even with eRWFlag==GF_Write, the content of the buffer might be
187
 * temporarily modified during the execution of this method (and eventually
188
 * restored back to its original content), so it is not safe to use a buffer
189
 * stored in a read-only section of the calling program.
190
 *
191
 * @param nBufXSize the width of the buffer image into which the desired region
192
 * is to be read, or from which it is to be written.
193
 *
194
 * @param nBufYSize the height of the buffer image into which the desired region
195
 * is to be read, or from which it is to be written.
196
 *
197
 * @param eBufType the type of the pixel values in the pData data buffer. The
198
 * pixel values will automatically be translated to/from the GDALRasterBand
199
 * data type as needed. Most driver implementations will use GDALCopyWords64()
200
 * to perform data type translation.
201
 *
202
 * @param nPixelSpace The byte offset from the start of one pixel value in
203
 * pData to the start of the next pixel value within a scanline. If defaulted
204
 * (0) the size of the datatype eBufType is used.
205
 *
206
 * @param nLineSpace The byte offset from the start of one scanline in
207
 * pData to the start of the next. If defaulted (0) the size of the datatype
208
 * eBufType * nBufXSize is used.
209
 *
210
 * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
211
 * structure with additional arguments to specify resampling and progress
212
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
213
 * configuration option can also be defined to override the default resampling
214
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
215
 *
216
 * @return CE_Failure if the access fails, otherwise CE_None.
217
 */
218
219
/**
220
 * \brief Read/write a region of image data for this band.
221
 *
222
 * This method allows reading a region of a GDALRasterBand into a buffer,
223
 * or writing data from a buffer into a region of a GDALRasterBand. It
224
 * automatically takes care of data type translation if the data type
225
 * (eBufType) of the buffer is different than that of the GDALRasterBand.
226
 * The method also takes care of image decimation / replication if the
227
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
228
 * region being accessed (nXSize x nYSize).
229
 *
230
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
231
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
232
 * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
233
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
234
 * Or use nLineSpace and a possibly shifted pData value.
235
 *
236
 * The nPixelSpace and nLineSpace parameters allow reading into or
237
 * writing from unusually organized buffers. This is primarily used
238
 * for buffers containing more than one bands raster data in interleaved
239
 * format.
240
 *
241
 * Some formats may efficiently implement decimation into a buffer by
242
 * reading from lower resolution overview images. The logic of the default
243
 * implementation in the base class GDALRasterBand is the following one. It
244
 * computes a target_downscaling_factor from the window of interest and buffer
245
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
246
 * It then walks through overviews and will select the first one whose
247
 * downscaling factor is greater than target_downscaling_factor / 1.2.
248
 *
249
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
250
 * The relationship between target_downscaling_factor and the select overview
251
 * level is the following one:
252
 *
253
 * target_downscaling_factor  | selected_overview
254
 * -------------------------  | -----------------
255
 * ]0,       2 / 1.2]         | full resolution band
256
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
257
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
258
 * ]8 / 1.2, infinity[        | 8x downsampled band
259
 *
260
 * For highest performance full resolution data access, read and write
261
 * on "block boundaries" as returned by GetBlockSize(), or use the
262
 * ReadBlock() and WriteBlock() methods.
263
 *
264
 * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
265
 * functions.
266
 *
267
 * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
268
 * more convenient to use for most common use cases.
269
 *
270
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
271
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
272
 * instance of this dataset) concurrently from several threads.
273
 *
274
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
275
 * write a region of data.
276
 *
277
 * @param nXOff The pixel offset to the top left corner of the region
278
 * of the band to be accessed. This would be zero to start from the left side.
279
 *
280
 * @param nYOff The line offset to the top left corner of the region
281
 * of the band to be accessed. This would be zero to start from the top.
282
 *
283
 * @param nXSize The width of the region of the band to be accessed in pixels.
284
 *
285
 * @param nYSize The height of the region of the band to be accessed in lines.
286
 *
287
 * @param[in,out] pData The buffer into which the data should be read, or from
288
 * which it should be written. This buffer must contain at least nBufXSize *
289
 * nBufYSize words of type eBufType. It is organized in left to right,
290
 * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
291
 * and nLineSpace parameters.
292
 *
293
 * @param nBufXSize the width of the buffer image into which the desired region
294
 * is to be read, or from which it is to be written.
295
 *
296
 * @param nBufYSize the height of the buffer image into which the desired region
297
 * is to be read, or from which it is to be written.
298
 *
299
 * @param eBufType the type of the pixel values in the pData data buffer. The
300
 * pixel values will automatically be translated to/from the GDALRasterBand
301
 * data type as needed.
302
 *
303
 * @param nPixelSpace The byte offset from the start of one pixel value in
304
 * pData to the start of the next pixel value within a scanline. If defaulted
305
 * (0) the size of the datatype eBufType is used.
306
 *
307
 * @param nLineSpace The byte offset from the start of one scanline in
308
 * pData to the start of the next. If defaulted (0) the size of the datatype
309
 * eBufType * nBufXSize is used.
310
 *
311
 * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
312
 * structure with additional arguments to specify resampling and progress
313
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
314
 * configuration option can also be defined to override the default resampling
315
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
316
 *
317
 * @return CE_Failure if the access fails, otherwise CE_None.
318
 *
319
 * @see GDALRasterBand::ReadRaster()
320
 */
321
322
CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
323
                                int nXSize, int nYSize, void *pData,
324
                                int nBufXSize, int nBufYSize,
325
                                GDALDataType eBufType, GSpacing nPixelSpace,
326
                                GSpacing nLineSpace,
327
                                GDALRasterIOExtraArg *psExtraArg)
328
329
0
{
330
0
    GDALRasterIOExtraArg sExtraArg;
331
0
    if (psExtraArg == nullptr)
332
0
    {
333
0
        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
334
0
        psExtraArg = &sExtraArg;
335
0
    }
336
0
    else if (CPL_UNLIKELY(psExtraArg->nVersion >
337
0
                          RASTERIO_EXTRA_ARG_CURRENT_VERSION))
338
0
    {
339
0
        ReportError(CE_Failure, CPLE_AppDefined,
340
0
                    "Unhandled version of GDALRasterIOExtraArg");
341
0
        return CE_Failure;
342
0
    }
343
344
0
    GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
345
0
                                       nBufYSize);
346
347
0
    if (CPL_UNLIKELY(nullptr == pData))
348
0
    {
349
0
        ReportError(CE_Failure, CPLE_AppDefined,
350
0
                    "The buffer into which the data should be read is null");
351
0
        return CE_Failure;
352
0
    }
353
354
    /* -------------------------------------------------------------------- */
355
    /*      Some size values are "noop".  Lets just return to avoid         */
356
    /*      stressing lower level functions.                                */
357
    /* -------------------------------------------------------------------- */
358
0
    if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
359
0
                     nBufYSize < 1))
360
0
    {
361
0
        CPLDebug("GDAL",
362
0
                 "RasterIO() skipped for odd window or buffer size.\n"
363
0
                 "  Window = (%d,%d)x%dx%d\n"
364
0
                 "  Buffer = %dx%d\n",
365
0
                 nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
366
367
0
        return CE_None;
368
0
    }
369
370
0
    if (eRWFlag == GF_Write)
371
0
    {
372
0
        if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
373
0
        {
374
0
            ReportError(eFlushBlockErr, CPLE_AppDefined,
375
0
                        "An error occurred while writing a dirty block "
376
0
                        "from GDALRasterBand::RasterIO");
377
0
            CPLErr eErr = eFlushBlockErr;
378
0
            eFlushBlockErr = CE_None;
379
0
            return eErr;
380
0
        }
381
0
        if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
382
0
        {
383
0
            return CE_Failure;
384
0
        }
385
0
    }
386
387
    /* -------------------------------------------------------------------- */
388
    /*      If pixel and line spacing are defaulted assign reasonable      */
389
    /*      value assuming a packed buffer.                                 */
390
    /* -------------------------------------------------------------------- */
391
0
    if (nPixelSpace == 0)
392
0
    {
393
0
        nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
394
0
    }
395
396
0
    if (nLineSpace == 0)
397
0
    {
398
0
        nLineSpace = nPixelSpace * nBufXSize;
399
0
    }
400
401
    /* -------------------------------------------------------------------- */
402
    /*      Do some validation of parameters.                               */
403
    /* -------------------------------------------------------------------- */
404
0
    if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
405
0
                     nXOff + nXSize > nRasterXSize || nYOff < 0 ||
406
0
                     nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
407
0
    {
408
0
        ReportError(CE_Failure, CPLE_IllegalArg,
409
0
                    "Access window out of range in RasterIO().  Requested\n"
410
0
                    "(%d,%d) of size %dx%d on raster of %dx%d.",
411
0
                    nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
412
0
        return CE_Failure;
413
0
    }
414
415
0
    if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
416
0
    {
417
0
        ReportError(
418
0
            CE_Failure, CPLE_IllegalArg,
419
0
            "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
420
0
            eRWFlag);
421
0
        return CE_Failure;
422
0
    }
423
0
    if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
424
0
    {
425
0
        ReportError(CE_Failure, CPLE_IllegalArg,
426
0
                    "Illegal GDT_Unknown/GDT_TypeCount argument");
427
0
        return CE_Failure;
428
0
    }
429
430
0
    return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
431
0
                            nBufXSize, nBufYSize, eBufType, nPixelSpace,
432
0
                            nLineSpace, psExtraArg);
433
0
}
434
435
/************************************************************************/
436
/*                         RasterIOInternal()                           */
437
/************************************************************************/
438
439
CPLErr GDALRasterBand::RasterIOInternal(
440
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
441
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
442
    GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
443
0
{
444
    /* -------------------------------------------------------------------- */
445
    /*      Call the format specific function.                              */
446
    /* -------------------------------------------------------------------- */
447
448
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
449
450
0
    CPLErr eErr;
451
0
    if (bForceCachedIO)
452
0
        eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
453
0
                                         pData, nBufXSize, nBufYSize, eBufType,
454
0
                                         nPixelSpace, nLineSpace, psExtraArg);
455
0
    else
456
0
        eErr =
457
0
            IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
458
0
                      nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
459
460
0
    if (bCallLeaveReadWrite)
461
0
        LeaveReadWrite();
462
463
0
    return eErr;
464
0
}
465
466
/************************************************************************/
467
/*                            GDALRasterIO()                            */
468
/************************************************************************/
469
470
/**
471
 * \brief Read/write a region of image data for this band.
472
 *
473
 * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
474
 * resolution, progress callback, etc. are needed)
475
 *
476
 * @see GDALRasterBand::RasterIO()
477
 */
478
479
CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
480
                                int nXOff, int nYOff, int nXSize, int nYSize,
481
                                void *pData, int nBufXSize, int nBufYSize,
482
                                GDALDataType eBufType, int nPixelSpace,
483
                                int nLineSpace)
484
485
0
{
486
0
    VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
487
488
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
489
490
0
    return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
491
0
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
492
0
                             nLineSpace, nullptr));
493
0
}
494
495
/************************************************************************/
496
/*                            GDALRasterIOEx()                          */
497
/************************************************************************/
498
499
/**
500
 * \brief Read/write a region of image data for this band.
501
 *
502
 * @see GDALRasterBand::RasterIO()
503
 * @since GDAL 2.0
504
 */
505
506
CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
507
                                  int nXOff, int nYOff, int nXSize, int nYSize,
508
                                  void *pData, int nBufXSize, int nBufYSize,
509
                                  GDALDataType eBufType, GSpacing nPixelSpace,
510
                                  GSpacing nLineSpace,
511
                                  GDALRasterIOExtraArg *psExtraArg)
512
513
0
{
514
0
    VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
515
516
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
517
518
0
    return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
519
0
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
520
0
                             nLineSpace, psExtraArg));
521
0
}
522
523
/************************************************************************/
524
/*                           GetGDTFromCppType()                        */
525
/************************************************************************/
526
527
namespace
528
{
529
template <class T> struct GetGDTFromCppType;
530
531
#define DEFINE_GetGDTFromCppType(T, eDT)                                       \
532
    template <> struct GetGDTFromCppType<T>                                    \
533
    {                                                                          \
534
        static constexpr GDALDataType GDT = eDT;                               \
535
    }
536
537
DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
538
DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
539
DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
540
DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
541
DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
542
DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
543
DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
544
DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
545
DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
546
DEFINE_GetGDTFromCppType(float, GDT_Float32);
547
DEFINE_GetGDTFromCppType(double, GDT_Float64);
548
// Not allowed by C++ standard
549
//DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
550
//DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
551
DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
552
DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
553
}  // namespace
554
555
/************************************************************************/
556
/*                           ReadRaster()                               */
557
/************************************************************************/
558
559
// clang-format off
560
/** Read a region of image data for this band.
561
 *
562
 * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
563
 * for common use cases, like reading a whole band.
564
 * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
565
 * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
566
 * float, double, std::complex<float|double>.
567
 *
568
 * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
569
 * and can allocate memory automatically.
570
 *
571
 * To read a whole band (assuming it fits into memory), as an array of double:
572
 *
573
\code{.cpp}
574
 double* myArray = static_cast<double*>(
575
     VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
576
 // TODO: check here that myArray != nullptr
577
 const size_t nArrayEltCount =
578
     static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
579
 if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
580
 {
581
     // do something
582
 }
583
 VSIFree(myArray)
584
\endcode
585
 *
586
 * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
587
 *
588
\code{.cpp}
589
 double* myArray = static_cast<double*>(
590
     VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
591
 // TODO: check here that myArray != nullptr
592
 const size_t nArrayEltCount = 128 * 128;
593
 if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
594
 {
595
     // do something
596
 }
597
 VSIFree(myArray)
598
\endcode
599
 *
600
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
601
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
602
 * instance of this dataset) concurrently from several threads.
603
 *
604
 * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
605
 * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
606
 * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
607
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
608
 * Or use nLineSpace and a possibly shifted pData value.
609
 *
610
 * @param[out] pData The buffer into which the data should be written.
611
 * This buffer must contain at least nBufXSize *
612
 * nBufYSize words of type T. It is organized in left to right,
613
 * top to bottom pixel order, and fully packed.
614
 * The type of the buffer does not need to be the one of GetDataType(). The
615
 * method will perform data type translation (with potential rounding, clamping)
616
 * if needed.
617
 *
618
 * @param nArrayEltCount Number of values of pData. If non zero, the method will
619
 * check that it is at least greater or equal to nBufXSize * nBufYSize, and
620
 * return in error if it is not. If set to zero, then pData is trusted to be
621
 * large enough.
622
 *
623
 * @param dfXOff The pixel offset to the top left corner of the region
624
 * of the band to be accessed. This would be zero to start from the left side.
625
 * Defaults to 0.
626
 *
627
 * @param dfYOff The line offset to the top left corner of the region
628
 * of the band to be accessed. This would be zero to start from the top.
629
 * Defaults to 0.
630
 *
631
 * @param dfXSize The width of the region of the band to be accessed in pixels.
632
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
633
 * dfXSize is set to the band width.
634
 *
635
 * @param dfYSize The height of the region of the band to be accessed in lines.
636
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
637
 * dfYSize is set to the band height.
638
 *
639
 * @param nBufXSize the width of the buffer image into which the desired region
640
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
641
 * then nBufXSize is initialized with dfXSize.
642
 *
643
 * @param nBufYSize the height of the buffer image into which the desired region
644
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
645
 * then nBufYSize is initialized with dfYSize.
646
 *
647
 * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
648
 *
649
 * @param pfnProgress Progress function. May be nullptr.
650
 *
651
 * @param pProgressData User data of pfnProgress. May be nullptr.
652
 *
653
 * @return CE_Failure if the access fails, otherwise CE_None.
654
 *
655
 * @see GDALRasterBand::RasterIO()
656
 * @since GDAL 3.10
657
 */
658
// clang-format on
659
660
template <class T>
661
CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
662
                                  double dfXOff, double dfYOff, double dfXSize,
663
                                  double dfYSize, size_t nBufXSize,
664
                                  size_t nBufYSize,
665
                                  GDALRIOResampleAlg eResampleAlg,
666
                                  GDALProgressFunc pfnProgress,
667
                                  void *pProgressData) const
668
0
{
669
0
    if (((nBufXSize | nBufYSize) >> 31) != 0)
670
0
    {
671
0
        return CE_Failure;
672
0
    }
673
674
0
    if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
675
0
    {
676
0
        dfXSize = nRasterXSize;
677
0
        dfYSize = nRasterYSize;
678
0
    }
679
0
    else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
680
0
             !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
681
0
             !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
682
0
             dfYOff + dfYSize > INT_MAX)
683
0
    {
684
0
        return CE_Failure;
685
0
    }
686
687
0
    GDALRasterIOExtraArg sExtraArg;
688
0
    sExtraArg.nVersion = 1;
689
0
    sExtraArg.eResampleAlg = eResampleAlg;
690
0
    sExtraArg.pfnProgress = pfnProgress;
691
0
    sExtraArg.pProgressData = pProgressData;
692
0
    sExtraArg.bFloatingPointWindowValidity = true;
693
0
    sExtraArg.dfXOff = dfXOff;
694
0
    sExtraArg.dfYOff = dfYOff;
695
0
    sExtraArg.dfXSize = dfXSize;
696
0
    sExtraArg.dfYSize = dfYSize;
697
0
    const int nXOff = static_cast<int>(dfXOff);
698
0
    const int nYOff = static_cast<int>(dfYOff);
699
0
    const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
700
0
    const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
701
0
    if (nBufXSize == 0 && nBufYSize == 0)
702
0
    {
703
0
        if (static_cast<int>(dfXSize) == dfXSize &&
704
0
            static_cast<int>(dfYSize) == dfYSize)
705
0
        {
706
0
            nBufXSize = static_cast<int>(dfXSize);
707
0
            nBufYSize = static_cast<int>(dfYSize);
708
0
        }
709
0
        else
710
0
        {
711
0
            CPLError(CE_Failure, CPLE_AppDefined,
712
0
                     "nBufXSize and nBufYSize must be provided if dfXSize or "
713
0
                     "dfYSize is not an integer value");
714
0
            return CE_Failure;
715
0
        }
716
0
    }
717
0
    if (nBufXSize == 0 || nBufYSize == 0)
718
0
    {
719
0
        CPLDebug("GDAL",
720
0
                 "RasterIO() skipped for odd window or buffer size.\n"
721
0
                 "  Window = (%d,%d)x%dx%d\n"
722
0
                 "  Buffer = %dx%d\n",
723
0
                 nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
724
0
                 static_cast<int>(nBufYSize));
725
726
0
        return CE_None;
727
0
    }
728
729
0
    if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
730
0
    {
731
0
        CPLError(CE_Failure, CPLE_AppDefined,
732
0
                 "Provided array is not large enough");
733
0
        return CE_Failure;
734
0
    }
735
736
0
    constexpr GSpacing nPixelSpace = sizeof(T);
737
0
    const GSpacing nLineSpace = nPixelSpace * nBufXSize;
738
0
    constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
739
740
0
    GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
741
742
0
    return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
743
0
                                   static_cast<int>(nBufXSize),
744
0
                                   static_cast<int>(nBufYSize), eBufType,
745
0
                                   nPixelSpace, nLineSpace, &sExtraArg);
746
0
}
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned char>(unsigned char*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<signed char>(signed char*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned short>(unsigned short*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<short>(short*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned int>(unsigned int*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<int>(int*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned long>(unsigned long*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<long>(long*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<cpl::Float16>(cpl::Float16*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<float>(float*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<double>(double*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<std::__1::complex<float> >(std::__1::complex<float>*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<std::__1::complex<double> >(std::__1::complex<double>*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
747
748
//! @cond Doxygen_Suppress
749
750
#define INSTANTIATE_READ_RASTER(T)                                             \
751
    template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
752
        T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
753
        double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
754
        GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
755
        void *pProgressData) const;
756
757
INSTANTIATE_READ_RASTER(uint8_t)
758
INSTANTIATE_READ_RASTER(int8_t)
759
INSTANTIATE_READ_RASTER(uint16_t)
760
INSTANTIATE_READ_RASTER(int16_t)
761
INSTANTIATE_READ_RASTER(uint32_t)
762
INSTANTIATE_READ_RASTER(int32_t)
763
INSTANTIATE_READ_RASTER(uint64_t)
764
INSTANTIATE_READ_RASTER(int64_t)
765
INSTANTIATE_READ_RASTER(GFloat16)
766
INSTANTIATE_READ_RASTER(float)
767
INSTANTIATE_READ_RASTER(double)
768
// Not allowed by C++ standard
769
// INSTANTIATE_READ_RASTER(std::complex<int16_t>)
770
// INSTANTIATE_READ_RASTER(std::complex<int32_t>)
771
INSTANTIATE_READ_RASTER(std::complex<float>)
772
INSTANTIATE_READ_RASTER(std::complex<double>)
773
774
//! @endcond
775
776
/************************************************************************/
777
/*                           ReadRaster()                               */
778
/************************************************************************/
779
780
/** Read a region of image data for this band.
781
 *
782
 * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
783
 * for common use cases, like reading a whole band.
784
 * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
785
 * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
786
 * float, double, std::complex<float|double>.
787
 *
788
 * To read a whole band (assuming it fits into memory), as a vector of double:
789
 *
790
\code
791
 std::vector<double> myArray;
792
 if (poBand->ReadRaster(myArray) == CE_None)
793
 {
794
     // do something
795
 }
796
\endcode
797
 *
798
 * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
799
 *
800
\code{.cpp}
801
 std::vector<double> myArray;
802
 if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
803
 {
804
     // do something
805
 }
806
\endcode
807
 *
808
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
809
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
810
 * instance of this dataset) concurrently from several threads.
811
 *
812
 * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
813
 * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
814
 * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
815
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
816
 * Or use nLineSpace and a possibly shifted pData value.
817
 *
818
 * @param[out] vData The vector into which the data should be written.
819
 * The vector will be resized, if needed, to contain at least nBufXSize *
820
 * nBufYSize values. The values in the vector are organized in left to right,
821
 * top to bottom pixel order, and fully packed.
822
 * The type of the vector does not need to be the one of GetDataType(). The
823
 * method will perform data type translation (with potential rounding, clamping)
824
 * if needed.
825
 *
826
 * @param dfXOff The pixel offset to the top left corner of the region
827
 * of the band to be accessed. This would be zero to start from the left side.
828
 * Defaults to 0.
829
 *
830
 * @param dfYOff The line offset to the top left corner of the region
831
 * of the band to be accessed. This would be zero to start from the top.
832
 * Defaults to 0.
833
 *
834
 * @param dfXSize The width of the region of the band to be accessed in pixels.
835
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
836
 * dfXSize is set to the band width.
837
 *
838
 * @param dfYSize The height of the region of the band to be accessed in lines.
839
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
840
 * dfYSize is set to the band height.
841
 *
842
 * @param nBufXSize the width of the buffer image into which the desired region
843
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
844
 * then nBufXSize is initialized with dfXSize.
845
 *
846
 * @param nBufYSize the height of the buffer image into which the desired region
847
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
848
 * then nBufYSize is initialized with dfYSize.
849
 *
850
 * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
851
 *
852
 * @param pfnProgress Progress function. May be nullptr.
853
 *
854
 * @param pProgressData User data of pfnProgress. May be nullptr.
855
 *
856
 * @return CE_Failure if the access fails, otherwise CE_None.
857
 *
858
 * @see GDALRasterBand::RasterIO()
859
 * @since GDAL 3.10
860
 */
861
template <class T>
862
CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
863
                                  double dfYOff, double dfXSize, double dfYSize,
864
                                  size_t nBufXSize, size_t nBufYSize,
865
                                  GDALRIOResampleAlg eResampleAlg,
866
                                  GDALProgressFunc pfnProgress,
867
                                  void *pProgressData) const
868
0
{
869
0
    if (((nBufXSize | nBufYSize) >> 31) != 0)
870
0
    {
871
0
        return CE_Failure;
872
0
    }
873
874
0
    if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
875
0
    {
876
0
        dfXSize = nRasterXSize;
877
0
        dfYSize = nRasterYSize;
878
0
    }
879
0
    else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
880
0
             !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
881
0
             !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
882
0
             dfYOff + dfYSize > INT_MAX)
883
0
    {
884
0
        return CE_Failure;
885
0
    }
886
887
0
    GDALRasterIOExtraArg sExtraArg;
888
0
    sExtraArg.nVersion = 1;
889
0
    sExtraArg.eResampleAlg = eResampleAlg;
890
0
    sExtraArg.pfnProgress = pfnProgress;
891
0
    sExtraArg.pProgressData = pProgressData;
892
0
    sExtraArg.bFloatingPointWindowValidity = true;
893
0
    sExtraArg.dfXOff = dfXOff;
894
0
    sExtraArg.dfYOff = dfYOff;
895
0
    sExtraArg.dfXSize = dfXSize;
896
0
    sExtraArg.dfYSize = dfYSize;
897
0
    const int nXOff = static_cast<int>(dfXOff);
898
0
    const int nYOff = static_cast<int>(dfYOff);
899
0
    const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
900
0
    const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
901
0
    if (nBufXSize == 0 && nBufYSize == 0)
902
0
    {
903
0
        if (static_cast<int>(dfXSize) == dfXSize &&
904
0
            static_cast<int>(dfYSize) == dfYSize)
905
0
        {
906
0
            nBufXSize = static_cast<int>(dfXSize);
907
0
            nBufYSize = static_cast<int>(dfYSize);
908
0
        }
909
0
        else
910
0
        {
911
0
            CPLError(CE_Failure, CPLE_AppDefined,
912
0
                     "nBufXSize and nBufYSize must be provided if "
913
0
                     "dfXSize or dfYSize is not an integer value");
914
0
            return CE_Failure;
915
0
        }
916
0
    }
917
0
    if (nBufXSize == 0 || nBufYSize == 0)
918
0
    {
919
0
        CPLDebug("GDAL",
920
0
                 "RasterIO() skipped for odd window or buffer size.\n"
921
0
                 "  Window = (%d,%d)x%dx%d\n"
922
0
                 "  Buffer = %dx%d\n",
923
0
                 nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
924
0
                 static_cast<int>(nBufYSize));
925
926
0
        return CE_None;
927
0
    }
928
929
    if constexpr (SIZEOF_VOIDP < 8)
930
    {
931
        if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
932
        {
933
            CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
934
            return CE_Failure;
935
        }
936
    }
937
938
0
    if (vData.size() < nBufXSize * nBufYSize)
939
0
    {
940
0
        try
941
0
        {
942
0
            vData.resize(nBufXSize * nBufYSize);
943
0
        }
944
0
        catch (const std::exception &)
945
0
        {
946
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
947
0
            return CE_Failure;
948
0
        }
949
0
    }
950
951
0
    constexpr GSpacing nPixelSpace = sizeof(T);
952
0
    const GSpacing nLineSpace = nPixelSpace * nBufXSize;
953
0
    constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
954
955
0
    GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
956
957
0
    return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
958
0
                                   vData.data(), static_cast<int>(nBufXSize),
959
0
                                   static_cast<int>(nBufYSize), eBufType,
960
0
                                   nPixelSpace, nLineSpace, &sExtraArg);
961
0
}
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned char>(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<signed char>(std::__1::vector<signed char, std::__1::allocator<signed char> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned short>(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<short>(std::__1::vector<short, std::__1::allocator<short> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<int>(std::__1::vector<int, std::__1::allocator<int> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned long>(std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<long>(std::__1::vector<long, std::__1::allocator<long> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<cpl::Float16>(std::__1::vector<cpl::Float16, std::__1::allocator<cpl::Float16> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<float>(std::__1::vector<float, std::__1::allocator<float> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<double>(std::__1::vector<double, std::__1::allocator<double> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<std::__1::complex<float> >(std::__1::vector<std::__1::complex<float>, std::__1::allocator<std::__1::complex<float> > >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<std::__1::complex<double> >(std::__1::vector<std::__1::complex<double>, std::__1::allocator<std::__1::complex<double> > >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
962
963
//! @cond Doxygen_Suppress
964
965
#define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
966
    template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
967
        std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
968
        double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
969
        GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
970
        void *pProgressData) const;
971
972
INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
973
INSTANTIATE_READ_RASTER_VECTOR(int8_t)
974
INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
975
INSTANTIATE_READ_RASTER_VECTOR(int16_t)
976
INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
977
INSTANTIATE_READ_RASTER_VECTOR(int32_t)
978
INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
979
INSTANTIATE_READ_RASTER_VECTOR(int64_t)
980
INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
981
INSTANTIATE_READ_RASTER_VECTOR(float)
982
INSTANTIATE_READ_RASTER_VECTOR(double)
983
// Not allowed by C++ standard
984
// INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
985
// INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
986
INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
987
INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
988
989
//! @endcond
990
991
/************************************************************************/
992
/*                             ReadBlock()                              */
993
/************************************************************************/
994
995
/**
996
 * \brief Read a block of image data efficiently.
997
 *
998
 * This method accesses a "natural" block from the raster band without
999
 * resampling, or data type conversion.  For a more generalized, but
1000
 * potentially less efficient access use RasterIO().
1001
 *
1002
 * This method is the same as the C GDALReadBlock() function.
1003
 *
1004
 * See the GetLockedBlockRef() method for a way of accessing internally cached
1005
 * block oriented data without an extra copy into an application buffer.
1006
 *
1007
 * The following code would efficiently compute a histogram of eight bit
1008
 * raster data.  Note that the final block may be partial ... data beyond
1009
 * the edge of the underlying raster band in these edge blocks is of an
1010
 * undetermined value.
1011
 *
1012
\code{.cpp}
1013
 CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1014
1015
 {
1016
     memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1017
1018
     CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1019
1020
     int nXBlockSize, nYBlockSize;
1021
1022
     poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1023
     int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1024
     int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1025
1026
     GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1027
1028
     for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1029
     {
1030
         for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1031
         {
1032
             int        nXValid, nYValid;
1033
1034
             poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1035
1036
             // Compute the portion of the block that is valid
1037
             // for partial edge blocks.
1038
             poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1039
1040
             // Collect the histogram counts.
1041
             for( int iY = 0; iY < nYValid; iY++ )
1042
             {
1043
                 for( int iX = 0; iX < nXValid; iX++ )
1044
                 {
1045
                     panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1046
                 }
1047
             }
1048
         }
1049
     }
1050
 }
1051
\endcode
1052
 *
1053
 * @param nXBlockOff the horizontal block offset, with zero indicating
1054
 * the left most block, 1 the next block and so forth.
1055
 *
1056
 * @param nYBlockOff the vertical block offset, with zero indicating
1057
 * the top most block, 1 the next block and so forth.
1058
 *
1059
 * @param pImage the buffer into which the data will be read.  The buffer
1060
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1061
 * of type GetRasterDataType().
1062
 *
1063
 * @return CE_None on success or CE_Failure on an error.
1064
 */
1065
1066
CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1067
1068
0
{
1069
    /* -------------------------------------------------------------------- */
1070
    /*      Validate arguments.                                             */
1071
    /* -------------------------------------------------------------------- */
1072
0
    CPLAssert(pImage != nullptr);
1073
1074
0
    if (!InitBlockInfo())
1075
0
        return CE_Failure;
1076
1077
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1078
0
    {
1079
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1080
0
                    "Illegal nXBlockOff value (%d) in "
1081
0
                    "GDALRasterBand::ReadBlock()\n",
1082
0
                    nXBlockOff);
1083
1084
0
        return (CE_Failure);
1085
0
    }
1086
1087
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1088
0
    {
1089
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1090
0
                    "Illegal nYBlockOff value (%d) in "
1091
0
                    "GDALRasterBand::ReadBlock()\n",
1092
0
                    nYBlockOff);
1093
1094
0
        return (CE_Failure);
1095
0
    }
1096
1097
    /* -------------------------------------------------------------------- */
1098
    /*      Invoke underlying implementation method.                        */
1099
    /* -------------------------------------------------------------------- */
1100
1101
0
    int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1102
0
    CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1103
0
    if (bCallLeaveReadWrite)
1104
0
        LeaveReadWrite();
1105
0
    return eErr;
1106
0
}
1107
1108
/************************************************************************/
1109
/*                           GDALReadBlock()                            */
1110
/************************************************************************/
1111
1112
/**
1113
 * \brief Read a block of image data efficiently.
1114
 *
1115
 * @see GDALRasterBand::ReadBlock()
1116
 */
1117
1118
CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1119
                                 void *pData)
1120
1121
0
{
1122
0
    VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1123
1124
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1125
0
    return (poBand->ReadBlock(nXOff, nYOff, pData));
1126
0
}
1127
1128
/************************************************************************/
1129
/*                            IReadBlock()                             */
1130
/************************************************************************/
1131
1132
/** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1133
 * ) \brief Read a block of data.
1134
 *
1135
 * Default internal implementation ... to be overridden by
1136
 * subclasses that support reading.
1137
 * @param nBlockXOff Block X Offset
1138
 * @param nBlockYOff Block Y Offset
1139
 * @param pData Pixel buffer into which to place read data.
1140
 * @return CE_None on success or CE_Failure on an error.
1141
 */
1142
1143
/************************************************************************/
1144
/*                            IWriteBlock()                             */
1145
/************************************************************************/
1146
1147
/**
1148
 * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1149
 * Write a block of data.
1150
 *
1151
 * Default internal implementation ... to be overridden by
1152
 * subclasses that support writing.
1153
 * @param nBlockXOff Block X Offset
1154
 * @param nBlockYOff Block Y Offset
1155
 * @param pData Pixel buffer to write
1156
 * @return CE_None on success or CE_Failure on an error.
1157
 */
1158
1159
/**/
1160
/**/
1161
1162
CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1163
                                   void * /*pData*/)
1164
1165
0
{
1166
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1167
0
        ReportError(CE_Failure, CPLE_NotSupported,
1168
0
                    "WriteBlock() not supported for this dataset.");
1169
1170
0
    return (CE_Failure);
1171
0
}
1172
1173
/************************************************************************/
1174
/*                             WriteBlock()                             */
1175
/************************************************************************/
1176
1177
/**
1178
 * \brief Write a block of image data efficiently.
1179
 *
1180
 * This method accesses a "natural" block from the raster band without
1181
 * resampling, or data type conversion.  For a more generalized, but
1182
 * potentially less efficient access use RasterIO().
1183
 *
1184
 * This method is the same as the C GDALWriteBlock() function.
1185
 *
1186
 * See ReadBlock() for an example of block oriented data access.
1187
 *
1188
 * @param nXBlockOff the horizontal block offset, with zero indicating
1189
 * the left most block, 1 the next block and so forth.
1190
 *
1191
 * @param nYBlockOff the vertical block offset, with zero indicating
1192
 * the left most block, 1 the next block and so forth.
1193
 *
1194
 * @param pImage the buffer from which the data will be written.  The buffer
1195
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1196
 * of type GetRasterDataType(). Note that the content of the buffer might be
1197
 * temporarily modified during the execution of this method (and eventually
1198
 * restored back to its original content), so it is not safe to use a buffer
1199
 * stored in a read-only section of the calling program.
1200
 *
1201
 * @return CE_None on success or CE_Failure on an error.
1202
 */
1203
1204
CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1205
1206
0
{
1207
    /* -------------------------------------------------------------------- */
1208
    /*      Validate arguments.                                             */
1209
    /* -------------------------------------------------------------------- */
1210
0
    CPLAssert(pImage != nullptr);
1211
1212
0
    if (!InitBlockInfo())
1213
0
        return CE_Failure;
1214
1215
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1216
0
    {
1217
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1218
0
                    "Illegal nXBlockOff value (%d) in "
1219
0
                    "GDALRasterBand::WriteBlock()\n",
1220
0
                    nXBlockOff);
1221
1222
0
        return (CE_Failure);
1223
0
    }
1224
1225
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1226
0
    {
1227
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1228
0
                    "Illegal nYBlockOff value (%d) in "
1229
0
                    "GDALRasterBand::WriteBlock()\n",
1230
0
                    nYBlockOff);
1231
1232
0
        return (CE_Failure);
1233
0
    }
1234
1235
0
    if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1236
0
    {
1237
0
        return CE_Failure;
1238
0
    }
1239
1240
0
    if (eFlushBlockErr != CE_None)
1241
0
    {
1242
0
        ReportError(eFlushBlockErr, CPLE_AppDefined,
1243
0
                    "An error occurred while writing a dirty block "
1244
0
                    "from GDALRasterBand::WriteBlock");
1245
0
        CPLErr eErr = eFlushBlockErr;
1246
0
        eFlushBlockErr = CE_None;
1247
0
        return eErr;
1248
0
    }
1249
1250
    /* -------------------------------------------------------------------- */
1251
    /*      Invoke underlying implementation method.                        */
1252
    /* -------------------------------------------------------------------- */
1253
1254
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1255
0
    CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1256
0
    if (bCallLeaveReadWrite)
1257
0
        LeaveReadWrite();
1258
1259
0
    return eErr;
1260
0
}
1261
1262
/************************************************************************/
1263
/*                           GDALWriteBlock()                           */
1264
/************************************************************************/
1265
1266
/**
1267
 * \brief Write a block of image data efficiently.
1268
 *
1269
 * @see GDALRasterBand::WriteBlock()
1270
 */
1271
1272
CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1273
                                  void *pData)
1274
1275
0
{
1276
0
    VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1277
1278
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1279
0
    return (poBand->WriteBlock(nXOff, nYOff, pData));
1280
0
}
1281
1282
/************************************************************************/
1283
/*                   EmitErrorMessageIfWriteNotSupported()              */
1284
/************************************************************************/
1285
1286
/**
1287
 * Emit an error message if a write operation to this band is not supported.
1288
 *
1289
 * The base implementation will emit an error message if the access mode is
1290
 * read-only. Derived classes may implement it to provide a custom message.
1291
 *
1292
 * @param pszCaller Calling function.
1293
 * @return true if an error message has been emitted.
1294
 */
1295
bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1296
    const char *pszCaller) const
1297
0
{
1298
0
    if (eAccess == GA_ReadOnly)
1299
0
    {
1300
0
        ReportError(CE_Failure, CPLE_NoWriteAccess,
1301
0
                    "%s: attempt to write to dataset opened in read-only mode.",
1302
0
                    pszCaller);
1303
1304
0
        return true;
1305
0
    }
1306
0
    return false;
1307
0
}
1308
1309
/************************************************************************/
1310
/*                         GetActualBlockSize()                         */
1311
/************************************************************************/
1312
/**
1313
 * \brief Fetch the actual block size for a given block offset.
1314
 *
1315
 * Handles partial blocks at the edges of the raster and returns the true
1316
 * number of pixels
1317
 *
1318
 * @param nXBlockOff the horizontal block offset for which to calculate the
1319
 * number of valid pixels, with zero indicating the left most block, 1 the next
1320
 * block and so forth.
1321
 *
1322
 * @param nYBlockOff the vertical block offset, with zero indicating
1323
 * the top most block, 1 the next block and so forth.
1324
 *
1325
 * @param pnXValid pointer to an integer in which the number of valid pixels in
1326
 * the x direction will be stored
1327
 *
1328
 * @param pnYValid pointer to an integer in which the number of valid pixels in
1329
 * the y direction will be stored
1330
 *
1331
 * @return CE_None if the input parameters are valid, CE_Failure otherwise
1332
 *
1333
 * @since GDAL 2.2
1334
 */
1335
CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1336
                                          int *pnXValid, int *pnYValid) const
1337
0
{
1338
0
    if (nXBlockOff < 0 || nBlockXSize == 0 ||
1339
0
        nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1340
0
        nYBlockOff < 0 || nBlockYSize == 0 ||
1341
0
        nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1342
0
    {
1343
0
        return CE_Failure;
1344
0
    }
1345
1346
0
    const int nXPixelOff = nXBlockOff * nBlockXSize;
1347
0
    const int nYPixelOff = nYBlockOff * nBlockYSize;
1348
1349
0
    *pnXValid = nBlockXSize;
1350
0
    *pnYValid = nBlockYSize;
1351
1352
0
    if (nXPixelOff >= nRasterXSize - nBlockXSize)
1353
0
    {
1354
0
        *pnXValid = nRasterXSize - nXPixelOff;
1355
0
    }
1356
1357
0
    if (nYPixelOff >= nRasterYSize - nBlockYSize)
1358
0
    {
1359
0
        *pnYValid = nRasterYSize - nYPixelOff;
1360
0
    }
1361
1362
0
    return CE_None;
1363
0
}
1364
1365
/************************************************************************/
1366
/*                           GDALGetActualBlockSize()                   */
1367
/************************************************************************/
1368
1369
/**
1370
 * \brief Retrieve the actual block size for a given block offset.
1371
 *
1372
 * @see GDALRasterBand::GetActualBlockSize()
1373
 */
1374
1375
CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1376
                                          int nYBlockOff, int *pnXValid,
1377
                                          int *pnYValid)
1378
1379
0
{
1380
0
    VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1381
1382
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1383
0
    return (
1384
0
        poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1385
0
}
1386
1387
/************************************************************************/
1388
/*                     GetSuggestedBlockAccessPattern()                 */
1389
/************************************************************************/
1390
1391
/**
1392
 * \brief Return the suggested/most efficient access pattern to blocks
1393
 *        (for read operations).
1394
 *
1395
 * While all GDAL drivers have to expose a block size, not all can guarantee
1396
 * efficient random access (GSBAP_RANDOM) to any block.
1397
 * Some drivers for example decompress sequentially a compressed stream from
1398
 * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1399
 * case best performance will be achieved while reading blocks in that order.
1400
 * (accessing blocks in random access in such rasters typically causes the
1401
 * decoding to be re-initialized from the start if accessing blocks in
1402
 * a non-sequential order)
1403
 *
1404
 * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1405
 * returned by drivers that expose a somewhat artificial block size, because
1406
 * they can extract any part of a raster, but in a rather inefficient way.
1407
 *
1408
 * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1409
 * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1410
 * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1411
 * most efficient strategy is to read as many pixels as possible in the less
1412
 * RasterIO() operations.
1413
 *
1414
 * The return of this method is for example used to determine the swath size
1415
 * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1416
 *
1417
 * @since GDAL 3.6
1418
 */
1419
1420
GDALSuggestedBlockAccessPattern
1421
GDALRasterBand::GetSuggestedBlockAccessPattern() const
1422
0
{
1423
0
    return GSBAP_UNKNOWN;
1424
0
}
1425
1426
/************************************************************************/
1427
/*                         GetRasterDataType()                          */
1428
/************************************************************************/
1429
1430
/**
1431
 * \brief Fetch the pixel data type for this band.
1432
 *
1433
 * This method is the same as the C function GDALGetRasterDataType().
1434
 *
1435
 * @return the data type of pixels for this band.
1436
 */
1437
1438
GDALDataType GDALRasterBand::GetRasterDataType() const
1439
1440
0
{
1441
0
    return eDataType;
1442
0
}
1443
1444
/************************************************************************/
1445
/*                       GDALGetRasterDataType()                        */
1446
/************************************************************************/
1447
1448
/**
1449
 * \brief Fetch the pixel data type for this band.
1450
 *
1451
 * @see GDALRasterBand::GetRasterDataType()
1452
 */
1453
1454
GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1455
1456
0
{
1457
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1458
1459
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1460
0
    return poBand->GetRasterDataType();
1461
0
}
1462
1463
/************************************************************************/
1464
/*                            GetBlockSize()                            */
1465
/************************************************************************/
1466
1467
/**
1468
 * \brief Fetch the "natural" block size of this band.
1469
 *
1470
 * GDAL contains a concept of the natural block size of rasters so that
1471
 * applications can organized data access efficiently for some file formats.
1472
 * The natural block size is the block size that is most efficient for
1473
 * accessing the format.  For many formats this is simple a whole scanline
1474
 * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1475
 *
1476
 * However, for tiled images this will typically be the tile size.
1477
 *
1478
 * Note that the X and Y block sizes don't have to divide the image size
1479
 * evenly, meaning that right and bottom edge blocks may be incomplete.
1480
 * See ReadBlock() for an example of code dealing with these issues.
1481
 *
1482
 * This method is the same as the C function GDALGetBlockSize().
1483
 *
1484
 * @param pnXSize integer to put the X block size into or NULL.
1485
 *
1486
 * @param pnYSize integer to put the Y block size into or NULL.
1487
 */
1488
1489
void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1490
1491
0
{
1492
0
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
1493
0
    {
1494
0
        ReportError(CE_Failure, CPLE_AppDefined,
1495
0
                    "Invalid block dimension : %d * %d", nBlockXSize,
1496
0
                    nBlockYSize);
1497
0
        if (pnXSize != nullptr)
1498
0
            *pnXSize = 0;
1499
0
        if (pnYSize != nullptr)
1500
0
            *pnYSize = 0;
1501
0
    }
1502
0
    else
1503
0
    {
1504
0
        if (pnXSize != nullptr)
1505
0
            *pnXSize = nBlockXSize;
1506
0
        if (pnYSize != nullptr)
1507
0
            *pnYSize = nBlockYSize;
1508
0
    }
1509
0
}
1510
1511
/************************************************************************/
1512
/*                          GDALGetBlockSize()                          */
1513
/************************************************************************/
1514
1515
/**
1516
 * \brief Fetch the "natural" block size of this band.
1517
 *
1518
 * @see GDALRasterBand::GetBlockSize()
1519
 */
1520
1521
void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1522
                                  int *pnYSize)
1523
1524
0
{
1525
0
    VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1526
1527
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1528
0
    poBand->GetBlockSize(pnXSize, pnYSize);
1529
0
}
1530
1531
/************************************************************************/
1532
/*                           InitBlockInfo()                            */
1533
/************************************************************************/
1534
1535
//! @cond Doxygen_Suppress
1536
int GDALRasterBand::InitBlockInfo()
1537
1538
0
{
1539
0
    if (poBandBlockCache != nullptr)
1540
0
        return poBandBlockCache->IsInitOK();
1541
1542
    /* Do some validation of raster and block dimensions in case the driver */
1543
    /* would have neglected to do it itself */
1544
0
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
1545
0
    {
1546
0
        ReportError(CE_Failure, CPLE_AppDefined,
1547
0
                    "Invalid block dimension : %d * %d", nBlockXSize,
1548
0
                    nBlockYSize);
1549
0
        return FALSE;
1550
0
    }
1551
1552
0
    if (nRasterXSize <= 0 || nRasterYSize <= 0)
1553
0
    {
1554
0
        ReportError(CE_Failure, CPLE_AppDefined,
1555
0
                    "Invalid raster dimension : %d * %d", nRasterXSize,
1556
0
                    nRasterYSize);
1557
0
        return FALSE;
1558
0
    }
1559
1560
0
    const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1561
0
    if (nDataTypeSize == 0)
1562
0
    {
1563
0
        ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1564
0
        return FALSE;
1565
0
    }
1566
1567
#if SIZEOF_VOIDP == 4
1568
    if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1569
    {
1570
        /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1571
         * multiplication in other cases */
1572
        if (nBlockXSize > INT_MAX / nDataTypeSize ||
1573
            nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1574
        {
1575
            ReportError(CE_Failure, CPLE_NotSupported,
1576
                        "Too big block : %d * %d for 32-bit build", nBlockXSize,
1577
                        nBlockYSize);
1578
            return FALSE;
1579
        }
1580
    }
1581
#endif
1582
1583
0
    nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1584
0
    nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1585
1586
0
    const char *pszBlockStrategy =
1587
0
        CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1588
0
    bool bUseArray = true;
1589
0
    if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1590
0
    {
1591
0
        if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1592
0
                                   GDAL_OF_DEFAULT_BLOCK_ACCESS)
1593
0
        {
1594
0
            GUIntBig nBlockCount =
1595
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1596
0
            if (poDS != nullptr)
1597
0
                nBlockCount *= poDS->GetRasterCount();
1598
0
            bUseArray = (nBlockCount < 1024 * 1024);
1599
0
        }
1600
0
        else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1601
0
                 GDAL_OF_HASHSET_BLOCK_ACCESS)
1602
0
        {
1603
0
            bUseArray = false;
1604
0
        }
1605
0
    }
1606
0
    else if (EQUAL(pszBlockStrategy, "HASHSET"))
1607
0
        bUseArray = false;
1608
0
    else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1609
0
        CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1610
0
                 pszBlockStrategy);
1611
1612
0
    if (bUseArray)
1613
0
        poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1614
0
    else
1615
0
    {
1616
0
        if (nBand == 1)
1617
0
            CPLDebug("GDAL", "Use hashset band block cache");
1618
0
        poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1619
0
    }
1620
0
    if (poBandBlockCache == nullptr)
1621
0
        return FALSE;
1622
0
    return poBandBlockCache->Init();
1623
0
}
1624
1625
//! @endcond
1626
1627
/************************************************************************/
1628
/*                             FlushCache()                             */
1629
/************************************************************************/
1630
1631
/**
1632
 * \brief Flush raster data cache.
1633
 *
1634
 * This call will recover memory used to cache data blocks for this raster
1635
 * band, and ensure that new requests are referred to the underlying driver.
1636
 *
1637
 * This method is the same as the C function GDALFlushRasterCache().
1638
 *
1639
 * @param bAtClosing Whether this is called from a GDALDataset destructor
1640
 * @return CE_None on success.
1641
 */
1642
1643
CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1644
1645
0
{
1646
0
    if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1647
0
        poBandBlockCache)
1648
0
        poBandBlockCache->DisableDirtyBlockWriting();
1649
1650
0
    CPLErr eGlobalErr = eFlushBlockErr;
1651
1652
0
    if (eFlushBlockErr != CE_None)
1653
0
    {
1654
0
        ReportError(
1655
0
            eFlushBlockErr, CPLE_AppDefined,
1656
0
            "An error occurred while writing a dirty block from FlushCache");
1657
0
        eFlushBlockErr = CE_None;
1658
0
    }
1659
1660
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1661
0
        return eGlobalErr;
1662
1663
0
    return poBandBlockCache->FlushCache();
1664
0
}
1665
1666
/************************************************************************/
1667
/*                        GDALFlushRasterCache()                        */
1668
/************************************************************************/
1669
1670
/**
1671
 * \brief Flush raster data cache.
1672
 *
1673
 * @see GDALRasterBand::FlushCache()
1674
 */
1675
1676
CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1677
1678
0
{
1679
0
    VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1680
1681
0
    return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1682
0
}
1683
1684
/************************************************************************/
1685
/*                             DropCache()                              */
1686
/************************************************************************/
1687
1688
/**
1689
* \brief Drop raster data cache : data in cache will be lost.
1690
*
1691
* This call will recover memory used to cache data blocks for this raster
1692
* band, and ensure that new requests are referred to the underlying driver.
1693
*
1694
* This method is the same as the C function GDALDropRasterCache().
1695
*
1696
* @return CE_None on success.
1697
* @since 3.9
1698
*/
1699
1700
CPLErr GDALRasterBand::DropCache()
1701
1702
0
{
1703
0
    CPLErr result = CE_None;
1704
1705
0
    if (poBandBlockCache)
1706
0
        poBandBlockCache->DisableDirtyBlockWriting();
1707
1708
0
    CPLErr eGlobalErr = eFlushBlockErr;
1709
1710
0
    if (eFlushBlockErr != CE_None)
1711
0
    {
1712
0
        ReportError(
1713
0
            eFlushBlockErr, CPLE_AppDefined,
1714
0
            "An error occurred while writing a dirty block from DropCache");
1715
0
        eFlushBlockErr = CE_None;
1716
0
    }
1717
1718
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1719
0
        result = eGlobalErr;
1720
0
    else
1721
0
        result = poBandBlockCache->FlushCache();
1722
1723
0
    if (poBandBlockCache)
1724
0
        poBandBlockCache->EnableDirtyBlockWriting();
1725
1726
0
    return result;
1727
0
}
1728
1729
/************************************************************************/
1730
/*                        GDALDropRasterCache()                         */
1731
/************************************************************************/
1732
1733
/**
1734
* \brief Drop raster data cache.
1735
*
1736
* @see GDALRasterBand::DropCache()
1737
* @since 3.9
1738
*/
1739
1740
CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1741
1742
0
{
1743
0
    VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1744
1745
0
    return GDALRasterBand::FromHandle(hBand)->DropCache();
1746
0
}
1747
1748
/************************************************************************/
1749
/*                        UnreferenceBlock()                            */
1750
/*                                                                      */
1751
/*      Unreference the block from our array of blocks                  */
1752
/*      This method should only be called by                            */
1753
/*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1754
/*      the block cache mutex)                                          */
1755
/************************************************************************/
1756
1757
CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1758
0
{
1759
#ifdef notdef
1760
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1761
    {
1762
        if (poBandBlockCache == nullptr)
1763
            printf("poBandBlockCache == NULL\n"); /*ok*/
1764
        else
1765
            printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1766
        printf("caller = %s\n", pszCaller);            /*ok*/
1767
        printf("GDALRasterBand: %p\n", this);          /*ok*/
1768
        printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
1769
        printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
1770
        printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
1771
        printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
1772
        printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
1773
        poBlock->DumpBlock();
1774
        if (GetDataset() != nullptr)
1775
            printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1776
        GDALRasterBlock::Verify();
1777
        abort();
1778
    }
1779
#endif
1780
0
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1781
0
    return poBandBlockCache->UnreferenceBlock(poBlock);
1782
0
}
1783
1784
/************************************************************************/
1785
/*                        AddBlockToFreeList()                          */
1786
/*                                                                      */
1787
/*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
1788
/*      finished with a block about to be free'd, they pass it to that  */
1789
/*      method.                                                         */
1790
/************************************************************************/
1791
1792
//! @cond Doxygen_Suppress
1793
void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1794
0
{
1795
0
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1796
0
    return poBandBlockCache->AddBlockToFreeList(poBlock);
1797
0
}
1798
1799
//! @endcond
1800
1801
/************************************************************************/
1802
/*                             FlushBlock()                             */
1803
/************************************************************************/
1804
1805
/** Flush a block out of the block cache.
1806
 * @param nXBlockOff block x offset
1807
 * @param nYBlockOff blocky offset
1808
 * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1809
 * @return CE_None in case of success, an error code otherwise.
1810
 */
1811
CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1812
                                  int bWriteDirtyBlock)
1813
1814
0
{
1815
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1816
0
        return (CE_Failure);
1817
1818
    /* -------------------------------------------------------------------- */
1819
    /*      Validate the request                                            */
1820
    /* -------------------------------------------------------------------- */
1821
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1822
0
    {
1823
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1824
0
                    "Illegal nBlockXOff value (%d) in "
1825
0
                    "GDALRasterBand::FlushBlock()\n",
1826
0
                    nXBlockOff);
1827
1828
0
        return (CE_Failure);
1829
0
    }
1830
1831
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1832
0
    {
1833
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1834
0
                    "Illegal nBlockYOff value (%d) in "
1835
0
                    "GDALRasterBand::FlushBlock()\n",
1836
0
                    nYBlockOff);
1837
1838
0
        return (CE_Failure);
1839
0
    }
1840
1841
0
    return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1842
0
                                        bWriteDirtyBlock);
1843
0
}
1844
1845
/************************************************************************/
1846
/*                        TryGetLockedBlockRef()                        */
1847
/************************************************************************/
1848
1849
/**
1850
 * \brief Try fetching block ref.
1851
 *
1852
 * This method will returned the requested block (locked) if it is already
1853
 * in the block cache for the layer.  If not, nullptr is returned.
1854
 *
1855
 * If a non-NULL value is returned, then a lock for the block will have been
1856
 * acquired on behalf of the caller.  It is absolutely imperative that the
1857
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1858
 * severe problems may result.
1859
 *
1860
 * @param nXBlockOff the horizontal block offset, with zero indicating
1861
 * the left most block, 1 the next block and so forth.
1862
 *
1863
 * @param nYBlockOff the vertical block offset, with zero indicating
1864
 * the top most block, 1 the next block and so forth.
1865
 *
1866
 * @return NULL if block not available, or locked block pointer.
1867
 */
1868
1869
GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1870
                                                      int nYBlockOff)
1871
1872
0
{
1873
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1874
0
        return nullptr;
1875
1876
    /* -------------------------------------------------------------------- */
1877
    /*      Validate the request                                            */
1878
    /* -------------------------------------------------------------------- */
1879
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1880
0
    {
1881
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1882
0
                    "Illegal nBlockXOff value (%d) in "
1883
0
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1884
0
                    nXBlockOff);
1885
1886
0
        return (nullptr);
1887
0
    }
1888
1889
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1890
0
    {
1891
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1892
0
                    "Illegal nBlockYOff value (%d) in "
1893
0
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1894
0
                    nYBlockOff);
1895
1896
0
        return (nullptr);
1897
0
    }
1898
1899
0
    return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1900
0
}
1901
1902
/************************************************************************/
1903
/*                         GetLockedBlockRef()                          */
1904
/************************************************************************/
1905
1906
/**
1907
 * \brief Fetch a pointer to an internally cached raster block.
1908
 *
1909
 * This method will returned the requested block (locked) if it is already
1910
 * in the block cache for the layer.  If not, the block will be read from
1911
 * the driver, and placed in the layer block cached, then returned.  If an
1912
 * error occurs reading the block from the driver, a NULL value will be
1913
 * returned.
1914
 *
1915
 * If a non-NULL value is returned, then a lock for the block will have been
1916
 * acquired on behalf of the caller.  It is absolutely imperative that the
1917
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1918
 * severe problems may result.
1919
 *
1920
 * Note that calling GetLockedBlockRef() on a previously uncached band will
1921
 * enable caching.
1922
 *
1923
 * @param nXBlockOff the horizontal block offset, with zero indicating
1924
 * the left most block, 1 the next block and so forth.
1925
 *
1926
 * @param nYBlockOff the vertical block offset, with zero indicating
1927
 * the top most block, 1 the next block and so forth.
1928
 *
1929
 * @param bJustInitialize If TRUE the block will be allocated and initialized,
1930
 * but not actually read from the source.  This is useful when it will just
1931
 * be completely set and written back.
1932
 *
1933
 * @return pointer to the block object, or NULL on failure.
1934
 */
1935
1936
GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1937
                                                   int nYBlockOff,
1938
                                                   int bJustInitialize)
1939
1940
0
{
1941
    /* -------------------------------------------------------------------- */
1942
    /*      Try and fetch from cache.                                       */
1943
    /* -------------------------------------------------------------------- */
1944
0
    GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1945
1946
    /* -------------------------------------------------------------------- */
1947
    /*      If we didn't find it in our memory cache, instantiate a         */
1948
    /*      block (potentially load from disk) and "adopt" it into the      */
1949
    /*      cache.                                                          */
1950
    /* -------------------------------------------------------------------- */
1951
0
    if (poBlock == nullptr)
1952
0
    {
1953
0
        if (!InitBlockInfo())
1954
0
            return (nullptr);
1955
1956
        /* --------------------------------------------------------------------
1957
         */
1958
        /*      Validate the request */
1959
        /* --------------------------------------------------------------------
1960
         */
1961
0
        if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1962
0
        {
1963
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1964
0
                        "Illegal nBlockXOff value (%d) in "
1965
0
                        "GDALRasterBand::GetLockedBlockRef()\n",
1966
0
                        nXBlockOff);
1967
1968
0
            return (nullptr);
1969
0
        }
1970
1971
0
        if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1972
0
        {
1973
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1974
0
                        "Illegal nBlockYOff value (%d) in "
1975
0
                        "GDALRasterBand::GetLockedBlockRef()\n",
1976
0
                        nYBlockOff);
1977
1978
0
            return (nullptr);
1979
0
        }
1980
1981
0
        poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1982
0
        if (poBlock == nullptr)
1983
0
            return nullptr;
1984
1985
0
        poBlock->AddLock();
1986
1987
        /* We need to temporarily drop the read-write lock in the following */
1988
        /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
1989
         */
1990
        /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
1991
        /* block cache fills, T1 might need to flush dirty blocks of D2 in the
1992
         */
1993
        /* below Internalize(), which will cause GDALRasterBlock::Write() to be
1994
         */
1995
        /* called and attempt at taking the lock on T2 (already taken).
1996
         * Similarly */
1997
        /* for T2 with D1, hence a deadlock situation (#6163) */
1998
        /* But this may open the door to other problems... */
1999
0
        if (poDS)
2000
0
            poDS->TemporarilyDropReadWriteLock();
2001
        /* allocate data space */
2002
0
        CPLErr eErr = poBlock->Internalize();
2003
0
        if (poDS)
2004
0
            poDS->ReacquireReadWriteLock();
2005
0
        if (eErr != CE_None)
2006
0
        {
2007
0
            poBlock->DropLock();
2008
0
            delete poBlock;
2009
0
            return nullptr;
2010
0
        }
2011
2012
0
        if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2013
0
        {
2014
0
            poBlock->DropLock();
2015
0
            delete poBlock;
2016
0
            return nullptr;
2017
0
        }
2018
2019
0
        if (!bJustInitialize)
2020
0
        {
2021
0
            const GUInt32 nErrorCounter = CPLGetErrorCounter();
2022
0
            int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2023
0
            eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2024
0
            if (bCallLeaveReadWrite)
2025
0
                LeaveReadWrite();
2026
0
            if (eErr != CE_None)
2027
0
            {
2028
0
                poBlock->DropLock();
2029
0
                FlushBlock(nXBlockOff, nYBlockOff);
2030
0
                ReportError(CE_Failure, CPLE_AppDefined,
2031
0
                            "IReadBlock failed at X offset %d, Y offset %d%s",
2032
0
                            nXBlockOff, nYBlockOff,
2033
0
                            (nErrorCounter != CPLGetErrorCounter())
2034
0
                                ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2035
0
                                : "");
2036
0
                return nullptr;
2037
0
            }
2038
2039
0
            nBlockReads++;
2040
0
            if (static_cast<GIntBig>(nBlockReads) ==
2041
0
                    static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2042
0
                        1 &&
2043
0
                nBand == 1 && poDS != nullptr)
2044
0
            {
2045
0
                CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2046
0
                         poDS->GetDescription());
2047
0
            }
2048
0
        }
2049
0
    }
2050
2051
0
    return poBlock;
2052
0
}
2053
2054
/************************************************************************/
2055
/*                               Fill()                                 */
2056
/************************************************************************/
2057
2058
/**
2059
 * \brief Fill this band with a constant value.
2060
 *
2061
 * GDAL makes no guarantees
2062
 * about what values pixels in newly created files are set to, so this
2063
 * method can be used to clear a band to a specified "default" value.
2064
 * The fill value is passed in as a double but this will be converted
2065
 * to the underlying type before writing to the file. An optional
2066
 * second argument allows the imaginary component of a complex
2067
 * constant value to be specified.
2068
 *
2069
 * This method is the same as the C function GDALFillRaster().
2070
 *
2071
 * @param dfRealValue Real component of fill value
2072
 * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2073
 *
2074
 * @return CE_Failure if the write fails, otherwise CE_None
2075
 */
2076
CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2077
0
{
2078
2079
    // General approach is to construct a source block of the file's
2080
    // native type containing the appropriate value and then copy this
2081
    // to each block in the image via the RasterBlock cache. Using
2082
    // the cache means we avoid file I/O if it is not necessary, at the
2083
    // expense of some extra memcpy's (since we write to the
2084
    // RasterBlock cache, which is then at some point written to the
2085
    // underlying file, rather than simply directly to the underlying
2086
    // file.)
2087
2088
    // Check we can write to the file.
2089
0
    if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2090
0
    {
2091
0
        return CE_Failure;
2092
0
    }
2093
2094
    // Make sure block parameters are set.
2095
0
    if (!InitBlockInfo())
2096
0
        return CE_Failure;
2097
2098
    // Allocate the source block.
2099
0
    auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2100
0
    int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2101
0
    auto blockByteSize = blockSize * elementSize;
2102
0
    unsigned char *srcBlock =
2103
0
        static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2104
0
    if (srcBlock == nullptr)
2105
0
    {
2106
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
2107
0
                    "GDALRasterBand::Fill(): Out of memory "
2108
0
                    "allocating " CPL_FRMT_GUIB " bytes.\n",
2109
0
                    static_cast<GUIntBig>(blockByteSize));
2110
0
        return CE_Failure;
2111
0
    }
2112
2113
    // Initialize the source block.
2114
0
    double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2115
0
    GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2116
0
                    elementSize, blockSize);
2117
2118
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2119
2120
    // Write block to block cache
2121
0
    for (int j = 0; j < nBlocksPerColumn; ++j)
2122
0
    {
2123
0
        for (int i = 0; i < nBlocksPerRow; ++i)
2124
0
        {
2125
0
            GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2126
0
            if (destBlock == nullptr)
2127
0
            {
2128
0
                ReportError(CE_Failure, CPLE_OutOfMemory,
2129
0
                            "GDALRasterBand::Fill(): Error "
2130
0
                            "while retrieving cache block.");
2131
0
                VSIFree(srcBlock);
2132
0
                return CE_Failure;
2133
0
            }
2134
0
            memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2135
0
            destBlock->MarkDirty();
2136
0
            destBlock->DropLock();
2137
0
        }
2138
0
    }
2139
2140
0
    if (bCallLeaveReadWrite)
2141
0
        LeaveReadWrite();
2142
2143
    // Free up the source block
2144
0
    VSIFree(srcBlock);
2145
2146
0
    return CE_None;
2147
0
}
2148
2149
/************************************************************************/
2150
/*                         GDALFillRaster()                             */
2151
/************************************************************************/
2152
2153
/**
2154
 * \brief Fill this band with a constant value.
2155
 *
2156
 * @see GDALRasterBand::Fill()
2157
 */
2158
CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2159
                                  double dfImaginaryValue)
2160
0
{
2161
0
    VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2162
2163
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2164
0
    return poBand->Fill(dfRealValue, dfImaginaryValue);
2165
0
}
2166
2167
/************************************************************************/
2168
/*                             GetAccess()                              */
2169
/************************************************************************/
2170
2171
/**
2172
 * \brief Find out if we have update permission for this band.
2173
 *
2174
 * This method is the same as the C function GDALGetRasterAccess().
2175
 *
2176
 * @return Either GA_Update or GA_ReadOnly.
2177
 */
2178
2179
GDALAccess GDALRasterBand::GetAccess()
2180
2181
0
{
2182
0
    return eAccess;
2183
0
}
2184
2185
/************************************************************************/
2186
/*                        GDALGetRasterAccess()                         */
2187
/************************************************************************/
2188
2189
/**
2190
 * \brief Find out if we have update permission for this band.
2191
 *
2192
 * @see GDALRasterBand::GetAccess()
2193
 */
2194
2195
GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2196
2197
0
{
2198
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2199
2200
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2201
0
    return poBand->GetAccess();
2202
0
}
2203
2204
/************************************************************************/
2205
/*                          GetCategoryNames()                          */
2206
/************************************************************************/
2207
2208
/**
2209
 * \brief Fetch the list of category names for this raster.
2210
 *
2211
 * The return list is a "StringList" in the sense of the CPL functions.
2212
 * That is a NULL terminated array of strings.  Raster values without
2213
 * associated names will have an empty string in the returned list.  The
2214
 * first entry in the list is for raster values of zero, and so on.
2215
 *
2216
 * The returned stringlist should not be altered or freed by the application.
2217
 * It may change on the next GDAL call, so please copy it if it is needed
2218
 * for any period of time.
2219
 *
2220
 * This method is the same as the C function GDALGetRasterCategoryNames().
2221
 *
2222
 * @return list of names, or NULL if none.
2223
 */
2224
2225
char **GDALRasterBand::GetCategoryNames()
2226
2227
0
{
2228
0
    return nullptr;
2229
0
}
2230
2231
/************************************************************************/
2232
/*                     GDALGetRasterCategoryNames()                     */
2233
/************************************************************************/
2234
2235
/**
2236
 * \brief Fetch the list of category names for this raster.
2237
 *
2238
 * @see GDALRasterBand::GetCategoryNames()
2239
 */
2240
2241
char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2242
2243
0
{
2244
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2245
2246
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2247
0
    return poBand->GetCategoryNames();
2248
0
}
2249
2250
/************************************************************************/
2251
/*                          SetCategoryNames()                          */
2252
/************************************************************************/
2253
2254
/**
2255
 * \fn GDALRasterBand::SetCategoryNames(char**)
2256
 * \brief Set the category names for this band.
2257
 *
2258
 * See the GetCategoryNames() method for more on the interpretation of
2259
 * category names.
2260
 *
2261
 * This method is the same as the C function GDALSetRasterCategoryNames().
2262
 *
2263
 * @param papszNames the NULL terminated StringList of category names.  May
2264
 * be NULL to just clear the existing list.
2265
 *
2266
 * @return CE_None on success of CE_Failure on failure.  If unsupported
2267
 * by the driver CE_Failure is returned, but no error message is reported.
2268
 */
2269
2270
/**/
2271
/**/
2272
2273
CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2274
0
{
2275
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2276
0
        ReportError(CE_Failure, CPLE_NotSupported,
2277
0
                    "SetCategoryNames() not supported for this dataset.");
2278
2279
0
    return CE_Failure;
2280
0
}
2281
2282
/************************************************************************/
2283
/*                        GDALSetCategoryNames()                        */
2284
/************************************************************************/
2285
2286
/**
2287
 * \brief Set the category names for this band.
2288
 *
2289
 * @see GDALRasterBand::SetCategoryNames()
2290
 */
2291
2292
CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2293
                                              CSLConstList papszNames)
2294
2295
0
{
2296
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2297
2298
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2299
0
    return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2300
0
}
2301
2302
/************************************************************************/
2303
/*                           GetNoDataValue()                           */
2304
/************************************************************************/
2305
2306
/**
2307
 * \brief Fetch the no data value for this band.
2308
 *
2309
 * If there is no out of data value, an out of range value will generally
2310
 * be returned.  The no data value for a band is generally a special marker
2311
 * value used to mark pixels that are not valid data.  Such pixels should
2312
 * generally not be displayed, nor contribute to analysis operations.
2313
 *
2314
 * The no data value returned is 'raw', meaning that it has no offset and
2315
 * scale applied.
2316
 *
2317
 * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2318
 * lossy if the nodata value cannot exactly been represented by a double.
2319
 * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2320
 *
2321
 * This method is the same as the C function GDALGetRasterNoDataValue().
2322
 *
2323
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2324
 * is actually associated with this layer.  May be NULL (default).
2325
 *
2326
 * @return the nodata value for this band.
2327
 */
2328
2329
double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2330
2331
0
{
2332
0
    if (pbSuccess != nullptr)
2333
0
        *pbSuccess = FALSE;
2334
2335
0
    return -1e10;
2336
0
}
2337
2338
/************************************************************************/
2339
/*                      GDALGetRasterNoDataValue()                      */
2340
/************************************************************************/
2341
2342
/**
2343
 * \brief Fetch the no data value for this band.
2344
 *
2345
 * @see GDALRasterBand::GetNoDataValue()
2346
 */
2347
2348
double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2349
                                            int *pbSuccess)
2350
2351
0
{
2352
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2353
2354
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2355
0
    return poBand->GetNoDataValue(pbSuccess);
2356
0
}
2357
2358
/************************************************************************/
2359
/*                       GetNoDataValueAsInt64()                        */
2360
/************************************************************************/
2361
2362
/**
2363
 * \brief Fetch the no data value for this band.
2364
 *
2365
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2366
 *
2367
 * If there is no out of data value, an out of range value will generally
2368
 * be returned.  The no data value for a band is generally a special marker
2369
 * value used to mark pixels that are not valid data.  Such pixels should
2370
 * generally not be displayed, nor contribute to analysis operations.
2371
 *
2372
 * The no data value returned is 'raw', meaning that it has no offset and
2373
 * scale applied.
2374
 *
2375
 * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2376
 *
2377
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2378
 * is actually associated with this layer.  May be NULL (default).
2379
 *
2380
 * @return the nodata value for this band.
2381
 *
2382
 * @since GDAL 3.5
2383
 */
2384
2385
int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2386
2387
0
{
2388
0
    if (pbSuccess != nullptr)
2389
0
        *pbSuccess = FALSE;
2390
2391
0
    return std::numeric_limits<int64_t>::min();
2392
0
}
2393
2394
/************************************************************************/
2395
/*                   GDALGetRasterNoDataValueAsInt64()                  */
2396
/************************************************************************/
2397
2398
/**
2399
 * \brief Fetch the no data value for this band.
2400
 *
2401
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2402
 *
2403
 * @see GDALRasterBand::GetNoDataValueAsInt64()
2404
 *
2405
 * @since GDAL 3.5
2406
 */
2407
2408
int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2409
                                                    int *pbSuccess)
2410
2411
0
{
2412
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2413
0
                      std::numeric_limits<int64_t>::min());
2414
2415
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2416
0
    return poBand->GetNoDataValueAsInt64(pbSuccess);
2417
0
}
2418
2419
/************************************************************************/
2420
/*                       GetNoDataValueAsUInt64()                        */
2421
/************************************************************************/
2422
2423
/**
2424
 * \brief Fetch the no data value for this band.
2425
 *
2426
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2427
 *
2428
 * If there is no out of data value, an out of range value will generally
2429
 * be returned.  The no data value for a band is generally a special marker
2430
 * value used to mark pixels that are not valid data.  Such pixels should
2431
 * generally not be displayed, nor contribute to analysis operations.
2432
 *
2433
 * The no data value returned is 'raw', meaning that it has no offset and
2434
 * scale applied.
2435
 *
2436
 * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2437
 *
2438
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2439
 * is actually associated with this layer.  May be NULL (default).
2440
 *
2441
 * @return the nodata value for this band.
2442
 *
2443
 * @since GDAL 3.5
2444
 */
2445
2446
uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2447
2448
0
{
2449
0
    if (pbSuccess != nullptr)
2450
0
        *pbSuccess = FALSE;
2451
2452
0
    return std::numeric_limits<uint64_t>::max();
2453
0
}
2454
2455
/************************************************************************/
2456
/*                   GDALGetRasterNoDataValueAsUInt64()                  */
2457
/************************************************************************/
2458
2459
/**
2460
 * \brief Fetch the no data value for this band.
2461
 *
2462
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2463
 *
2464
 * @see GDALRasterBand::GetNoDataValueAsUInt64()
2465
 *
2466
 * @since GDAL 3.5
2467
 */
2468
2469
uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2470
                                                      int *pbSuccess)
2471
2472
0
{
2473
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2474
0
                      std::numeric_limits<uint64_t>::max());
2475
2476
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2477
0
    return poBand->GetNoDataValueAsUInt64(pbSuccess);
2478
0
}
2479
2480
/************************************************************************/
2481
/*                        SetNoDataValueAsString()                      */
2482
/************************************************************************/
2483
2484
/**
2485
 * \brief Set the no data value for this band.
2486
 *
2487
 * Depending on drivers, changing the no data value may or may not have an
2488
 * effect on the pixel values of a raster that has just been created. It is
2489
 * thus advised to explicitly called Fill() if the intent is to initialize
2490
 * the raster to the nodata value.
2491
 * In any case, changing an existing no data value, when one already exists and
2492
 * the dataset exists or has been initialized, has no effect on the pixel whose
2493
 * value matched the previous nodata value.
2494
 *
2495
 * To clear the nodata value, use DeleteNoDataValue().
2496
 *
2497
 * @param pszNoData the value to set.
2498
 * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2499
 *             If the value cannot be exactly represented on the output data
2500
 *             type, *pbCannotBeExactlyRepresented will be set to true.
2501
 *
2502
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2503
 * by the driver, CE_Failure is returned but no error message will have
2504
 * been emitted.
2505
 *
2506
 * @since 3.11
2507
 */
2508
2509
CPLErr
2510
GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2511
                                       bool *pbCannotBeExactlyRepresented)
2512
0
{
2513
0
    if (pbCannotBeExactlyRepresented)
2514
0
        *pbCannotBeExactlyRepresented = false;
2515
0
    if (eDataType == GDT_Int64)
2516
0
    {
2517
0
        if (strchr(pszNoData, '.') ||
2518
0
            CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2519
0
        {
2520
0
            char *endptr = nullptr;
2521
0
            const double dfVal = CPLStrtod(pszNoData, &endptr);
2522
0
            if (endptr == pszNoData + strlen(pszNoData) &&
2523
0
                GDALIsValueExactAs<int64_t>(dfVal))
2524
0
            {
2525
0
                return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2526
0
            }
2527
0
        }
2528
0
        else
2529
0
        {
2530
0
            try
2531
0
            {
2532
0
                const auto val = std::stoll(pszNoData);
2533
0
                return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2534
0
            }
2535
0
            catch (const std::exception &)
2536
0
            {
2537
0
            }
2538
0
        }
2539
0
    }
2540
0
    else if (eDataType == GDT_UInt64)
2541
0
    {
2542
0
        if (strchr(pszNoData, '.') ||
2543
0
            CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2544
0
        {
2545
0
            char *endptr = nullptr;
2546
0
            const double dfVal = CPLStrtod(pszNoData, &endptr);
2547
0
            if (endptr == pszNoData + strlen(pszNoData) &&
2548
0
                GDALIsValueExactAs<uint64_t>(dfVal))
2549
0
            {
2550
0
                return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2551
0
            }
2552
0
        }
2553
0
        else
2554
0
        {
2555
0
            try
2556
0
            {
2557
0
                const auto val = std::stoull(pszNoData);
2558
0
                return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2559
0
            }
2560
0
            catch (const std::exception &)
2561
0
            {
2562
0
            }
2563
0
        }
2564
0
    }
2565
0
    else if (eDataType == GDT_Float32)
2566
0
    {
2567
0
        char *endptr = nullptr;
2568
0
        const float fVal = CPLStrtof(pszNoData, &endptr);
2569
0
        if (endptr == pszNoData + strlen(pszNoData))
2570
0
        {
2571
0
            return SetNoDataValue(fVal);
2572
0
        }
2573
0
    }
2574
0
    else
2575
0
    {
2576
0
        char *endptr = nullptr;
2577
0
        const double dfVal = CPLStrtod(pszNoData, &endptr);
2578
0
        if (endptr == pszNoData + strlen(pszNoData) &&
2579
0
            GDALIsValueExactAs(dfVal, eDataType))
2580
0
        {
2581
0
            return SetNoDataValue(dfVal);
2582
0
        }
2583
0
    }
2584
0
    if (pbCannotBeExactlyRepresented)
2585
0
        *pbCannotBeExactlyRepresented = true;
2586
0
    return CE_Failure;
2587
0
}
2588
2589
/************************************************************************/
2590
/*                           SetNoDataValue()                           */
2591
/************************************************************************/
2592
2593
/**
2594
 * \fn GDALRasterBand::SetNoDataValue(double)
2595
 * \brief Set the no data value for this band.
2596
 *
2597
 * Depending on drivers, changing the no data value may or may not have an
2598
 * effect on the pixel values of a raster that has just been created. It is
2599
 * thus advised to explicitly called Fill() if the intent is to initialize
2600
 * the raster to the nodata value.
2601
 * In any case, changing an existing no data value, when one already exists and
2602
 * the dataset exists or has been initialized, has no effect on the pixel whose
2603
 * value matched the previous nodata value.
2604
 *
2605
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2606
 * be represented by a double, use SetNoDataValueAsInt64() or
2607
 * SetNoDataValueAsUInt64() instead.
2608
 *
2609
 * To clear the nodata value, use DeleteNoDataValue().
2610
 *
2611
 * This method is the same as the C function GDALSetRasterNoDataValue().
2612
 *
2613
 * @param dfNoData the value to set.
2614
 *
2615
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2616
 * by the driver, CE_Failure is returned but no error message will have
2617
 * been emitted.
2618
 */
2619
2620
/**/
2621
/**/
2622
2623
CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2624
2625
0
{
2626
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2627
0
        ReportError(CE_Failure, CPLE_NotSupported,
2628
0
                    "SetNoDataValue() not supported for this dataset.");
2629
2630
0
    return CE_Failure;
2631
0
}
2632
2633
/************************************************************************/
2634
/*                         GDALSetRasterNoDataValue()                   */
2635
/************************************************************************/
2636
2637
/**
2638
 * \brief Set the no data value for this band.
2639
 *
2640
 * Depending on drivers, changing the no data value may or may not have an
2641
 * effect on the pixel values of a raster that has just been created. It is
2642
 * thus advised to explicitly called Fill() if the intent is to initialize
2643
 * the raster to the nodata value.
2644
 * In any case, changing an existing no data value, when one already exists and
2645
 * the dataset exists or has been initialized, has no effect on the pixel whose
2646
 * value matched the previous nodata value.
2647
 *
2648
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2649
 * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2650
 * GDALSetRasterNoDataValueAsUInt64() instead.
2651
 *
2652
 * @see GDALRasterBand::SetNoDataValue()
2653
 */
2654
2655
CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2656
                                            double dfValue)
2657
2658
0
{
2659
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2660
2661
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2662
0
    return poBand->SetNoDataValue(dfValue);
2663
0
}
2664
2665
/************************************************************************/
2666
/*                       SetNoDataValueAsInt64()                        */
2667
/************************************************************************/
2668
2669
/**
2670
 * \brief Set the no data value for this band.
2671
 *
2672
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2673
 *
2674
 * Depending on drivers, changing the no data value may or may not have an
2675
 * effect on the pixel values of a raster that has just been created. It is
2676
 * thus advised to explicitly called Fill() if the intent is to initialize
2677
 * the raster to the nodata value.
2678
 * In ay case, changing an existing no data value, when one already exists and
2679
 * the dataset exists or has been initialized, has no effect on the pixel whose
2680
 * value matched the previous nodata value.
2681
 *
2682
 * To clear the nodata value, use DeleteNoDataValue().
2683
 *
2684
 * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2685
 *
2686
 * @param nNoDataValue the value to set.
2687
 *
2688
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2689
 * by the driver, CE_Failure is returned but no error message will have
2690
 * been emitted.
2691
 *
2692
 * @since GDAL 3.5
2693
 */
2694
2695
CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2696
2697
0
{
2698
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2699
0
        ReportError(CE_Failure, CPLE_NotSupported,
2700
0
                    "SetNoDataValueAsInt64() not supported for this dataset.");
2701
2702
0
    return CE_Failure;
2703
0
}
2704
2705
/************************************************************************/
2706
/*                 GDALSetRasterNoDataValueAsInt64()                    */
2707
/************************************************************************/
2708
2709
/**
2710
 * \brief Set the no data value for this band.
2711
 *
2712
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2713
 *
2714
 * Depending on drivers, changing the no data value may or may not have an
2715
 * effect on the pixel values of a raster that has just been created. It is
2716
 * thus advised to explicitly called Fill() if the intent is to initialize
2717
 * the raster to the nodata value.
2718
 * In ay case, changing an existing no data value, when one already exists and
2719
 * the dataset exists or has been initialized, has no effect on the pixel whose
2720
 * value matched the previous nodata value.
2721
 *
2722
 * @see GDALRasterBand::SetNoDataValueAsInt64()
2723
 *
2724
 * @since GDAL 3.5
2725
 */
2726
2727
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2728
                                                   int64_t nValue)
2729
2730
0
{
2731
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2732
2733
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2734
0
    return poBand->SetNoDataValueAsInt64(nValue);
2735
0
}
2736
2737
/************************************************************************/
2738
/*                       SetNoDataValueAsUInt64()                       */
2739
/************************************************************************/
2740
2741
/**
2742
 * \brief Set the no data value for this band.
2743
 *
2744
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2745
 *
2746
 * Depending on drivers, changing the no data value may or may not have an
2747
 * effect on the pixel values of a raster that has just been created. It is
2748
 * thus advised to explicitly called Fill() if the intent is to initialize
2749
 * the raster to the nodata value.
2750
 * In ay case, changing an existing no data value, when one already exists and
2751
 * the dataset exists or has been initialized, has no effect on the pixel whose
2752
 * value matched the previous nodata value.
2753
 *
2754
 * To clear the nodata value, use DeleteNoDataValue().
2755
 *
2756
 * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2757
 *
2758
 * @param nNoDataValue the value to set.
2759
 *
2760
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2761
 * by the driver, CE_Failure is returned but no error message will have
2762
 * been emitted.
2763
 *
2764
 * @since GDAL 3.5
2765
 */
2766
2767
CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2768
2769
0
{
2770
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2771
0
        ReportError(CE_Failure, CPLE_NotSupported,
2772
0
                    "SetNoDataValueAsUInt64() not supported for this dataset.");
2773
2774
0
    return CE_Failure;
2775
0
}
2776
2777
/************************************************************************/
2778
/*                 GDALSetRasterNoDataValueAsUInt64()                    */
2779
/************************************************************************/
2780
2781
/**
2782
 * \brief Set the no data value for this band.
2783
 *
2784
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2785
 *
2786
 * Depending on drivers, changing the no data value may or may not have an
2787
 * effect on the pixel values of a raster that has just been created. It is
2788
 * thus advised to explicitly called Fill() if the intent is to initialize
2789
 * the raster to the nodata value.
2790
 * In ay case, changing an existing no data value, when one already exists and
2791
 * the dataset exists or has been initialized, has no effect on the pixel whose
2792
 * value matched the previous nodata value.
2793
 *
2794
 * @see GDALRasterBand::SetNoDataValueAsUInt64()
2795
 *
2796
 * @since GDAL 3.5
2797
 */
2798
2799
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2800
                                                    uint64_t nValue)
2801
2802
0
{
2803
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2804
2805
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2806
0
    return poBand->SetNoDataValueAsUInt64(nValue);
2807
0
}
2808
2809
/************************************************************************/
2810
/*                        DeleteNoDataValue()                           */
2811
/************************************************************************/
2812
2813
/**
2814
 * \brief Remove the no data value for this band.
2815
 *
2816
 * This method is the same as the C function GDALDeleteRasterNoDataValue().
2817
 *
2818
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2819
 * by the driver, CE_Failure is returned but no error message will have
2820
 * been emitted.
2821
 *
2822
 * @since GDAL 2.1
2823
 */
2824
2825
CPLErr GDALRasterBand::DeleteNoDataValue()
2826
2827
0
{
2828
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2829
0
        ReportError(CE_Failure, CPLE_NotSupported,
2830
0
                    "DeleteNoDataValue() not supported for this dataset.");
2831
2832
0
    return CE_Failure;
2833
0
}
2834
2835
/************************************************************************/
2836
/*                       GDALDeleteRasterNoDataValue()                  */
2837
/************************************************************************/
2838
2839
/**
2840
 * \brief Remove the no data value for this band.
2841
 *
2842
 * @see GDALRasterBand::DeleteNoDataValue()
2843
 *
2844
 * @since GDAL 2.1
2845
 */
2846
2847
CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2848
2849
0
{
2850
0
    VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2851
2852
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2853
0
    return poBand->DeleteNoDataValue();
2854
0
}
2855
2856
/************************************************************************/
2857
/*                             GetMaximum()                             */
2858
/************************************************************************/
2859
2860
/**
2861
 * \brief Fetch the maximum value for this band.
2862
 *
2863
 * For file formats that don't know this intrinsically, the maximum supported
2864
 * value for the data type will generally be returned.
2865
 *
2866
 * This method is the same as the C function GDALGetRasterMaximum().
2867
 *
2868
 * @param pbSuccess pointer to a boolean to use to indicate if the
2869
 * returned value is a tight maximum or not.  May be NULL (default).
2870
 *
2871
 * @return the maximum raster value (excluding no data pixels)
2872
 */
2873
2874
double GDALRasterBand::GetMaximum(int *pbSuccess)
2875
2876
0
{
2877
0
    const char *pszValue = nullptr;
2878
2879
0
    if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2880
0
    {
2881
0
        if (pbSuccess != nullptr)
2882
0
            *pbSuccess = TRUE;
2883
2884
0
        return CPLAtofM(pszValue);
2885
0
    }
2886
2887
0
    if (pbSuccess != nullptr)
2888
0
        *pbSuccess = FALSE;
2889
2890
0
    switch (eDataType)
2891
0
    {
2892
0
        case GDT_Byte:
2893
0
        {
2894
0
            EnablePixelTypeSignedByteWarning(false);
2895
0
            const char *pszPixelType =
2896
0
                GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2897
0
            EnablePixelTypeSignedByteWarning(true);
2898
0
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2899
0
                return 127;
2900
2901
0
            return 255;
2902
0
        }
2903
2904
0
        case GDT_Int8:
2905
0
            return 127;
2906
2907
0
        case GDT_UInt16:
2908
0
            return 65535;
2909
2910
0
        case GDT_Int16:
2911
0
        case GDT_CInt16:
2912
0
            return 32767;
2913
2914
0
        case GDT_Int32:
2915
0
        case GDT_CInt32:
2916
0
            return 2147483647.0;
2917
2918
0
        case GDT_UInt32:
2919
0
            return 4294967295.0;
2920
2921
0
        case GDT_Int64:
2922
0
            return static_cast<double>(std::numeric_limits<GInt64>::max());
2923
2924
0
        case GDT_UInt64:
2925
0
            return static_cast<double>(std::numeric_limits<GUInt64>::max());
2926
2927
0
        case GDT_Float16:
2928
0
        case GDT_CFloat16:
2929
0
            return 65504.0;
2930
2931
0
        case GDT_Float32:
2932
0
        case GDT_CFloat32:
2933
0
            return 4294967295.0;  // Not actually accurate.
2934
2935
0
        case GDT_Float64:
2936
0
        case GDT_CFloat64:
2937
0
            return 4294967295.0;  // Not actually accurate.
2938
2939
0
        case GDT_Unknown:
2940
0
        case GDT_TypeCount:
2941
0
            break;
2942
0
    }
2943
0
    return 4294967295.0;  // Not actually accurate.
2944
0
}
2945
2946
/************************************************************************/
2947
/*                        GDALGetRasterMaximum()                        */
2948
/************************************************************************/
2949
2950
/**
2951
 * \brief Fetch the maximum value for this band.
2952
 *
2953
 * @see GDALRasterBand::GetMaximum()
2954
 */
2955
2956
double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2957
2958
0
{
2959
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2960
2961
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2962
0
    return poBand->GetMaximum(pbSuccess);
2963
0
}
2964
2965
/************************************************************************/
2966
/*                             GetMinimum()                             */
2967
/************************************************************************/
2968
2969
/**
2970
 * \brief Fetch the minimum value for this band.
2971
 *
2972
 * For file formats that don't know this intrinsically, the minimum supported
2973
 * value for the data type will generally be returned.
2974
 *
2975
 * This method is the same as the C function GDALGetRasterMinimum().
2976
 *
2977
 * @param pbSuccess pointer to a boolean to use to indicate if the
2978
 * returned value is a tight minimum or not.  May be NULL (default).
2979
 *
2980
 * @return the minimum raster value (excluding no data pixels)
2981
 */
2982
2983
double GDALRasterBand::GetMinimum(int *pbSuccess)
2984
2985
0
{
2986
0
    const char *pszValue = nullptr;
2987
2988
0
    if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
2989
0
    {
2990
0
        if (pbSuccess != nullptr)
2991
0
            *pbSuccess = TRUE;
2992
2993
0
        return CPLAtofM(pszValue);
2994
0
    }
2995
2996
0
    if (pbSuccess != nullptr)
2997
0
        *pbSuccess = FALSE;
2998
2999
0
    switch (eDataType)
3000
0
    {
3001
0
        case GDT_Byte:
3002
0
        {
3003
0
            EnablePixelTypeSignedByteWarning(false);
3004
0
            const char *pszPixelType =
3005
0
                GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3006
0
            EnablePixelTypeSignedByteWarning(true);
3007
0
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3008
0
                return -128;
3009
3010
0
            return 0;
3011
0
        }
3012
3013
0
        case GDT_Int8:
3014
0
            return -128;
3015
0
            break;
3016
3017
0
        case GDT_UInt16:
3018
0
            return 0;
3019
3020
0
        case GDT_Int16:
3021
0
        case GDT_CInt16:
3022
0
            return -32768;
3023
3024
0
        case GDT_Int32:
3025
0
        case GDT_CInt32:
3026
0
            return -2147483648.0;
3027
3028
0
        case GDT_UInt32:
3029
0
            return 0;
3030
3031
0
        case GDT_Int64:
3032
0
            return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3033
3034
0
        case GDT_UInt64:
3035
0
            return 0;
3036
3037
0
        case GDT_Float16:
3038
0
        case GDT_CFloat16:
3039
0
            return -65504.0;
3040
3041
0
        case GDT_Float32:
3042
0
        case GDT_CFloat32:
3043
0
            return -4294967295.0;  // Not actually accurate.
3044
3045
0
        case GDT_Float64:
3046
0
        case GDT_CFloat64:
3047
0
            return -4294967295.0;  // Not actually accurate.
3048
3049
0
        case GDT_Unknown:
3050
0
        case GDT_TypeCount:
3051
0
            break;
3052
0
    }
3053
0
    return -4294967295.0;  // Not actually accurate.
3054
0
}
3055
3056
/************************************************************************/
3057
/*                        GDALGetRasterMinimum()                        */
3058
/************************************************************************/
3059
3060
/**
3061
 * \brief Fetch the minimum value for this band.
3062
 *
3063
 * @see GDALRasterBand::GetMinimum()
3064
 */
3065
3066
double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3067
3068
0
{
3069
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3070
3071
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3072
0
    return poBand->GetMinimum(pbSuccess);
3073
0
}
3074
3075
/************************************************************************/
3076
/*                       GetColorInterpretation()                       */
3077
/************************************************************************/
3078
3079
/**
3080
 * \brief How should this band be interpreted as color?
3081
 *
3082
 * GCI_Undefined is returned when the format doesn't know anything
3083
 * about the color interpretation.
3084
 *
3085
 * This method is the same as the C function
3086
 * GDALGetRasterColorInterpretation().
3087
 *
3088
 * @return color interpretation value for band.
3089
 */
3090
3091
GDALColorInterp GDALRasterBand::GetColorInterpretation()
3092
3093
0
{
3094
0
    return GCI_Undefined;
3095
0
}
3096
3097
/************************************************************************/
3098
/*                  GDALGetRasterColorInterpretation()                  */
3099
/************************************************************************/
3100
3101
/**
3102
 * \brief How should this band be interpreted as color?
3103
 *
3104
 * @see GDALRasterBand::GetColorInterpretation()
3105
 */
3106
3107
GDALColorInterp CPL_STDCALL
3108
GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3109
3110
0
{
3111
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3112
3113
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3114
0
    return poBand->GetColorInterpretation();
3115
0
}
3116
3117
/************************************************************************/
3118
/*                       SetColorInterpretation()                       */
3119
/************************************************************************/
3120
3121
/**
3122
 * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3123
 * \brief Set color interpretation of a band.
3124
 *
3125
 * This method is the same as the C function GDALSetRasterColorInterpretation().
3126
 *
3127
 * @param eColorInterp the new color interpretation to apply to this band.
3128
 *
3129
 * @return CE_None on success or CE_Failure if method is unsupported by format.
3130
 */
3131
3132
/**/
3133
/**/
3134
3135
CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3136
3137
0
{
3138
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3139
0
        ReportError(CE_Failure, CPLE_NotSupported,
3140
0
                    "SetColorInterpretation() not supported for this dataset.");
3141
0
    return CE_Failure;
3142
0
}
3143
3144
/************************************************************************/
3145
/*                  GDALSetRasterColorInterpretation()                  */
3146
/************************************************************************/
3147
3148
/**
3149
 * \brief Set color interpretation of a band.
3150
 *
3151
 * @see GDALRasterBand::SetColorInterpretation()
3152
 */
3153
3154
CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3155
    GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3156
3157
0
{
3158
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3159
3160
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3161
0
    return poBand->SetColorInterpretation(eColorInterp);
3162
0
}
3163
3164
/************************************************************************/
3165
/*                           GetColorTable()                            */
3166
/************************************************************************/
3167
3168
/**
3169
 * \brief Fetch the color table associated with band.
3170
 *
3171
 * If there is no associated color table, the return result is NULL.  The
3172
 * returned color table remains owned by the GDALRasterBand, and can't
3173
 * be depended on for long, nor should it ever be modified by the caller.
3174
 *
3175
 * This method is the same as the C function GDALGetRasterColorTable().
3176
 *
3177
 * @return internal color table, or NULL.
3178
 */
3179
3180
GDALColorTable *GDALRasterBand::GetColorTable()
3181
3182
0
{
3183
0
    return nullptr;
3184
0
}
3185
3186
/************************************************************************/
3187
/*                      GDALGetRasterColorTable()                       */
3188
/************************************************************************/
3189
3190
/**
3191
 * \brief Fetch the color table associated with band.
3192
 *
3193
 * @see GDALRasterBand::GetColorTable()
3194
 */
3195
3196
GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3197
3198
0
{
3199
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3200
3201
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3202
0
    return GDALColorTable::ToHandle(poBand->GetColorTable());
3203
0
}
3204
3205
/************************************************************************/
3206
/*                           SetColorTable()                            */
3207
/************************************************************************/
3208
3209
/**
3210
 * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3211
 * \brief Set the raster color table.
3212
 *
3213
 * The driver will make a copy of all desired data in the colortable.  It
3214
 * remains owned by the caller after the call.
3215
 *
3216
 * This method is the same as the C function GDALSetRasterColorTable().
3217
 *
3218
 * @param poCT the color table to apply.  This may be NULL to clear the color
3219
 * table (where supported).
3220
 *
3221
 * @return CE_None on success, or CE_Failure on failure.  If the action is
3222
 * unsupported by the driver, a value of CE_Failure is returned, but no
3223
 * error is issued.
3224
 */
3225
3226
/**/
3227
/**/
3228
3229
CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3230
3231
0
{
3232
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3233
0
        ReportError(CE_Failure, CPLE_NotSupported,
3234
0
                    "SetColorTable() not supported for this dataset.");
3235
0
    return CE_Failure;
3236
0
}
3237
3238
/************************************************************************/
3239
/*                      GDALSetRasterColorTable()                       */
3240
/************************************************************************/
3241
3242
/**
3243
 * \brief Set the raster color table.
3244
 *
3245
 * @see GDALRasterBand::SetColorTable()
3246
 */
3247
3248
CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3249
                                           GDALColorTableH hCT)
3250
3251
0
{
3252
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3253
3254
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3255
0
    return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3256
0
}
3257
3258
/************************************************************************/
3259
/*                       HasArbitraryOverviews()                        */
3260
/************************************************************************/
3261
3262
/**
3263
 * \brief Check for arbitrary overviews.
3264
 *
3265
 * This returns TRUE if the underlying datastore can compute arbitrary
3266
 * overviews efficiently, such as is the case with OGDI over a network.
3267
 * Datastores with arbitrary overviews don't generally have any fixed
3268
 * overviews, but the RasterIO() method can be used in downsampling mode
3269
 * to get overview data efficiently.
3270
 *
3271
 * This method is the same as the C function GDALHasArbitraryOverviews(),
3272
 *
3273
 * @return TRUE if arbitrary overviews available (efficiently), otherwise
3274
 * FALSE.
3275
 */
3276
3277
int GDALRasterBand::HasArbitraryOverviews()
3278
3279
0
{
3280
0
    return FALSE;
3281
0
}
3282
3283
/************************************************************************/
3284
/*                     GDALHasArbitraryOverviews()                      */
3285
/************************************************************************/
3286
3287
/**
3288
 * \brief Check for arbitrary overviews.
3289
 *
3290
 * @see GDALRasterBand::HasArbitraryOverviews()
3291
 */
3292
3293
int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3294
3295
0
{
3296
0
    VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3297
3298
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3299
0
    return poBand->HasArbitraryOverviews();
3300
0
}
3301
3302
/************************************************************************/
3303
/*                          GetOverviewCount()                          */
3304
/************************************************************************/
3305
3306
/**
3307
 * \brief Return the number of overview layers available.
3308
 *
3309
 * This method is the same as the C function GDALGetOverviewCount().
3310
 *
3311
 * @return overview count, zero if none.
3312
 */
3313
3314
int GDALRasterBand::GetOverviewCount()
3315
3316
0
{
3317
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3318
0
        poDS->AreOverviewsEnabled())
3319
0
        return poDS->oOvManager.GetOverviewCount(nBand);
3320
3321
0
    return 0;
3322
0
}
3323
3324
/************************************************************************/
3325
/*                        GDALGetOverviewCount()                        */
3326
/************************************************************************/
3327
3328
/**
3329
 * \brief Return the number of overview layers available.
3330
 *
3331
 * @see GDALRasterBand::GetOverviewCount()
3332
 */
3333
3334
int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3335
3336
0
{
3337
0
    VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3338
3339
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3340
0
    return poBand->GetOverviewCount();
3341
0
}
3342
3343
/************************************************************************/
3344
/*                            GetOverview()                             */
3345
/************************************************************************/
3346
3347
/**
3348
 * \brief Fetch overview raster band object.
3349
 *
3350
 * This method is the same as the C function GDALGetOverview().
3351
 *
3352
 * @param i overview index between 0 and GetOverviewCount()-1.
3353
 *
3354
 * @return overview GDALRasterBand.
3355
 */
3356
3357
GDALRasterBand *GDALRasterBand::GetOverview(int i)
3358
3359
0
{
3360
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3361
0
        poDS->AreOverviewsEnabled())
3362
0
        return poDS->oOvManager.GetOverview(nBand, i);
3363
3364
0
    return nullptr;
3365
0
}
3366
3367
/************************************************************************/
3368
/*                          GDALGetOverview()                           */
3369
/************************************************************************/
3370
3371
/**
3372
 * \brief Fetch overview raster band object.
3373
 *
3374
 * @see GDALRasterBand::GetOverview()
3375
 */
3376
3377
GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3378
3379
0
{
3380
0
    VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3381
3382
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3383
0
    return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3384
0
}
3385
3386
/************************************************************************/
3387
/*                      GetRasterSampleOverview()                       */
3388
/************************************************************************/
3389
3390
/**
3391
 * \brief Fetch best sampling overview.
3392
 *
3393
 * Returns the most reduced overview of the given band that still satisfies
3394
 * the desired number of samples.  This function can be used with zero
3395
 * as the number of desired samples to fetch the most reduced overview.
3396
 * The same band as was passed in will be returned if it has not overviews,
3397
 * or if none of the overviews have enough samples.
3398
 *
3399
 * This method is the same as the C functions GDALGetRasterSampleOverview()
3400
 * and GDALGetRasterSampleOverviewEx().
3401
 *
3402
 * @param nDesiredSamples the returned band will have at least this many
3403
 * pixels.
3404
 *
3405
 * @return optimal overview or the band itself.
3406
 */
3407
3408
GDALRasterBand *
3409
GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3410
3411
0
{
3412
0
    GDALRasterBand *poBestBand = this;
3413
3414
0
    double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3415
3416
0
    for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3417
0
    {
3418
0
        GDALRasterBand *poOBand = GetOverview(iOverview);
3419
3420
0
        if (poOBand == nullptr)
3421
0
            continue;
3422
3423
0
        const double dfOSamples =
3424
0
            poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3425
3426
0
        if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3427
0
        {
3428
0
            dfBestSamples = dfOSamples;
3429
0
            poBestBand = poOBand;
3430
0
        }
3431
0
    }
3432
3433
0
    return poBestBand;
3434
0
}
3435
3436
/************************************************************************/
3437
/*                    GDALGetRasterSampleOverview()                     */
3438
/************************************************************************/
3439
3440
/**
3441
 * \brief Fetch best sampling overview.
3442
 *
3443
 * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3444
 * billion samples.
3445
 *
3446
 * @see GDALRasterBand::GetRasterSampleOverview()
3447
 * @see GDALGetRasterSampleOverviewEx()
3448
 */
3449
3450
GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3451
                                                        int nDesiredSamples)
3452
3453
0
{
3454
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3455
3456
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3457
0
    return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3458
0
        nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3459
0
}
3460
3461
/************************************************************************/
3462
/*                    GDALGetRasterSampleOverviewEx()                   */
3463
/************************************************************************/
3464
3465
/**
3466
 * \brief Fetch best sampling overview.
3467
 *
3468
 * @see GDALRasterBand::GetRasterSampleOverview()
3469
 * @since GDAL 2.0
3470
 */
3471
3472
GDALRasterBandH CPL_STDCALL
3473
GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3474
3475
0
{
3476
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3477
3478
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3479
0
    return GDALRasterBand::ToHandle(
3480
0
        poBand->GetRasterSampleOverview(nDesiredSamples));
3481
0
}
3482
3483
/************************************************************************/
3484
/*                           BuildOverviews()                           */
3485
/************************************************************************/
3486
3487
/**
3488
 * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3489
 * GDALProgressFunc, void*) \brief Build raster overview(s)
3490
 *
3491
 * If the operation is unsupported for the indicated dataset, then
3492
 * CE_Failure is returned, and CPLGetLastErrorNo() will return
3493
 * CPLE_NotSupported.
3494
 *
3495
 * WARNING: Most formats don't support per-band overview computation, but
3496
 * require that overviews are computed for all bands of a dataset, using
3497
 * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3498
 * is the HFA driver which supports this method.
3499
 *
3500
 * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3501
 * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3502
 * applied.
3503
 * @param nOverviews number of overviews to build.
3504
 * @param panOverviewList the list of overview decimation factors to build.
3505
 * @param pfnProgress a function to call to report progress, or NULL.
3506
 * @param pProgressData application data to pass to the progress function.
3507
 * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3508
 *                     key=value pairs, or NULL
3509
 *
3510
 * @return CE_None on success or CE_Failure if the operation doesn't work.
3511
 */
3512
3513
/**/
3514
/**/
3515
3516
CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3517
                                      int /*nOverviews*/,
3518
                                      const int * /*panOverviewList*/,
3519
                                      GDALProgressFunc /*pfnProgress*/,
3520
                                      void * /*pProgressData*/,
3521
                                      CSLConstList /* papszOptions */)
3522
3523
0
{
3524
0
    ReportError(CE_Failure, CPLE_NotSupported,
3525
0
                "BuildOverviews() not supported for this dataset.");
3526
3527
0
    return (CE_Failure);
3528
0
}
3529
3530
/************************************************************************/
3531
/*                             GetOffset()                              */
3532
/************************************************************************/
3533
3534
/**
3535
 * \brief Fetch the raster value offset.
3536
 *
3537
 * This value (in combination with the GetScale() value) can be used to
3538
 * transform raw pixel values into the units returned by GetUnitType().
3539
 * For example this might be used to store elevations in GUInt16 bands
3540
 * with a precision of 0.1, and starting from -100.
3541
 *
3542
 * Units value = (raw value * scale) + offset
3543
 *
3544
 * Note that applying scale and offset is of the responsibility of the user,
3545
 * and is not done by methods such as RasterIO() or ReadBlock().
3546
 *
3547
 * For file formats that don't know this intrinsically a value of zero
3548
 * is returned.
3549
 *
3550
 * This method is the same as the C function GDALGetRasterOffset().
3551
 *
3552
 * @param pbSuccess pointer to a boolean to use to indicate if the
3553
 * returned value is meaningful or not.  May be NULL (default).
3554
 *
3555
 * @return the raster offset.
3556
 */
3557
3558
double GDALRasterBand::GetOffset(int *pbSuccess)
3559
3560
0
{
3561
0
    if (pbSuccess != nullptr)
3562
0
        *pbSuccess = FALSE;
3563
3564
0
    return 0.0;
3565
0
}
3566
3567
/************************************************************************/
3568
/*                        GDALGetRasterOffset()                         */
3569
/************************************************************************/
3570
3571
/**
3572
 * \brief Fetch the raster value offset.
3573
 *
3574
 * @see GDALRasterBand::GetOffset()
3575
 */
3576
3577
double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3578
3579
0
{
3580
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3581
3582
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3583
0
    return poBand->GetOffset(pbSuccess);
3584
0
}
3585
3586
/************************************************************************/
3587
/*                             SetOffset()                              */
3588
/************************************************************************/
3589
3590
/**
3591
 * \fn GDALRasterBand::SetOffset(double)
3592
 * \brief Set scaling offset.
3593
 *
3594
 * Very few formats implement this method.   When not implemented it will
3595
 * issue a CPLE_NotSupported error and return CE_Failure.
3596
 *
3597
 * This method is the same as the C function GDALSetRasterOffset().
3598
 *
3599
 * @param dfNewOffset the new offset.
3600
 *
3601
 * @return CE_None or success or CE_Failure on failure.
3602
 */
3603
3604
/**/
3605
/**/
3606
3607
CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3608
0
{
3609
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3610
0
        ReportError(CE_Failure, CPLE_NotSupported,
3611
0
                    "SetOffset() not supported on this raster band.");
3612
3613
0
    return CE_Failure;
3614
0
}
3615
3616
/************************************************************************/
3617
/*                        GDALSetRasterOffset()                         */
3618
/************************************************************************/
3619
3620
/**
3621
 * \brief Set scaling offset.
3622
 *
3623
 * @see GDALRasterBand::SetOffset()
3624
 */
3625
3626
CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3627
                                       double dfNewOffset)
3628
3629
0
{
3630
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3631
3632
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3633
0
    return poBand->SetOffset(dfNewOffset);
3634
0
}
3635
3636
/************************************************************************/
3637
/*                              GetScale()                              */
3638
/************************************************************************/
3639
3640
/**
3641
 * \brief Fetch the raster value scale.
3642
 *
3643
 * This value (in combination with the GetOffset() value) can be used to
3644
 * transform raw pixel values into the units returned by GetUnitType().
3645
 * For example this might be used to store elevations in GUInt16 bands
3646
 * with a precision of 0.1, and starting from -100.
3647
 *
3648
 * Units value = (raw value * scale) + offset
3649
 *
3650
 * Note that applying scale and offset is of the responsibility of the user,
3651
 * and is not done by methods such as RasterIO() or ReadBlock().
3652
 *
3653
 * For file formats that don't know this intrinsically a value of one
3654
 * is returned.
3655
 *
3656
 * This method is the same as the C function GDALGetRasterScale().
3657
 *
3658
 * @param pbSuccess pointer to a boolean to use to indicate if the
3659
 * returned value is meaningful or not.  May be NULL (default).
3660
 *
3661
 * @return the raster scale.
3662
 */
3663
3664
double GDALRasterBand::GetScale(int *pbSuccess)
3665
3666
0
{
3667
0
    if (pbSuccess != nullptr)
3668
0
        *pbSuccess = FALSE;
3669
3670
0
    return 1.0;
3671
0
}
3672
3673
/************************************************************************/
3674
/*                         GDALGetRasterScale()                         */
3675
/************************************************************************/
3676
3677
/**
3678
 * \brief Fetch the raster value scale.
3679
 *
3680
 * @see GDALRasterBand::GetScale()
3681
 */
3682
3683
double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3684
3685
0
{
3686
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3687
3688
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3689
0
    return poBand->GetScale(pbSuccess);
3690
0
}
3691
3692
/************************************************************************/
3693
/*                              SetScale()                              */
3694
/************************************************************************/
3695
3696
/**
3697
 * \fn GDALRasterBand::SetScale(double)
3698
 * \brief Set scaling ratio.
3699
 *
3700
 * Very few formats implement this method.   When not implemented it will
3701
 * issue a CPLE_NotSupported error and return CE_Failure.
3702
 *
3703
 * This method is the same as the C function GDALSetRasterScale().
3704
 *
3705
 * @param dfNewScale the new scale.
3706
 *
3707
 * @return CE_None or success or CE_Failure on failure.
3708
 */
3709
3710
/**/
3711
/**/
3712
3713
CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3714
3715
0
{
3716
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3717
0
        ReportError(CE_Failure, CPLE_NotSupported,
3718
0
                    "SetScale() not supported on this raster band.");
3719
3720
0
    return CE_Failure;
3721
0
}
3722
3723
/************************************************************************/
3724
/*                        GDALSetRasterScale()                          */
3725
/************************************************************************/
3726
3727
/**
3728
 * \brief Set scaling ratio.
3729
 *
3730
 * @see GDALRasterBand::SetScale()
3731
 */
3732
3733
CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3734
3735
0
{
3736
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3737
3738
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3739
0
    return poBand->SetScale(dfNewOffset);
3740
0
}
3741
3742
/************************************************************************/
3743
/*                            GetUnitType()                             */
3744
/************************************************************************/
3745
3746
/**
3747
 * \brief Return raster unit type.
3748
 *
3749
 * Return a name for the units of this raster's values.  For instance, it
3750
 * might be "m" for an elevation model in meters, or "ft" for feet.  If no
3751
 * units are available, a value of "" will be returned.  The returned string
3752
 * should not be modified, nor freed by the calling application.
3753
 *
3754
 * This method is the same as the C function GDALGetRasterUnitType().
3755
 *
3756
 * @return unit name string.
3757
 */
3758
3759
const char *GDALRasterBand::GetUnitType()
3760
3761
0
{
3762
0
    return "";
3763
0
}
3764
3765
/************************************************************************/
3766
/*                       GDALGetRasterUnitType()                        */
3767
/************************************************************************/
3768
3769
/**
3770
 * \brief Return raster unit type.
3771
 *
3772
 * @see GDALRasterBand::GetUnitType()
3773
 */
3774
3775
const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3776
3777
0
{
3778
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3779
3780
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3781
0
    return poBand->GetUnitType();
3782
0
}
3783
3784
/************************************************************************/
3785
/*                            SetUnitType()                             */
3786
/************************************************************************/
3787
3788
/**
3789
 * \fn GDALRasterBand::SetUnitType(const char*)
3790
 * \brief Set unit type.
3791
 *
3792
 * Set the unit type for a raster band.  Values should be one of
3793
 * "" (the default indicating it is unknown), "m" indicating meters,
3794
 * or "ft" indicating feet, though other nonstandard values are allowed.
3795
 *
3796
 * This method is the same as the C function GDALSetRasterUnitType().
3797
 *
3798
 * @param pszNewValue the new unit type value.
3799
 *
3800
 * @return CE_None on success or CE_Failure if not successful, or
3801
 * unsupported.
3802
 */
3803
3804
/**/
3805
/**/
3806
3807
CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3808
3809
0
{
3810
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3811
0
        ReportError(CE_Failure, CPLE_NotSupported,
3812
0
                    "SetUnitType() not supported on this raster band.");
3813
0
    return CE_Failure;
3814
0
}
3815
3816
/************************************************************************/
3817
/*                       GDALSetRasterUnitType()                        */
3818
/************************************************************************/
3819
3820
/**
3821
 * \brief Set unit type.
3822
 *
3823
 * @see GDALRasterBand::SetUnitType()
3824
 *
3825
 * @since GDAL 1.8.0
3826
 */
3827
3828
CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3829
                                         const char *pszNewValue)
3830
3831
0
{
3832
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3833
3834
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3835
0
    return poBand->SetUnitType(pszNewValue);
3836
0
}
3837
3838
/************************************************************************/
3839
/*                              GetXSize()                              */
3840
/************************************************************************/
3841
3842
/**
3843
 * \brief Fetch XSize of raster.
3844
 *
3845
 * This method is the same as the C function GDALGetRasterBandXSize().
3846
 *
3847
 * @return the width in pixels of this band.
3848
 */
3849
3850
int GDALRasterBand::GetXSize() const
3851
3852
0
{
3853
0
    return nRasterXSize;
3854
0
}
3855
3856
/************************************************************************/
3857
/*                       GDALGetRasterBandXSize()                       */
3858
/************************************************************************/
3859
3860
/**
3861
 * \brief Fetch XSize of raster.
3862
 *
3863
 * @see GDALRasterBand::GetXSize()
3864
 */
3865
3866
int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3867
3868
0
{
3869
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3870
3871
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3872
0
    return poBand->GetXSize();
3873
0
}
3874
3875
/************************************************************************/
3876
/*                              GetYSize()                              */
3877
/************************************************************************/
3878
3879
/**
3880
 * \brief Fetch YSize of raster.
3881
 *
3882
 * This method is the same as the C function GDALGetRasterBandYSize().
3883
 *
3884
 * @return the height in pixels of this band.
3885
 */
3886
3887
int GDALRasterBand::GetYSize() const
3888
3889
0
{
3890
0
    return nRasterYSize;
3891
0
}
3892
3893
/************************************************************************/
3894
/*                       GDALGetRasterBandYSize()                       */
3895
/************************************************************************/
3896
3897
/**
3898
 * \brief Fetch YSize of raster.
3899
 *
3900
 * @see GDALRasterBand::GetYSize()
3901
 */
3902
3903
int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3904
3905
0
{
3906
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3907
3908
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3909
0
    return poBand->GetYSize();
3910
0
}
3911
3912
/************************************************************************/
3913
/*                              GetBand()                               */
3914
/************************************************************************/
3915
3916
/**
3917
 * \brief Fetch the band number.
3918
 *
3919
 * This method returns the band that this GDALRasterBand objects represents
3920
 * within its dataset.  This method may return a value of 0 to indicate
3921
 * GDALRasterBand objects without an apparently relationship to a dataset,
3922
 * such as GDALRasterBands serving as overviews.
3923
 *
3924
 * This method is the same as the C function GDALGetBandNumber().
3925
 *
3926
 * @return band number (1+) or 0 if the band number isn't known.
3927
 */
3928
3929
int GDALRasterBand::GetBand() const
3930
3931
0
{
3932
0
    return nBand;
3933
0
}
3934
3935
/************************************************************************/
3936
/*                         GDALGetBandNumber()                          */
3937
/************************************************************************/
3938
3939
/**
3940
 * \brief Fetch the band number.
3941
 *
3942
 * @see GDALRasterBand::GetBand()
3943
 */
3944
3945
int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3946
3947
0
{
3948
0
    VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3949
3950
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3951
0
    return poBand->GetBand();
3952
0
}
3953
3954
/************************************************************************/
3955
/*                             GetDataset()                             */
3956
/************************************************************************/
3957
3958
/**
3959
 * \brief Fetch the owning dataset handle.
3960
 *
3961
 * Note that some GDALRasterBands are not considered to be a part of a dataset,
3962
 * such as overviews or other "freestanding" bands.
3963
 *
3964
 * This method is the same as the C function GDALGetBandDataset().
3965
 *
3966
 * @return the pointer to the GDALDataset to which this band belongs, or
3967
 * NULL if this cannot be determined.
3968
 */
3969
3970
GDALDataset *GDALRasterBand::GetDataset() const
3971
3972
0
{
3973
0
    return poDS;
3974
0
}
3975
3976
/************************************************************************/
3977
/*                         GDALGetBandDataset()                         */
3978
/************************************************************************/
3979
3980
/**
3981
 * \brief Fetch the owning dataset handle.
3982
 *
3983
 * @see GDALRasterBand::GetDataset()
3984
 */
3985
3986
GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
3987
3988
0
{
3989
0
    VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
3990
3991
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3992
0
    return GDALDataset::ToHandle(poBand->GetDataset());
3993
0
}
3994
3995
/************************************************************************/
3996
/*                        ComputeFloat16NoDataValue()                     */
3997
/************************************************************************/
3998
3999
static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4000
                                             double dfNoDataValue,
4001
                                             int &bGotNoDataValue,
4002
                                             GFloat16 &fNoDataValue,
4003
                                             bool &bGotFloat16NoDataValue)
4004
0
{
4005
0
    if (eDataType == GDT_Float16 && bGotNoDataValue)
4006
0
    {
4007
0
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4008
0
        if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4009
0
        {
4010
0
            fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4011
0
            bGotFloat16NoDataValue = true;
4012
0
            bGotNoDataValue = false;
4013
0
        }
4014
0
    }
4015
0
}
4016
4017
/************************************************************************/
4018
/*                        ComputeFloatNoDataValue()                     */
4019
/************************************************************************/
4020
4021
static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4022
                                           double dfNoDataValue,
4023
                                           int &bGotNoDataValue,
4024
                                           float &fNoDataValue,
4025
                                           bool &bGotFloatNoDataValue)
4026
0
{
4027
0
    if (eDataType == GDT_Float32 && bGotNoDataValue)
4028
0
    {
4029
0
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4030
0
        if (GDALIsValueInRange<float>(dfNoDataValue))
4031
0
        {
4032
0
            fNoDataValue = static_cast<float>(dfNoDataValue);
4033
0
            bGotFloatNoDataValue = true;
4034
0
            bGotNoDataValue = false;
4035
0
        }
4036
0
    }
4037
0
}
4038
4039
/************************************************************************/
4040
/*                        struct GDALNoDataValues                       */
4041
/************************************************************************/
4042
4043
/**
4044
 * \brief No-data-values for all types
4045
 *
4046
 * The functions below pass various no-data-values around. To avoid
4047
 * long argument lists, this struct collects the no-data-values for
4048
 * all types into a single, convenient place.
4049
 **/
4050
4051
struct GDALNoDataValues
4052
{
4053
    int bGotNoDataValue;
4054
    double dfNoDataValue;
4055
4056
    bool bGotFloatNoDataValue;
4057
    float fNoDataValue;
4058
4059
    bool bGotFloat16NoDataValue;
4060
    GFloat16 hfNoDataValue;
4061
4062
    GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4063
0
        : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4064
0
          bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4065
0
          bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4066
0
    {
4067
0
        dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4068
0
        bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4069
4070
0
        ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4071
0
                                fNoDataValue, bGotFloatNoDataValue);
4072
4073
0
        ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4074
0
                                  hfNoDataValue, bGotFloat16NoDataValue);
4075
0
    }
4076
};
4077
4078
/************************************************************************/
4079
/*                            ARE_REAL_EQUAL()                          */
4080
/************************************************************************/
4081
4082
inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4083
0
{
4084
0
    using std::abs;
4085
0
    return dfVal1 == dfVal2 || /* Should cover infinity */
4086
0
           abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4087
0
                                      abs(dfVal1 + dfVal2) * ulp;
4088
0
}
4089
4090
/************************************************************************/
4091
/*                            GetHistogram()                            */
4092
/************************************************************************/
4093
4094
/**
4095
 * \brief Compute raster histogram.
4096
 *
4097
 * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4098
 *
4099
 * For example to compute a simple 256 entry histogram of eight bit data,
4100
 * the following would be suitable.  The unusual bounds are to ensure that
4101
 * bucket boundaries don't fall right on integer values causing possible errors
4102
 * due to rounding after scaling.
4103
\code{.cpp}
4104
    GUIntBig anHistogram[256];
4105
4106
    poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4107
                          GDALDummyProgress, nullptr );
4108
\endcode
4109
 *
4110
 * Note that setting bApproxOK will generally result in a subsampling of the
4111
 * file, and will utilize overviews if available.  It should generally
4112
 * produce a representative histogram for the data that is suitable for use
4113
 * in generating histogram based luts for instance.  Generally bApproxOK is
4114
 * much faster than an exactly computed histogram.
4115
 *
4116
 * This method is the same as the C functions GDALGetRasterHistogram() and
4117
 * GDALGetRasterHistogramEx().
4118
 *
4119
 * @param dfMin the lower bound of the histogram.
4120
 * @param dfMax the upper bound of the histogram.
4121
 * @param nBuckets the number of buckets in panHistogram.
4122
 * @param panHistogram array into which the histogram totals are placed.
4123
 * @param bIncludeOutOfRange if TRUE values below the histogram range will
4124
 * mapped into panHistogram[0], and values above will be mapped into
4125
 * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4126
 * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4127
 * @param pfnProgress function to report progress to completion.
4128
 * @param pProgressData application data to pass to pfnProgress.
4129
 *
4130
 * @return CE_None on success, or CE_Failure if something goes wrong.
4131
 */
4132
4133
CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4134
                                    GUIntBig *panHistogram,
4135
                                    int bIncludeOutOfRange, int bApproxOK,
4136
                                    GDALProgressFunc pfnProgress,
4137
                                    void *pProgressData)
4138
4139
0
{
4140
0
    CPLAssert(nullptr != panHistogram);
4141
4142
0
    if (pfnProgress == nullptr)
4143
0
        pfnProgress = GDALDummyProgress;
4144
4145
    /* -------------------------------------------------------------------- */
4146
    /*      If we have overviews, use them for the histogram.               */
4147
    /* -------------------------------------------------------------------- */
4148
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4149
0
    {
4150
        // FIXME: should we use the most reduced overview here or use some
4151
        // minimum number of samples like GDALRasterBand::ComputeStatistics()
4152
        // does?
4153
0
        GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4154
4155
0
        if (poBestOverview != this)
4156
0
        {
4157
0
            return poBestOverview->GetHistogram(
4158
0
                dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4159
0
                bApproxOK, pfnProgress, pProgressData);
4160
0
        }
4161
0
    }
4162
4163
    /* -------------------------------------------------------------------- */
4164
    /*      Read actual data and build histogram.                           */
4165
    /* -------------------------------------------------------------------- */
4166
0
    if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4167
0
    {
4168
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4169
0
        return CE_Failure;
4170
0
    }
4171
4172
    // Written this way to deal with NaN
4173
0
    if (!(dfMax > dfMin))
4174
0
    {
4175
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4176
0
                    "dfMax should be strictly greater than dfMin");
4177
0
        return CE_Failure;
4178
0
    }
4179
4180
0
    GDALRasterIOExtraArg sExtraArg;
4181
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4182
4183
0
    const double dfScale = nBuckets / (dfMax - dfMin);
4184
0
    if (dfScale == 0 || !std::isfinite(dfScale))
4185
0
    {
4186
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4187
0
                    "dfMin and dfMax should be finite values such that "
4188
0
                    "nBuckets / (dfMax - dfMin) is non-zero");
4189
0
        return CE_Failure;
4190
0
    }
4191
0
    memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4192
4193
0
    GDALNoDataValues sNoDataValues(this, eDataType);
4194
0
    GDALRasterBand *poMaskBand = nullptr;
4195
0
    if (!sNoDataValues.bGotNoDataValue)
4196
0
    {
4197
0
        const int l_nMaskFlags = GetMaskFlags();
4198
0
        if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
4199
0
            GetColorInterpretation() != GCI_AlphaBand)
4200
0
        {
4201
0
            poMaskBand = GetMaskBand();
4202
0
        }
4203
0
    }
4204
4205
0
    bool bSignedByte = false;
4206
0
    if (eDataType == GDT_Byte)
4207
0
    {
4208
0
        EnablePixelTypeSignedByteWarning(false);
4209
0
        const char *pszPixelType =
4210
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4211
0
        EnablePixelTypeSignedByteWarning(true);
4212
0
        bSignedByte =
4213
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4214
0
    }
4215
4216
0
    if (bApproxOK && HasArbitraryOverviews())
4217
0
    {
4218
        /* --------------------------------------------------------------------
4219
         */
4220
        /*      Figure out how much the image should be reduced to get an */
4221
        /*      approximate value. */
4222
        /* --------------------------------------------------------------------
4223
         */
4224
0
        const double dfReduction =
4225
0
            sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4226
0
                 GDALSTAT_APPROX_NUMSAMPLES);
4227
4228
0
        int nXReduced = nRasterXSize;
4229
0
        int nYReduced = nRasterYSize;
4230
0
        if (dfReduction > 1.0)
4231
0
        {
4232
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4233
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4234
4235
            // Catch the case of huge resizing ratios here
4236
0
            if (nXReduced == 0)
4237
0
                nXReduced = 1;
4238
0
            if (nYReduced == 0)
4239
0
                nYReduced = 1;
4240
0
        }
4241
4242
0
        void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4243
0
                                          nXReduced, nYReduced);
4244
0
        if (!pData)
4245
0
            return CE_Failure;
4246
4247
0
        const CPLErr eErr =
4248
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4249
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4250
0
        if (eErr != CE_None)
4251
0
        {
4252
0
            CPLFree(pData);
4253
0
            return eErr;
4254
0
        }
4255
4256
0
        GByte *pabyMaskData = nullptr;
4257
0
        if (poMaskBand)
4258
0
        {
4259
0
            pabyMaskData =
4260
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4261
0
            if (!pabyMaskData)
4262
0
            {
4263
0
                CPLFree(pData);
4264
0
                return CE_Failure;
4265
0
            }
4266
4267
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4268
0
                                     pabyMaskData, nXReduced, nYReduced,
4269
0
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
4270
0
            {
4271
0
                CPLFree(pData);
4272
0
                CPLFree(pabyMaskData);
4273
0
                return CE_Failure;
4274
0
            }
4275
0
        }
4276
4277
        // This isn't the fastest way to do this, but is easier for now.
4278
0
        for (int iY = 0; iY < nYReduced; iY++)
4279
0
        {
4280
0
            for (int iX = 0; iX < nXReduced; iX++)
4281
0
            {
4282
0
                const int iOffset = iX + iY * nXReduced;
4283
0
                double dfValue = 0.0;
4284
4285
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
4286
0
                    continue;
4287
4288
0
                switch (eDataType)
4289
0
                {
4290
0
                    case GDT_Byte:
4291
0
                    {
4292
0
                        if (bSignedByte)
4293
0
                            dfValue =
4294
0
                                static_cast<signed char *>(pData)[iOffset];
4295
0
                        else
4296
0
                            dfValue = static_cast<GByte *>(pData)[iOffset];
4297
0
                        break;
4298
0
                    }
4299
0
                    case GDT_Int8:
4300
0
                        dfValue = static_cast<GInt8 *>(pData)[iOffset];
4301
0
                        break;
4302
0
                    case GDT_UInt16:
4303
0
                        dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4304
0
                        break;
4305
0
                    case GDT_Int16:
4306
0
                        dfValue = static_cast<GInt16 *>(pData)[iOffset];
4307
0
                        break;
4308
0
                    case GDT_UInt32:
4309
0
                        dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4310
0
                        break;
4311
0
                    case GDT_Int32:
4312
0
                        dfValue = static_cast<GInt32 *>(pData)[iOffset];
4313
0
                        break;
4314
0
                    case GDT_UInt64:
4315
0
                        dfValue = static_cast<double>(
4316
0
                            static_cast<GUInt64 *>(pData)[iOffset]);
4317
0
                        break;
4318
0
                    case GDT_Int64:
4319
0
                        dfValue = static_cast<double>(
4320
0
                            static_cast<GInt64 *>(pData)[iOffset]);
4321
0
                        break;
4322
0
                    case GDT_Float16:
4323
0
                    {
4324
0
                        using namespace std;
4325
0
                        const GFloat16 hfValue =
4326
0
                            static_cast<GFloat16 *>(pData)[iOffset];
4327
0
                        if (isnan(hfValue) ||
4328
0
                            (sNoDataValues.bGotFloat16NoDataValue &&
4329
0
                             ARE_REAL_EQUAL(hfValue,
4330
0
                                            sNoDataValues.hfNoDataValue)))
4331
0
                            continue;
4332
0
                        dfValue = hfValue;
4333
0
                        break;
4334
0
                    }
4335
0
                    case GDT_Float32:
4336
0
                    {
4337
0
                        const float fValue =
4338
0
                            static_cast<float *>(pData)[iOffset];
4339
0
                        if (std::isnan(fValue) ||
4340
0
                            (sNoDataValues.bGotFloatNoDataValue &&
4341
0
                             ARE_REAL_EQUAL(fValue,
4342
0
                                            sNoDataValues.fNoDataValue)))
4343
0
                            continue;
4344
0
                        dfValue = fValue;
4345
0
                        break;
4346
0
                    }
4347
0
                    case GDT_Float64:
4348
0
                        dfValue = static_cast<double *>(pData)[iOffset];
4349
0
                        if (std::isnan(dfValue))
4350
0
                            continue;
4351
0
                        break;
4352
0
                    case GDT_CInt16:
4353
0
                    {
4354
0
                        const double dfReal =
4355
0
                            static_cast<GInt16 *>(pData)[iOffset * 2];
4356
0
                        const double dfImag =
4357
0
                            static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4358
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4359
0
                            continue;
4360
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4361
0
                    }
4362
0
                    break;
4363
0
                    case GDT_CInt32:
4364
0
                    {
4365
0
                        const double dfReal =
4366
0
                            static_cast<GInt32 *>(pData)[iOffset * 2];
4367
0
                        const double dfImag =
4368
0
                            static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4369
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4370
0
                            continue;
4371
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4372
0
                    }
4373
0
                    break;
4374
0
                    case GDT_CFloat16:
4375
0
                    {
4376
0
                        const double dfReal =
4377
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2];
4378
0
                        const double dfImag =
4379
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4380
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4381
0
                            continue;
4382
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4383
0
                        break;
4384
0
                    }
4385
0
                    case GDT_CFloat32:
4386
0
                    {
4387
0
                        const double dfReal =
4388
0
                            static_cast<float *>(pData)[iOffset * 2];
4389
0
                        const double dfImag =
4390
0
                            static_cast<float *>(pData)[iOffset * 2 + 1];
4391
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4392
0
                            continue;
4393
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4394
0
                        break;
4395
0
                    }
4396
0
                    case GDT_CFloat64:
4397
0
                    {
4398
0
                        const double dfReal =
4399
0
                            static_cast<double *>(pData)[iOffset * 2];
4400
0
                        const double dfImag =
4401
0
                            static_cast<double *>(pData)[iOffset * 2 + 1];
4402
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4403
0
                            continue;
4404
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4405
0
                        break;
4406
0
                    }
4407
0
                    case GDT_Unknown:
4408
0
                    case GDT_TypeCount:
4409
0
                        CPLAssert(false);
4410
0
                }
4411
4412
0
                if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4413
0
                    sNoDataValues.bGotNoDataValue &&
4414
0
                    ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4415
0
                    continue;
4416
4417
                // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4418
                // finite, the result of the multiplication cannot be NaN
4419
0
                const double dfIndex = floor((dfValue - dfMin) * dfScale);
4420
4421
0
                if (dfIndex < 0)
4422
0
                {
4423
0
                    if (bIncludeOutOfRange)
4424
0
                        panHistogram[0]++;
4425
0
                }
4426
0
                else if (dfIndex >= nBuckets)
4427
0
                {
4428
0
                    if (bIncludeOutOfRange)
4429
0
                        ++panHistogram[nBuckets - 1];
4430
0
                }
4431
0
                else
4432
0
                {
4433
0
                    ++panHistogram[static_cast<int>(dfIndex)];
4434
0
                }
4435
0
            }
4436
0
        }
4437
4438
0
        CPLFree(pData);
4439
0
        CPLFree(pabyMaskData);
4440
0
    }
4441
0
    else  // No arbitrary overviews.
4442
0
    {
4443
0
        if (!InitBlockInfo())
4444
0
            return CE_Failure;
4445
4446
        /* --------------------------------------------------------------------
4447
         */
4448
        /*      Figure out the ratio of blocks we will read to get an */
4449
        /*      approximate value. */
4450
        /* --------------------------------------------------------------------
4451
         */
4452
4453
0
        int nSampleRate = 1;
4454
0
        if (bApproxOK)
4455
0
        {
4456
0
            nSampleRate = static_cast<int>(std::max(
4457
0
                1.0,
4458
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4459
            // We want to avoid probing only the first column of blocks for
4460
            // a square shaped raster, because it is not unlikely that it may
4461
            // be padding only (#6378).
4462
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4463
0
                nSampleRate += 1;
4464
0
        }
4465
4466
0
        GByte *pabyMaskData = nullptr;
4467
0
        if (poMaskBand)
4468
0
        {
4469
0
            pabyMaskData = static_cast<GByte *>(
4470
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4471
0
            if (!pabyMaskData)
4472
0
            {
4473
0
                return CE_Failure;
4474
0
            }
4475
0
        }
4476
4477
        /* --------------------------------------------------------------------
4478
         */
4479
        /*      Read the blocks, and add to histogram. */
4480
        /* --------------------------------------------------------------------
4481
         */
4482
0
        for (GIntBig iSampleBlock = 0;
4483
0
             iSampleBlock <
4484
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4485
0
             iSampleBlock += nSampleRate)
4486
0
        {
4487
0
            if (!pfnProgress(
4488
0
                    static_cast<double>(iSampleBlock) /
4489
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4490
0
                    "Compute Histogram", pProgressData))
4491
0
            {
4492
0
                CPLFree(pabyMaskData);
4493
0
                return CE_Failure;
4494
0
            }
4495
4496
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4497
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4498
4499
0
            GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4500
0
            if (poBlock == nullptr)
4501
0
            {
4502
0
                CPLFree(pabyMaskData);
4503
0
                return CE_Failure;
4504
0
            }
4505
4506
0
            void *pData = poBlock->GetDataRef();
4507
4508
0
            int nXCheck = 0, nYCheck = 0;
4509
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4510
4511
0
            if (poMaskBand &&
4512
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4513
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
4514
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4515
0
                                     0, nBlockXSize, nullptr) != CE_None)
4516
0
            {
4517
0
                CPLFree(pabyMaskData);
4518
0
                poBlock->DropLock();
4519
0
                return CE_Failure;
4520
0
            }
4521
4522
            // this is a special case for a common situation.
4523
0
            if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4524
0
                (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4525
0
                nXCheck == nBlockXSize && nBuckets == 256)
4526
0
            {
4527
0
                const GPtrDiff_t nPixels =
4528
0
                    static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4529
0
                GByte *pabyData = static_cast<GByte *>(pData);
4530
4531
0
                for (GPtrDiff_t i = 0; i < nPixels; i++)
4532
0
                {
4533
0
                    if (pabyMaskData && pabyMaskData[i] == 0)
4534
0
                        continue;
4535
0
                    if (!(sNoDataValues.bGotNoDataValue &&
4536
0
                          (pabyData[i] ==
4537
0
                           static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4538
0
                    {
4539
0
                        panHistogram[pabyData[i]]++;
4540
0
                    }
4541
0
                }
4542
4543
0
                poBlock->DropLock();
4544
0
                continue;  // To next sample block.
4545
0
            }
4546
4547
            // This isn't the fastest way to do this, but is easier for now.
4548
0
            for (int iY = 0; iY < nYCheck; iY++)
4549
0
            {
4550
0
                for (int iX = 0; iX < nXCheck; iX++)
4551
0
                {
4552
0
                    const GPtrDiff_t iOffset =
4553
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4554
4555
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
4556
0
                        continue;
4557
4558
0
                    double dfValue = 0.0;
4559
4560
0
                    switch (eDataType)
4561
0
                    {
4562
0
                        case GDT_Byte:
4563
0
                        {
4564
0
                            if (bSignedByte)
4565
0
                                dfValue =
4566
0
                                    static_cast<signed char *>(pData)[iOffset];
4567
0
                            else
4568
0
                                dfValue = static_cast<GByte *>(pData)[iOffset];
4569
0
                            break;
4570
0
                        }
4571
0
                        case GDT_Int8:
4572
0
                            dfValue = static_cast<GInt8 *>(pData)[iOffset];
4573
0
                            break;
4574
0
                        case GDT_UInt16:
4575
0
                            dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4576
0
                            break;
4577
0
                        case GDT_Int16:
4578
0
                            dfValue = static_cast<GInt16 *>(pData)[iOffset];
4579
0
                            break;
4580
0
                        case GDT_UInt32:
4581
0
                            dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4582
0
                            break;
4583
0
                        case GDT_Int32:
4584
0
                            dfValue = static_cast<GInt32 *>(pData)[iOffset];
4585
0
                            break;
4586
0
                        case GDT_UInt64:
4587
0
                            dfValue = static_cast<double>(
4588
0
                                static_cast<GUInt64 *>(pData)[iOffset]);
4589
0
                            break;
4590
0
                        case GDT_Int64:
4591
0
                            dfValue = static_cast<double>(
4592
0
                                static_cast<GInt64 *>(pData)[iOffset]);
4593
0
                            break;
4594
0
                        case GDT_Float16:
4595
0
                        {
4596
0
                            using namespace std;
4597
0
                            const GFloat16 hfValue =
4598
0
                                static_cast<GFloat16 *>(pData)[iOffset];
4599
0
                            if (isnan(hfValue) ||
4600
0
                                (sNoDataValues.bGotFloat16NoDataValue &&
4601
0
                                 ARE_REAL_EQUAL(hfValue,
4602
0
                                                sNoDataValues.hfNoDataValue)))
4603
0
                                continue;
4604
0
                            dfValue = hfValue;
4605
0
                            break;
4606
0
                        }
4607
0
                        case GDT_Float32:
4608
0
                        {
4609
0
                            const float fValue =
4610
0
                                static_cast<float *>(pData)[iOffset];
4611
0
                            if (std::isnan(fValue) ||
4612
0
                                (sNoDataValues.bGotFloatNoDataValue &&
4613
0
                                 ARE_REAL_EQUAL(fValue,
4614
0
                                                sNoDataValues.fNoDataValue)))
4615
0
                                continue;
4616
0
                            dfValue = fValue;
4617
0
                            break;
4618
0
                        }
4619
0
                        case GDT_Float64:
4620
0
                            dfValue = static_cast<double *>(pData)[iOffset];
4621
0
                            if (std::isnan(dfValue))
4622
0
                                continue;
4623
0
                            break;
4624
0
                        case GDT_CInt16:
4625
0
                        {
4626
0
                            double dfReal =
4627
0
                                static_cast<GInt16 *>(pData)[iOffset * 2];
4628
0
                            double dfImag =
4629
0
                                static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4630
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4631
0
                            break;
4632
0
                        }
4633
0
                        case GDT_CInt32:
4634
0
                        {
4635
0
                            double dfReal =
4636
0
                                static_cast<GInt32 *>(pData)[iOffset * 2];
4637
0
                            double dfImag =
4638
0
                                static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4639
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4640
0
                            break;
4641
0
                        }
4642
0
                        case GDT_CFloat16:
4643
0
                        {
4644
0
                            double dfReal =
4645
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2];
4646
0
                            double dfImag =
4647
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4648
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4649
0
                                continue;
4650
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4651
0
                            break;
4652
0
                        }
4653
0
                        case GDT_CFloat32:
4654
0
                        {
4655
0
                            double dfReal =
4656
0
                                static_cast<float *>(pData)[iOffset * 2];
4657
0
                            double dfImag =
4658
0
                                static_cast<float *>(pData)[iOffset * 2 + 1];
4659
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4660
0
                                continue;
4661
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4662
0
                            break;
4663
0
                        }
4664
0
                        case GDT_CFloat64:
4665
0
                        {
4666
0
                            double dfReal =
4667
0
                                static_cast<double *>(pData)[iOffset * 2];
4668
0
                            double dfImag =
4669
0
                                static_cast<double *>(pData)[iOffset * 2 + 1];
4670
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4671
0
                                continue;
4672
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4673
0
                            break;
4674
0
                        }
4675
0
                        case GDT_Unknown:
4676
0
                        case GDT_TypeCount:
4677
0
                            CPLAssert(false);
4678
0
                            CPLFree(pabyMaskData);
4679
0
                            return CE_Failure;
4680
0
                    }
4681
4682
0
                    if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4683
0
                        sNoDataValues.bGotNoDataValue &&
4684
0
                        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4685
0
                        continue;
4686
4687
                    // Given that dfValue and dfMin are not NaN, and dfScale > 0
4688
                    // and finite, the result of the multiplication cannot be
4689
                    // NaN
4690
0
                    const double dfIndex = floor((dfValue - dfMin) * dfScale);
4691
4692
0
                    if (dfIndex < 0)
4693
0
                    {
4694
0
                        if (bIncludeOutOfRange)
4695
0
                            panHistogram[0]++;
4696
0
                    }
4697
0
                    else if (dfIndex >= nBuckets)
4698
0
                    {
4699
0
                        if (bIncludeOutOfRange)
4700
0
                            ++panHistogram[nBuckets - 1];
4701
0
                    }
4702
0
                    else
4703
0
                    {
4704
0
                        ++panHistogram[static_cast<int>(dfIndex)];
4705
0
                    }
4706
0
                }
4707
0
            }
4708
4709
0
            poBlock->DropLock();
4710
0
        }
4711
4712
0
        CPLFree(pabyMaskData);
4713
0
    }
4714
4715
0
    pfnProgress(1.0, "Compute Histogram", pProgressData);
4716
4717
0
    return CE_None;
4718
0
}
4719
4720
/************************************************************************/
4721
/*                       GDALGetRasterHistogram()                       */
4722
/************************************************************************/
4723
4724
/**
4725
 * \brief Compute raster histogram.
4726
 *
4727
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4728
 * exceeding 2 billion.
4729
 *
4730
 * @see GDALRasterBand::GetHistogram()
4731
 * @see GDALGetRasterHistogramEx()
4732
 */
4733
4734
CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4735
                                          double dfMax, int nBuckets,
4736
                                          int *panHistogram,
4737
                                          int bIncludeOutOfRange, int bApproxOK,
4738
                                          GDALProgressFunc pfnProgress,
4739
                                          void *pProgressData)
4740
4741
0
{
4742
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4743
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4744
4745
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4746
4747
0
    GUIntBig *panHistogramTemp =
4748
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4749
0
    if (panHistogramTemp == nullptr)
4750
0
    {
4751
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4752
0
                            "Out of memory in GDALGetRasterHistogram().");
4753
0
        return CE_Failure;
4754
0
    }
4755
4756
0
    CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4757
0
                                       bIncludeOutOfRange, bApproxOK,
4758
0
                                       pfnProgress, pProgressData);
4759
4760
0
    if (eErr == CE_None)
4761
0
    {
4762
0
        for (int i = 0; i < nBuckets; i++)
4763
0
        {
4764
0
            if (panHistogramTemp[i] > INT_MAX)
4765
0
            {
4766
0
                CPLError(CE_Warning, CPLE_AppDefined,
4767
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
4768
0
                         " exceeds maximum 32 bit value",
4769
0
                         i, panHistogramTemp[i]);
4770
0
                panHistogram[i] = INT_MAX;
4771
0
            }
4772
0
            else
4773
0
            {
4774
0
                panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4775
0
            }
4776
0
        }
4777
0
    }
4778
4779
0
    CPLFree(panHistogramTemp);
4780
4781
0
    return eErr;
4782
0
}
4783
4784
/************************************************************************/
4785
/*                      GDALGetRasterHistogramEx()                      */
4786
/************************************************************************/
4787
4788
/**
4789
 * \brief Compute raster histogram.
4790
 *
4791
 * @see GDALRasterBand::GetHistogram()
4792
 *
4793
 * @since GDAL 2.0
4794
 */
4795
4796
CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4797
    GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4798
    GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4799
    GDALProgressFunc pfnProgress, void *pProgressData)
4800
4801
0
{
4802
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4803
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4804
4805
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4806
4807
0
    return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4808
0
                                bIncludeOutOfRange, bApproxOK, pfnProgress,
4809
0
                                pProgressData);
4810
0
}
4811
4812
/************************************************************************/
4813
/*                        GetDefaultHistogram()                         */
4814
/************************************************************************/
4815
4816
/**
4817
 * \brief Fetch default raster histogram.
4818
 *
4819
 * The default method in GDALRasterBand will compute a default histogram. This
4820
 * method is overridden by derived classes (such as GDALPamRasterBand,
4821
 * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4822
 * stored histogram.
4823
 *
4824
 * This method is the same as the C functions GDALGetDefaultHistogram() and
4825
 * GDALGetDefaultHistogramEx().
4826
 *
4827
 * @param pdfMin pointer to double value that will contain the lower bound of
4828
 * the histogram.
4829
 * @param pdfMax pointer to double value that will contain the upper bound of
4830
 * the histogram.
4831
 * @param pnBuckets pointer to int value that will contain the number of buckets
4832
 * in *ppanHistogram.
4833
 * @param ppanHistogram pointer to array into which the histogram totals are
4834
 * placed. To be freed with VSIFree
4835
 * @param bForce TRUE to force the computation. If FALSE and no default
4836
 * histogram is available, the method will return CE_Warning
4837
 * @param pfnProgress function to report progress to completion.
4838
 * @param pProgressData application data to pass to pfnProgress.
4839
 *
4840
 * @return CE_None on success, CE_Failure if something goes wrong, or
4841
 * CE_Warning if no default histogram is available.
4842
 */
4843
4844
CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4845
                                           int *pnBuckets,
4846
                                           GUIntBig **ppanHistogram, int bForce,
4847
                                           GDALProgressFunc pfnProgress,
4848
                                           void *pProgressData)
4849
4850
0
{
4851
0
    CPLAssert(nullptr != pnBuckets);
4852
0
    CPLAssert(nullptr != ppanHistogram);
4853
0
    CPLAssert(nullptr != pdfMin);
4854
0
    CPLAssert(nullptr != pdfMax);
4855
4856
0
    *pnBuckets = 0;
4857
0
    *ppanHistogram = nullptr;
4858
4859
0
    if (!bForce)
4860
0
        return CE_Warning;
4861
4862
0
    const int nBuckets = 256;
4863
4864
0
    bool bSignedByte = false;
4865
0
    if (eDataType == GDT_Byte)
4866
0
    {
4867
0
        EnablePixelTypeSignedByteWarning(false);
4868
0
        const char *pszPixelType =
4869
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4870
0
        EnablePixelTypeSignedByteWarning(true);
4871
0
        bSignedByte =
4872
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4873
0
    }
4874
4875
0
    if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4876
0
    {
4877
0
        *pdfMin = -0.5;
4878
0
        *pdfMax = 255.5;
4879
0
    }
4880
0
    else
4881
0
    {
4882
4883
0
        const CPLErr eErr =
4884
0
            GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4885
0
        const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4886
0
        *pdfMin -= dfHalfBucket;
4887
0
        *pdfMax += dfHalfBucket;
4888
4889
0
        if (eErr != CE_None)
4890
0
            return eErr;
4891
0
    }
4892
4893
0
    *ppanHistogram =
4894
0
        static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4895
0
    if (*ppanHistogram == nullptr)
4896
0
    {
4897
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
4898
0
                    "Out of memory in InitBlockInfo().");
4899
0
        return CE_Failure;
4900
0
    }
4901
4902
0
    *pnBuckets = nBuckets;
4903
0
    CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4904
0
                               TRUE, FALSE, pfnProgress, pProgressData);
4905
0
    if (eErr != CE_None)
4906
0
    {
4907
0
        *pnBuckets = 0;
4908
0
    }
4909
0
    return eErr;
4910
0
}
4911
4912
/************************************************************************/
4913
/*                      GDALGetDefaultHistogram()                       */
4914
/************************************************************************/
4915
4916
/**
4917
 * \brief Fetch default raster histogram.
4918
 *
4919
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4920
 * exceeding 2 billion.
4921
 *
4922
 * @see GDALRasterBand::GDALGetDefaultHistogram()
4923
 * @see GDALGetRasterHistogramEx()
4924
 */
4925
4926
CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4927
                                           double *pdfMin, double *pdfMax,
4928
                                           int *pnBuckets, int **ppanHistogram,
4929
                                           int bForce,
4930
                                           GDALProgressFunc pfnProgress,
4931
                                           void *pProgressData)
4932
4933
0
{
4934
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4935
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4936
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4937
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4938
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4939
4940
0
    GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4941
0
    GUIntBig *panHistogramTemp = nullptr;
4942
0
    CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
4943
0
                                              &panHistogramTemp, bForce,
4944
0
                                              pfnProgress, pProgressData);
4945
0
    if (eErr == CE_None)
4946
0
    {
4947
0
        const int nBuckets = *pnBuckets;
4948
0
        *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
4949
0
        if (*ppanHistogram == nullptr)
4950
0
        {
4951
0
            poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4952
0
                                "Out of memory in GDALGetDefaultHistogram().");
4953
0
            VSIFree(panHistogramTemp);
4954
0
            return CE_Failure;
4955
0
        }
4956
4957
0
        for (int i = 0; i < nBuckets; ++i)
4958
0
        {
4959
0
            if (panHistogramTemp[i] > INT_MAX)
4960
0
            {
4961
0
                CPLError(CE_Warning, CPLE_AppDefined,
4962
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
4963
0
                         " exceeds maximum 32 bit value",
4964
0
                         i, panHistogramTemp[i]);
4965
0
                (*ppanHistogram)[i] = INT_MAX;
4966
0
            }
4967
0
            else
4968
0
            {
4969
0
                (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
4970
0
            }
4971
0
        }
4972
4973
0
        CPLFree(panHistogramTemp);
4974
0
    }
4975
0
    else
4976
0
    {
4977
0
        *ppanHistogram = nullptr;
4978
0
    }
4979
4980
0
    return eErr;
4981
0
}
4982
4983
/************************************************************************/
4984
/*                      GDALGetDefaultHistogramEx()                     */
4985
/************************************************************************/
4986
4987
/**
4988
 * \brief Fetch default raster histogram.
4989
 *
4990
 * @see GDALRasterBand::GetDefaultHistogram()
4991
 *
4992
 * @since GDAL 2.0
4993
 */
4994
4995
CPLErr CPL_STDCALL
4996
GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
4997
                          int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
4998
                          GDALProgressFunc pfnProgress, void *pProgressData)
4999
5000
0
{
5001
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5002
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5003
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5004
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5005
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5006
5007
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5008
0
    return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5009
0
                                       bForce, pfnProgress, pProgressData);
5010
0
}
5011
5012
/************************************************************************/
5013
/*                             AdviseRead()                             */
5014
/************************************************************************/
5015
5016
/**
5017
 * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5018
 * \brief Advise driver of upcoming read requests.
5019
 *
5020
 * Some GDAL drivers operate more efficiently if they know in advance what
5021
 * set of upcoming read requests will be made.  The AdviseRead() method allows
5022
 * an application to notify the driver of the region of interest,
5023
 * and at what resolution the region will be read.
5024
 *
5025
 * Many drivers just ignore the AdviseRead() call, but it can dramatically
5026
 * accelerate access via some drivers.
5027
 *
5028
 * Depending on call paths, drivers might receive several calls to
5029
 * AdviseRead() with the same parameters.
5030
 *
5031
 * @param nXOff The pixel offset to the top left corner of the region
5032
 * of the band to be accessed.  This would be zero to start from the left side.
5033
 *
5034
 * @param nYOff The line offset to the top left corner of the region
5035
 * of the band to be accessed.  This would be zero to start from the top.
5036
 *
5037
 * @param nXSize The width of the region of the band to be accessed in pixels.
5038
 *
5039
 * @param nYSize The height of the region of the band to be accessed in lines.
5040
 *
5041
 * @param nBufXSize the width of the buffer image into which the desired region
5042
 * is to be read, or from which it is to be written.
5043
 *
5044
 * @param nBufYSize the height of the buffer image into which the desired
5045
 * region is to be read, or from which it is to be written.
5046
 *
5047
 * @param eBufType the type of the pixel values in the pData data buffer.  The
5048
 * pixel values will automatically be translated to/from the GDALRasterBand
5049
 * data type as needed.
5050
 *
5051
 * @param papszOptions a list of name=value strings with special control
5052
 * options.  Normally this is NULL.
5053
 *
5054
 * @return CE_Failure if the request is invalid and CE_None if it works or
5055
 * is ignored.
5056
 */
5057
5058
/**/
5059
/**/
5060
5061
CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5062
                                  int /*nYSize*/, int /*nBufXSize*/,
5063
                                  int /*nBufYSize*/, GDALDataType /*eBufType*/,
5064
                                  char ** /*papszOptions*/)
5065
0
{
5066
0
    return CE_None;
5067
0
}
5068
5069
/************************************************************************/
5070
/*                        GDALRasterAdviseRead()                        */
5071
/************************************************************************/
5072
5073
/**
5074
 * \brief Advise driver of upcoming read requests.
5075
 *
5076
 * @see GDALRasterBand::AdviseRead()
5077
 */
5078
5079
CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5080
                                        int nYOff, int nXSize, int nYSize,
5081
                                        int nBufXSize, int nBufYSize,
5082
                                        GDALDataType eDT,
5083
                                        CSLConstList papszOptions)
5084
5085
0
{
5086
0
    VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5087
5088
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5089
0
    return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5090
0
                              nBufYSize, eDT,
5091
0
                              const_cast<char **>(papszOptions));
5092
0
}
5093
5094
/************************************************************************/
5095
/*                           GetStatistics()                            */
5096
/************************************************************************/
5097
5098
/**
5099
 * \brief Fetch image statistics.
5100
 *
5101
 * Returns the minimum, maximum, mean and standard deviation of all
5102
 * pixel values in this band.  If approximate statistics are sufficient,
5103
 * the bApproxOK flag can be set to true in which case overviews, or a
5104
 * subset of image tiles may be used in computing the statistics.
5105
 *
5106
 * If bForce is FALSE results will only be returned if it can be done
5107
 * quickly (i.e. without scanning the image, typically by using pre-existing
5108
 * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5109
 * returned efficiently, the method will return CE_Warning but no warning will
5110
 * be issued. This is a non-standard use of the CE_Warning return value
5111
 * to indicate "nothing done".
5112
 *
5113
 * If bForce is TRUE, and results are quickly available without scanning the
5114
 * image, they will be used. If bForce is TRUE and results are not quickly
5115
 * available, GetStatistics() forwards the computation to ComputeStatistics(),
5116
 * which will scan the image.
5117
 *
5118
 * To always force recomputation of statistics, use ComputeStatistics() instead
5119
 * of this method.
5120
 *
5121
 * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5122
 * will generally cache statistics in the .pam file allowing fast fetch
5123
 * after the first request.
5124
 *
5125
 * This method is the same as the C function GDALGetRasterStatistics().
5126
 *
5127
 * @param bApproxOK If TRUE statistics may be computed based on overviews
5128
 * or a subset of all tiles.
5129
 *
5130
 * @param bForce If FALSE statistics will only be returned if it can
5131
 * be done without rescanning the image. If TRUE, statistics computation will
5132
 * be forced if pre-existing values are not quickly available.
5133
 *
5134
 * @param pdfMin Location into which to load image minimum (may be NULL).
5135
 *
5136
 * @param pdfMax Location into which to load image maximum (may be NULL).-
5137
 *
5138
 * @param pdfMean Location into which to load image mean (may be NULL).
5139
 *
5140
 * @param pdfStdDev Location into which to load image standard deviation
5141
 * (may be NULL).
5142
 *
5143
 * @return CE_None on success, CE_Warning if no values returned,
5144
 * CE_Failure if an error occurs.
5145
 */
5146
5147
CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5148
                                     double *pdfMax, double *pdfMean,
5149
                                     double *pdfStdDev)
5150
5151
0
{
5152
    /* -------------------------------------------------------------------- */
5153
    /*      Do we already have metadata items for the requested values?     */
5154
    /* -------------------------------------------------------------------- */
5155
0
    if ((pdfMin == nullptr ||
5156
0
         GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5157
0
        (pdfMax == nullptr ||
5158
0
         GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5159
0
        (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5160
0
        (pdfStdDev == nullptr ||
5161
0
         GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5162
0
    {
5163
0
        if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5164
0
        {
5165
0
            if (pdfMin != nullptr)
5166
0
                *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5167
0
            if (pdfMax != nullptr)
5168
0
                *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5169
0
            if (pdfMean != nullptr)
5170
0
                *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5171
0
            if (pdfStdDev != nullptr)
5172
0
                *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5173
5174
0
            return CE_None;
5175
0
        }
5176
0
    }
5177
5178
    /* -------------------------------------------------------------------- */
5179
    /*      Does the driver already know the min/max?                       */
5180
    /* -------------------------------------------------------------------- */
5181
0
    if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5182
0
    {
5183
0
        int bSuccessMin = FALSE;
5184
0
        int bSuccessMax = FALSE;
5185
5186
0
        const double dfMin = GetMinimum(&bSuccessMin);
5187
0
        const double dfMax = GetMaximum(&bSuccessMax);
5188
5189
0
        if (bSuccessMin && bSuccessMax)
5190
0
        {
5191
0
            if (pdfMin != nullptr)
5192
0
                *pdfMin = dfMin;
5193
0
            if (pdfMax != nullptr)
5194
0
                *pdfMax = dfMax;
5195
0
            return CE_None;
5196
0
        }
5197
0
    }
5198
5199
    /* -------------------------------------------------------------------- */
5200
    /*      Either return without results, or force computation.            */
5201
    /* -------------------------------------------------------------------- */
5202
0
    if (!bForce)
5203
0
        return CE_Warning;
5204
0
    else
5205
0
        return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5206
0
                                 GDALDummyProgress, nullptr);
5207
0
}
5208
5209
/************************************************************************/
5210
/*                      GDALGetRasterStatistics()                       */
5211
/************************************************************************/
5212
5213
/**
5214
 * \brief Fetch image statistics.
5215
 *
5216
 * @see GDALRasterBand::GetStatistics()
5217
 */
5218
5219
CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5220
                                           int bForce, double *pdfMin,
5221
                                           double *pdfMax, double *pdfMean,
5222
                                           double *pdfStdDev)
5223
5224
0
{
5225
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5226
5227
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5228
0
    return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5229
0
                                 pdfStdDev);
5230
0
}
5231
5232
/************************************************************************/
5233
/*                         GDALUInt128                                  */
5234
/************************************************************************/
5235
5236
#ifdef HAVE_UINT128_T
5237
class GDALUInt128
5238
{
5239
    __uint128_t val;
5240
5241
0
    explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5242
0
    {
5243
0
    }
5244
5245
  public:
5246
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5247
0
    {
5248
        // Evaluates to just a single mul on x86_64
5249
0
        return GDALUInt128(static_cast<__uint128_t>(first) * second);
5250
0
    }
5251
5252
    GDALUInt128 operator-(const GDALUInt128 &other) const
5253
0
    {
5254
0
        return GDALUInt128(val - other.val);
5255
0
    }
5256
5257
    operator double() const
5258
0
    {
5259
0
        return static_cast<double>(val);
5260
0
    }
5261
};
5262
#else
5263
5264
#if defined(_MSC_VER) && defined(_M_X64)
5265
#include <intrin.h>
5266
#endif
5267
5268
class GDALUInt128
5269
{
5270
    GUIntBig low, high;
5271
5272
    GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5273
    {
5274
    }
5275
5276
  public:
5277
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5278
    {
5279
#if defined(_MSC_VER) && defined(_M_X64)
5280
        GUIntBig highRes;
5281
        GUIntBig lowRes = _umul128(first, second, &highRes);
5282
        return GDALUInt128(lowRes, highRes);
5283
#else
5284
        const GUInt32 firstLow = static_cast<GUInt32>(first);
5285
        const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5286
        const GUInt32 secondLow = static_cast<GUInt32>(second);
5287
        const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5288
        GUIntBig highRes = 0;
5289
        const GUIntBig firstLowSecondHigh =
5290
            static_cast<GUIntBig>(firstLow) * secondHigh;
5291
        const GUIntBig firstHighSecondLow =
5292
            static_cast<GUIntBig>(firstHigh) * secondLow;
5293
        const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5294
        if (middleTerm < firstLowSecondHigh)  // check for overflow
5295
            highRes += static_cast<GUIntBig>(1) << 32;
5296
        const GUIntBig firstLowSecondLow =
5297
            static_cast<GUIntBig>(firstLow) * secondLow;
5298
        GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5299
        if (lowRes < firstLowSecondLow)  // check for overflow
5300
            highRes++;
5301
        highRes +=
5302
            (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5303
        return GDALUInt128(lowRes, highRes);
5304
#endif
5305
    }
5306
5307
    GDALUInt128 operator-(const GDALUInt128 &other) const
5308
    {
5309
        GUIntBig highRes = high - other.high;
5310
        GUIntBig lowRes = low - other.low;
5311
        if (lowRes > low)  // check for underflow
5312
            --highRes;
5313
        return GDALUInt128(lowRes, highRes);
5314
    }
5315
5316
    operator double() const
5317
    {
5318
        const double twoPow64 = 18446744073709551616.0;
5319
        return high * twoPow64 + low;
5320
    }
5321
};
5322
#endif
5323
5324
/************************************************************************/
5325
/*                    ComputeStatisticsInternal()                       */
5326
/************************************************************************/
5327
5328
// Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5329
// not needed.
5330
0
#define static_cast_for_coverity_scan static_cast
5331
5332
// The rationale for below optimizations is detailed in statistics.txt
5333
5334
// Use with T = GByte or GUInt16 only !
5335
template <class T, bool COMPUTE_OTHER_STATS>
5336
struct ComputeStatisticsInternalGeneric
5337
{
5338
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5339
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5340
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5341
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5342
0
    {
5343
0
        static_assert(std::is_same<T, GByte>::value ||
5344
0
                          std::is_same<T, GUInt16>::value,
5345
0
                      "bad type for T");
5346
0
        if (bHasNoData)
5347
0
        {
5348
            // General case
5349
0
            for (int iY = 0; iY < nYCheck; iY++)
5350
0
            {
5351
0
                for (int iX = 0; iX < nXCheck; iX++)
5352
0
                {
5353
0
                    const GPtrDiff_t iOffset =
5354
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5355
0
                    const GUInt32 nValue = pData[iOffset];
5356
0
                    if (nValue == nNoDataValue)
5357
0
                        continue;
5358
0
                    if (nValue < nMin)
5359
0
                        nMin = nValue;
5360
0
                    if (nValue > nMax)
5361
0
                        nMax = nValue;
5362
                    if constexpr (COMPUTE_OTHER_STATS)
5363
0
                    {
5364
0
                        nValidCount++;
5365
0
                        nSum += nValue;
5366
0
                        nSumSquare +=
5367
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5368
0
                            nValue;
5369
0
                    }
5370
0
                }
5371
0
            }
5372
            if constexpr (COMPUTE_OTHER_STATS)
5373
0
            {
5374
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5375
0
            }
5376
0
        }
5377
0
        else if (nMin == std::numeric_limits<T>::lowest() &&
5378
0
                 nMax == std::numeric_limits<T>::max())
5379
0
        {
5380
            if constexpr (COMPUTE_OTHER_STATS)
5381
0
            {
5382
                // Optimization when there is no nodata and we know we have already
5383
                // reached the min and max
5384
0
                for (int iY = 0; iY < nYCheck; iY++)
5385
0
                {
5386
0
                    int iX;
5387
0
                    for (iX = 0; iX + 3 < nXCheck; iX += 4)
5388
0
                    {
5389
0
                        const GPtrDiff_t iOffset =
5390
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5391
0
                        const GUIntBig nValue = pData[iOffset];
5392
0
                        const GUIntBig nValue2 = pData[iOffset + 1];
5393
0
                        const GUIntBig nValue3 = pData[iOffset + 2];
5394
0
                        const GUIntBig nValue4 = pData[iOffset + 3];
5395
0
                        nSum += nValue;
5396
0
                        nSumSquare += nValue * nValue;
5397
0
                        nSum += nValue2;
5398
0
                        nSumSquare += nValue2 * nValue2;
5399
0
                        nSum += nValue3;
5400
0
                        nSumSquare += nValue3 * nValue3;
5401
0
                        nSum += nValue4;
5402
0
                        nSumSquare += nValue4 * nValue4;
5403
0
                    }
5404
0
                    for (; iX < nXCheck; ++iX)
5405
0
                    {
5406
0
                        const GPtrDiff_t iOffset =
5407
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5408
0
                        const GUIntBig nValue = pData[iOffset];
5409
0
                        nSum += nValue;
5410
0
                        nSumSquare += nValue * nValue;
5411
0
                    }
5412
0
                }
5413
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5414
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5415
0
            }
5416
0
        }
5417
0
        else
5418
0
        {
5419
0
            for (int iY = 0; iY < nYCheck; iY++)
5420
0
            {
5421
0
                int iX;
5422
0
                for (iX = 0; iX + 1 < nXCheck; iX += 2)
5423
0
                {
5424
0
                    const GPtrDiff_t iOffset =
5425
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5426
0
                    const GUInt32 nValue = pData[iOffset];
5427
0
                    const GUInt32 nValue2 = pData[iOffset + 1];
5428
0
                    if (nValue < nValue2)
5429
0
                    {
5430
0
                        if (nValue < nMin)
5431
0
                            nMin = nValue;
5432
0
                        if (nValue2 > nMax)
5433
0
                            nMax = nValue2;
5434
0
                    }
5435
0
                    else
5436
0
                    {
5437
0
                        if (nValue2 < nMin)
5438
0
                            nMin = nValue2;
5439
0
                        if (nValue > nMax)
5440
0
                            nMax = nValue;
5441
0
                    }
5442
                    if constexpr (COMPUTE_OTHER_STATS)
5443
0
                    {
5444
0
                        nSum += nValue;
5445
0
                        nSumSquare +=
5446
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5447
0
                            nValue;
5448
0
                        nSum += nValue2;
5449
0
                        nSumSquare +=
5450
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5451
0
                            nValue2;
5452
0
                    }
5453
0
                }
5454
0
                if (iX < nXCheck)
5455
0
                {
5456
0
                    const GPtrDiff_t iOffset =
5457
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5458
0
                    const GUInt32 nValue = pData[iOffset];
5459
0
                    if (nValue < nMin)
5460
0
                        nMin = nValue;
5461
0
                    if (nValue > nMax)
5462
0
                        nMax = nValue;
5463
0
                    if (COMPUTE_OTHER_STATS)
5464
0
                    {
5465
0
                        nSum += nValue;
5466
0
                        nSumSquare +=
5467
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5468
0
                            nValue;
5469
0
                    }
5470
0
                }
5471
0
            }
5472
            if constexpr (COMPUTE_OTHER_STATS)
5473
0
            {
5474
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5475
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5476
0
            }
5477
0
        }
5478
0
    }
Unexecuted instantiation: ComputeStatisticsInternalGeneric<unsigned short, false>::f(int, int, int, unsigned short const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: ComputeStatisticsInternalGeneric<unsigned short, true>::f(int, int, int, unsigned short const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
5479
};
5480
5481
// Specialization for Byte that is mostly 32 bit friendly as it avoids
5482
// using 64bit accumulators in internal loops. This also slightly helps in
5483
// 64bit mode.
5484
template <bool COMPUTE_OTHER_STATS>
5485
struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5486
{
5487
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5488
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5489
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5490
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5491
0
    {
5492
0
        int nOuterLoops = nXCheck / 65536;
5493
0
        if (nXCheck % 65536)
5494
0
            nOuterLoops++;
5495
5496
0
        if (bHasNoData)
5497
0
        {
5498
            // General case
5499
0
            for (int iY = 0; iY < nYCheck; iY++)
5500
0
            {
5501
0
                int iX = 0;
5502
0
                for (int k = 0; k < nOuterLoops; k++)
5503
0
                {
5504
0
                    int iMax = iX + 65536;
5505
0
                    if (iMax > nXCheck)
5506
0
                        iMax = nXCheck;
5507
0
                    GUInt32 nSum32bit = 0;
5508
0
                    GUInt32 nSumSquare32bit = 0;
5509
0
                    GUInt32 nValidCount32bit = 0;
5510
0
                    GUInt32 nSampleCount32bit = 0;
5511
0
                    for (; iX < iMax; iX++)
5512
0
                    {
5513
0
                        const GPtrDiff_t iOffset =
5514
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5515
0
                        const GUInt32 nValue = pData[iOffset];
5516
5517
0
                        nSampleCount32bit++;
5518
0
                        if (nValue == nNoDataValue)
5519
0
                            continue;
5520
0
                        if (nValue < nMin)
5521
0
                            nMin = nValue;
5522
0
                        if (nValue > nMax)
5523
0
                            nMax = nValue;
5524
                        if constexpr (COMPUTE_OTHER_STATS)
5525
0
                        {
5526
0
                            nValidCount32bit++;
5527
0
                            nSum32bit += nValue;
5528
0
                            nSumSquare32bit += nValue * nValue;
5529
0
                        }
5530
0
                    }
5531
                    if constexpr (COMPUTE_OTHER_STATS)
5532
0
                    {
5533
0
                        nSampleCount += nSampleCount32bit;
5534
0
                        nValidCount += nValidCount32bit;
5535
0
                        nSum += nSum32bit;
5536
0
                        nSumSquare += nSumSquare32bit;
5537
0
                    }
5538
0
                }
5539
0
            }
5540
0
        }
5541
0
        else if (nMin == 0 && nMax == 255)
5542
0
        {
5543
            if constexpr (COMPUTE_OTHER_STATS)
5544
0
            {
5545
                // Optimization when there is no nodata and we know we have already
5546
                // reached the min and max
5547
0
                for (int iY = 0; iY < nYCheck; iY++)
5548
0
                {
5549
0
                    int iX = 0;
5550
0
                    for (int k = 0; k < nOuterLoops; k++)
5551
0
                    {
5552
0
                        int iMax = iX + 65536;
5553
0
                        if (iMax > nXCheck)
5554
0
                            iMax = nXCheck;
5555
0
                        GUInt32 nSum32bit = 0;
5556
0
                        GUInt32 nSumSquare32bit = 0;
5557
0
                        for (; iX + 3 < iMax; iX += 4)
5558
0
                        {
5559
0
                            const GPtrDiff_t iOffset =
5560
0
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5561
0
                            const GUInt32 nValue = pData[iOffset];
5562
0
                            const GUInt32 nValue2 = pData[iOffset + 1];
5563
0
                            const GUInt32 nValue3 = pData[iOffset + 2];
5564
0
                            const GUInt32 nValue4 = pData[iOffset + 3];
5565
0
                            nSum32bit += nValue;
5566
0
                            nSumSquare32bit += nValue * nValue;
5567
0
                            nSum32bit += nValue2;
5568
0
                            nSumSquare32bit += nValue2 * nValue2;
5569
0
                            nSum32bit += nValue3;
5570
0
                            nSumSquare32bit += nValue3 * nValue3;
5571
0
                            nSum32bit += nValue4;
5572
0
                            nSumSquare32bit += nValue4 * nValue4;
5573
0
                        }
5574
0
                        nSum += nSum32bit;
5575
0
                        nSumSquare += nSumSquare32bit;
5576
0
                    }
5577
0
                    for (; iX < nXCheck; ++iX)
5578
0
                    {
5579
0
                        const GPtrDiff_t iOffset =
5580
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5581
0
                        const GUIntBig nValue = pData[iOffset];
5582
0
                        nSum += nValue;
5583
0
                        nSumSquare += nValue * nValue;
5584
0
                    }
5585
0
                }
5586
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5587
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5588
0
            }
5589
0
        }
5590
0
        else
5591
0
        {
5592
0
            for (int iY = 0; iY < nYCheck; iY++)
5593
0
            {
5594
0
                int iX = 0;
5595
0
                for (int k = 0; k < nOuterLoops; k++)
5596
0
                {
5597
0
                    int iMax = iX + 65536;
5598
0
                    if (iMax > nXCheck)
5599
0
                        iMax = nXCheck;
5600
0
                    GUInt32 nSum32bit = 0;
5601
0
                    GUInt32 nSumSquare32bit = 0;
5602
0
                    for (; iX + 1 < iMax; iX += 2)
5603
0
                    {
5604
0
                        const GPtrDiff_t iOffset =
5605
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5606
0
                        const GUInt32 nValue = pData[iOffset];
5607
0
                        const GUInt32 nValue2 = pData[iOffset + 1];
5608
0
                        if (nValue < nValue2)
5609
0
                        {
5610
0
                            if (nValue < nMin)
5611
0
                                nMin = nValue;
5612
0
                            if (nValue2 > nMax)
5613
0
                                nMax = nValue2;
5614
0
                        }
5615
0
                        else
5616
0
                        {
5617
0
                            if (nValue2 < nMin)
5618
0
                                nMin = nValue2;
5619
0
                            if (nValue > nMax)
5620
0
                                nMax = nValue;
5621
0
                        }
5622
                        if constexpr (COMPUTE_OTHER_STATS)
5623
0
                        {
5624
0
                            nSum32bit += nValue;
5625
0
                            nSumSquare32bit += nValue * nValue;
5626
0
                            nSum32bit += nValue2;
5627
0
                            nSumSquare32bit += nValue2 * nValue2;
5628
0
                        }
5629
0
                    }
5630
                    if constexpr (COMPUTE_OTHER_STATS)
5631
0
                    {
5632
0
                        nSum += nSum32bit;
5633
0
                        nSumSquare += nSumSquare32bit;
5634
0
                    }
5635
0
                }
5636
0
                if (iX < nXCheck)
5637
0
                {
5638
0
                    const GPtrDiff_t iOffset =
5639
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5640
0
                    const GUInt32 nValue = pData[iOffset];
5641
0
                    if (nValue < nMin)
5642
0
                        nMin = nValue;
5643
0
                    if (nValue > nMax)
5644
0
                        nMax = nValue;
5645
                    if constexpr (COMPUTE_OTHER_STATS)
5646
0
                    {
5647
0
                        nSum += nValue;
5648
0
                        nSumSquare +=
5649
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5650
0
                            nValue;
5651
0
                    }
5652
0
                }
5653
0
            }
5654
            if constexpr (COMPUTE_OTHER_STATS)
5655
0
            {
5656
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5657
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5658
0
            }
5659
0
        }
5660
0
    }
Unexecuted instantiation: ComputeStatisticsInternalGeneric<unsigned char, false>::f(int, int, int, unsigned char const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: ComputeStatisticsInternalGeneric<unsigned char, true>::f(int, int, int, unsigned char const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
5661
};
5662
5663
template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5664
{
5665
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5666
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5667
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5668
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5669
    {
5670
        ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5671
            nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5672
            nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5673
    }
5674
};
5675
5676
#if (defined(__x86_64__) || defined(_M_X64)) &&                                \
5677
    (defined(__GNUC__) || defined(_MSC_VER))
5678
5679
#include "gdal_avx2_emulation.hpp"
5680
5681
0
#define ZERO256 GDALmm256_setzero_si256()
5682
5683
template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5684
static void
5685
ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5686
                              // assumed to be aligned on 256 bits
5687
                              const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5688
                              GUIntBig &nSum, GUIntBig &nSumSquare,
5689
                              GUIntBig &nSampleCount, GUIntBig &nValidCount)
5690
0
{
5691
    // 32-byte alignment may not be enforced by linker, so do it at hand
5692
0
    GByte
5693
0
        aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5694
0
    GByte *paby32ByteAligned =
5695
0
        aby32ByteUnaligned +
5696
0
        (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5697
0
    GByte *pabyMin = paby32ByteAligned;
5698
0
    GByte *pabyMax = paby32ByteAligned + 32;
5699
0
    GUInt32 *panSum =
5700
0
        COMPUTE_OTHER_STATS
5701
0
            ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5702
0
            : nullptr;
5703
0
    GUInt32 *panSumSquare =
5704
0
        COMPUTE_OTHER_STATS
5705
0
            ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5706
0
            : nullptr;
5707
5708
0
    CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5709
5710
0
    GPtrDiff_t i = 0;
5711
    // Make sure that sumSquare can fit on uint32
5712
    // * 8 since we can hold 8 sums per vector register
5713
0
    const int nMaxIterationsPerInnerLoop =
5714
0
        8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5715
0
    GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5716
0
    if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5717
0
        nOuterLoops++;
5718
5719
0
    GDALm256i ymm_min =
5720
0
        GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5721
0
    GDALm256i ymm_max = ymm_min;
5722
0
    [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5723
5724
0
    for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5725
0
    {
5726
0
        const auto iMax =
5727
0
            std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5728
5729
        // holds 4 uint32 sums in [0], [2], [4] and [6]
5730
0
        [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5731
0
        [[maybe_unused]] GDALm256i ymm_sumsquare =
5732
0
            ZERO256;  // holds 8 uint32 sums
5733
0
        for (; i + 31 < iMax; i += 32)
5734
0
        {
5735
0
            const GDALm256i ymm = GDALmm256_load_si256(
5736
0
                reinterpret_cast<const GDALm256i *>(pData + i));
5737
0
            if (COMPUTE_MIN)
5738
0
            {
5739
0
                ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5740
0
            }
5741
0
            if (COMPUTE_MAX)
5742
0
            {
5743
0
                ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5744
0
            }
5745
5746
            if constexpr (COMPUTE_OTHER_STATS)
5747
0
            {
5748
                // Extract even-8bit values
5749
0
                const GDALm256i ymm_even =
5750
0
                    GDALmm256_and_si256(ymm, ymm_mask_8bits);
5751
                // Compute square of those 16 values as 32 bit result
5752
                // and add adjacent pairs
5753
0
                const GDALm256i ymm_even_square =
5754
0
                    GDALmm256_madd_epi16(ymm_even, ymm_even);
5755
                // Add to the sumsquare accumulator
5756
0
                ymm_sumsquare =
5757
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5758
5759
                // Extract odd-8bit values
5760
0
                const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5761
0
                const GDALm256i ymm_odd_square =
5762
0
                    GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5763
0
                ymm_sumsquare =
5764
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5765
5766
                // Now compute the sums
5767
0
                ymm_sum = GDALmm256_add_epi32(ymm_sum,
5768
0
                                              GDALmm256_sad_epu8(ymm, ZERO256));
5769
0
            }
5770
0
        }
5771
5772
        if constexpr (COMPUTE_OTHER_STATS)
5773
0
        {
5774
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5775
0
                                  ymm_sum);
5776
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5777
0
                                  ymm_sumsquare);
5778
5779
0
            nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5780
0
            nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5781
0
                          panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5782
0
                          panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5783
0
                          panSumSquare[7];
5784
0
        }
5785
0
    }
5786
5787
    if constexpr (COMPUTE_MIN)
5788
0
    {
5789
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5790
0
    }
5791
    if constexpr (COMPUTE_MAX)
5792
0
    {
5793
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5794
0
    }
5795
    if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5796
0
    {
5797
0
        for (int j = 0; j < 32; j++)
5798
0
        {
5799
            if constexpr (COMPUTE_MIN)
5800
0
            {
5801
0
                if (pabyMin[j] < nMin)
5802
0
                    nMin = pabyMin[j];
5803
0
            }
5804
            if constexpr (COMPUTE_MAX)
5805
0
            {
5806
0
                if (pabyMax[j] > nMax)
5807
0
                    nMax = pabyMax[j];
5808
0
            }
5809
0
        }
5810
0
    }
5811
5812
0
    for (; i < nBlockPixels; i++)
5813
0
    {
5814
0
        const GUInt32 nValue = pData[i];
5815
        if constexpr (COMPUTE_MIN)
5816
0
        {
5817
0
            if (nValue < nMin)
5818
0
                nMin = nValue;
5819
0
        }
5820
        if constexpr (COMPUTE_MAX)
5821
0
        {
5822
0
            if (nValue > nMax)
5823
0
                nMax = nValue;
5824
0
        }
5825
        if constexpr (COMPUTE_OTHER_STATS)
5826
0
        {
5827
0
            nSum += nValue;
5828
0
            nSumSquare +=
5829
0
                static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5830
0
        }
5831
0
    }
5832
5833
    if constexpr (COMPUTE_OTHER_STATS)
5834
0
    {
5835
0
        nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5836
0
        nValidCount += static_cast<GUIntBig>(nBlockPixels);
5837
0
    }
5838
0
}
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<true, true, false>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<true, false, false>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<false, true, false>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<false, false, false>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<true, true, true>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<true, false, true>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<false, true, true>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<false, false, true>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
5839
5840
// SSE2/AVX2 optimization for GByte case
5841
// In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5842
// penaly in using the emulation, because, given the mm256 intrinsics used here,
5843
// there are strictly equivalent to 2 parallel SSE2 streams.
5844
template <bool COMPUTE_OTHER_STATS>
5845
struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5846
{
5847
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
5848
                  // assumed to be aligned on 256 bits
5849
                  const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5850
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5851
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5852
                  GUIntBig &nValidCount)
5853
0
    {
5854
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5855
0
        if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5856
0
            nMin <= nMax)
5857
0
        {
5858
            // 32-byte alignment may not be enforced by linker, so do it at hand
5859
0
            GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5860
0
            GByte *paby32ByteAligned =
5861
0
                aby32ByteUnaligned +
5862
0
                (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5863
0
            GByte *pabyMin = paby32ByteAligned;
5864
0
            GByte *pabyMax = paby32ByteAligned + 32;
5865
0
            GUInt32 *panSum =
5866
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5867
0
            GUInt32 *panSumSquare =
5868
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5869
5870
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5871
5872
0
            GPtrDiff_t i = 0;
5873
            // Make sure that sumSquare can fit on uint32
5874
            // * 8 since we can hold 8 sums per vector register
5875
0
            const int nMaxIterationsPerInnerLoop =
5876
0
                8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5877
0
            auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5878
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5879
0
                nOuterLoops++;
5880
5881
0
            const GDALm256i ymm_nodata =
5882
0
                GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5883
            // any non noData value in [min,max] would do.
5884
0
            const GDALm256i ymm_neutral =
5885
0
                GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5886
0
            GDALm256i ymm_min = ymm_neutral;
5887
0
            GDALm256i ymm_max = ymm_neutral;
5888
0
            [[maybe_unused]] const auto ymm_mask_8bits =
5889
0
                GDALmm256_set1_epi16(0xFF);
5890
5891
0
            const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5892
0
            const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5893
0
            const bool bComputeMinMax =
5894
0
                nMin > nMinThreshold || nMax < nMaxThreshold;
5895
5896
0
            for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5897
0
            {
5898
0
                const auto iMax =
5899
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5900
5901
                // holds 4 uint32 sums in [0], [2], [4] and [6]
5902
0
                [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5903
                // holds 8 uint32 sums
5904
0
                [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5905
                // holds 4 uint32 sums in [0], [2], [4] and [6]
5906
0
                [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5907
0
                const auto iInit = i;
5908
0
                for (; i + 31 < iMax; i += 32)
5909
0
                {
5910
0
                    const GDALm256i ymm = GDALmm256_load_si256(
5911
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
5912
5913
                    // Check which values are nodata
5914
0
                    const GDALm256i ymm_eq_nodata =
5915
0
                        GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5916
                    if constexpr (COMPUTE_OTHER_STATS)
5917
0
                    {
5918
                        // Count how many values are nodata (due to cmpeq
5919
                        // putting 255 when condition is met, this will actually
5920
                        // be 255 times the number of nodata value, spread in 4
5921
                        // 64 bits words). We can use add_epi32 as the counter
5922
                        // will not overflow uint32
5923
0
                        ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5924
0
                            ymm_count_nodata_mul_255,
5925
0
                            GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5926
0
                    }
5927
                    // Replace all nodata values by zero for the purpose of sum
5928
                    // and sumquare.
5929
0
                    const GDALm256i ymm_nodata_by_zero =
5930
0
                        GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5931
0
                    if (bComputeMinMax)
5932
0
                    {
5933
                        // Replace all nodata values by a neutral value for the
5934
                        // purpose of min and max.
5935
0
                        const GDALm256i ymm_nodata_by_neutral =
5936
0
                            GDALmm256_or_si256(
5937
0
                                GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5938
0
                                ymm_nodata_by_zero);
5939
5940
0
                        ymm_min =
5941
0
                            GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5942
0
                        ymm_max =
5943
0
                            GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
5944
0
                    }
5945
5946
                    if constexpr (COMPUTE_OTHER_STATS)
5947
0
                    {
5948
                        // Extract even-8bit values
5949
0
                        const GDALm256i ymm_even = GDALmm256_and_si256(
5950
0
                            ymm_nodata_by_zero, ymm_mask_8bits);
5951
                        // Compute square of those 16 values as 32 bit result
5952
                        // and add adjacent pairs
5953
0
                        const GDALm256i ymm_even_square =
5954
0
                            GDALmm256_madd_epi16(ymm_even, ymm_even);
5955
                        // Add to the sumsquare accumulator
5956
0
                        ymm_sumsquare =
5957
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5958
5959
                        // Extract odd-8bit values
5960
0
                        const GDALm256i ymm_odd =
5961
0
                            GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
5962
0
                        const GDALm256i ymm_odd_square =
5963
0
                            GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5964
0
                        ymm_sumsquare =
5965
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5966
5967
                        // Now compute the sums
5968
0
                        ymm_sum = GDALmm256_add_epi32(
5969
0
                            ymm_sum,
5970
0
                            GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
5971
0
                    }
5972
0
                }
5973
5974
                if constexpr (COMPUTE_OTHER_STATS)
5975
0
                {
5976
0
                    GUInt32 *panCoutNoDataMul255 = panSum;
5977
0
                    GDALmm256_store_si256(
5978
0
                        reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
5979
0
                        ymm_count_nodata_mul_255);
5980
5981
0
                    nSampleCount += (i - iInit);
5982
5983
0
                    nValidCount +=
5984
0
                        (i - iInit) -
5985
0
                        (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
5986
0
                         panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
5987
0
                            255;
5988
5989
0
                    GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5990
0
                                          ymm_sum);
5991
0
                    GDALmm256_store_si256(
5992
0
                        reinterpret_cast<GDALm256i *>(panSumSquare),
5993
0
                        ymm_sumsquare);
5994
0
                    nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5995
0
                    nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5996
0
                                  panSumSquare[1] + panSumSquare[2] +
5997
0
                                  panSumSquare[3] + panSumSquare[4] +
5998
0
                                  panSumSquare[5] + panSumSquare[6] +
5999
0
                                  panSumSquare[7];
6000
0
                }
6001
0
            }
6002
6003
0
            if (bComputeMinMax)
6004
0
            {
6005
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6006
0
                                      ymm_min);
6007
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6008
0
                                      ymm_max);
6009
0
                for (int j = 0; j < 32; j++)
6010
0
                {
6011
0
                    if (pabyMin[j] < nMin)
6012
0
                        nMin = pabyMin[j];
6013
0
                    if (pabyMax[j] > nMax)
6014
0
                        nMax = pabyMax[j];
6015
0
                }
6016
0
            }
6017
6018
            if constexpr (COMPUTE_OTHER_STATS)
6019
0
            {
6020
0
                nSampleCount += nBlockPixels - i;
6021
0
            }
6022
0
            for (; i < nBlockPixels; i++)
6023
0
            {
6024
0
                const GUInt32 nValue = pData[i];
6025
0
                if (nValue == nNoDataValue)
6026
0
                    continue;
6027
0
                if (nValue < nMin)
6028
0
                    nMin = nValue;
6029
0
                if (nValue > nMax)
6030
0
                    nMax = nValue;
6031
                if constexpr (COMPUTE_OTHER_STATS)
6032
0
                {
6033
0
                    nValidCount++;
6034
0
                    nSum += nValue;
6035
0
                    nSumSquare +=
6036
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6037
0
                        nValue;
6038
0
                }
6039
0
            }
6040
0
        }
6041
0
        else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6042
0
        {
6043
0
            if (nMin > 0)
6044
0
            {
6045
0
                if (nMax < 255)
6046
0
                {
6047
0
                    ComputeStatisticsByteNoNodata<true, true,
6048
0
                                                  COMPUTE_OTHER_STATS>(
6049
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6050
0
                        nSampleCount, nValidCount);
6051
0
                }
6052
0
                else
6053
0
                {
6054
0
                    ComputeStatisticsByteNoNodata<true, false,
6055
0
                                                  COMPUTE_OTHER_STATS>(
6056
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6057
0
                        nSampleCount, nValidCount);
6058
0
                }
6059
0
            }
6060
0
            else
6061
0
            {
6062
0
                if (nMax < 255)
6063
0
                {
6064
0
                    ComputeStatisticsByteNoNodata<false, true,
6065
0
                                                  COMPUTE_OTHER_STATS>(
6066
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6067
0
                        nSampleCount, nValidCount);
6068
0
                }
6069
0
                else
6070
0
                {
6071
0
                    ComputeStatisticsByteNoNodata<false, false,
6072
0
                                                  COMPUTE_OTHER_STATS>(
6073
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6074
0
                        nSampleCount, nValidCount);
6075
0
                }
6076
0
            }
6077
0
        }
6078
0
        else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6079
0
                 (nBlockXSize % 32) == 0)
6080
0
        {
6081
0
            for (int iY = 0; iY < nYCheck; iY++)
6082
0
            {
6083
0
                ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6084
0
                    nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6085
0
                    nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6086
0
            }
6087
0
        }
6088
0
        else
6089
0
        {
6090
0
            ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6091
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6092
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6093
0
        }
6094
0
    }
Unexecuted instantiation: ComputeStatisticsInternal<unsigned char, false>::f(int, int, int, unsigned char const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: ComputeStatisticsInternal<unsigned char, true>::f(int, int, int, unsigned char const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
6095
};
6096
6097
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6098
static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6099
                             GUIntBig i)
6100
0
{
6101
0
    nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6102
0
}
6103
6104
// AVX2/SSE2 optimization for GUInt16 case
6105
template <bool COMPUTE_OTHER_STATS>
6106
struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6107
{
6108
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
6109
                  // assumed to be aligned on 128 bits
6110
                  const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6111
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6112
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6113
                  GUIntBig &nValidCount)
6114
0
    {
6115
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6116
0
        if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6117
0
        {
6118
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6119
6120
0
            GPtrDiff_t i = 0;
6121
            // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6122
            // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6123
            // Furthermore the shift is also needed to use madd_epi16
6124
0
            const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6125
0
            GDALm256i ymm_min = GDALmm256_load_si256(
6126
0
                reinterpret_cast<const GDALm256i *>(pData + i));
6127
0
            ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6128
0
            GDALm256i ymm_max = ymm_min;
6129
0
            [[maybe_unused]] GDALm256i ymm_sumsquare =
6130
0
                ZERO256;  // holds 4 uint64 sums
6131
6132
            // Make sure that sum can fit on uint32
6133
            // * 8 since we can hold 8 sums per vector register
6134
0
            const int nMaxIterationsPerInnerLoop =
6135
0
                8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6136
0
            GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6137
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6138
0
                nOuterLoops++;
6139
6140
0
            const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6141
0
            [[maybe_unused]] const auto ymm_mask_16bits =
6142
0
                GDALmm256_set1_epi32(0xFFFF);
6143
0
            [[maybe_unused]] const auto ymm_mask_32bits =
6144
0
                GDALmm256_set1_epi64x(0xFFFFFFFF);
6145
6146
0
            GUIntBig nSumThis = 0;
6147
0
            for (int k = 0; k < nOuterLoops; k++)
6148
0
            {
6149
0
                const auto iMax =
6150
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6151
6152
0
                [[maybe_unused]] GDALm256i ymm_sum =
6153
0
                    ZERO256;  // holds 8 uint32 sums
6154
0
                for (; i + 15 < iMax; i += 16)
6155
0
                {
6156
0
                    const GDALm256i ymm = GDALmm256_load_si256(
6157
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
6158
0
                    const GDALm256i ymm_shifted =
6159
0
                        GDALmm256_add_epi16(ymm, ymm_m32768);
6160
0
                    if (bComputeMinMax)
6161
0
                    {
6162
0
                        ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6163
0
                        ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6164
0
                    }
6165
6166
                    if constexpr (COMPUTE_OTHER_STATS)
6167
0
                    {
6168
                        // Note: the int32 range can overflow for (0-32768)^2 +
6169
                        // (0-32768)^2 = 0x80000000, but as we know the result
6170
                        // is positive, this is OK as we interpret is a uint32.
6171
0
                        const GDALm256i ymm_square =
6172
0
                            GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6173
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6174
0
                            ymm_sumsquare,
6175
0
                            GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6176
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6177
0
                            ymm_sumsquare,
6178
0
                            GDALmm256_srli_epi64(ymm_square, 32));
6179
6180
                        // Now compute the sums
6181
0
                        ymm_sum = GDALmm256_add_epi32(
6182
0
                            ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6183
0
                        ymm_sum = GDALmm256_add_epi32(
6184
0
                            ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6185
0
                    }
6186
0
                }
6187
6188
                if constexpr (COMPUTE_OTHER_STATS)
6189
0
                {
6190
0
                    GUInt32 anSum[8];
6191
0
                    GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6192
0
                                           ymm_sum);
6193
0
                    nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6194
0
                                anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6195
0
                                anSum[6] + anSum[7];
6196
0
                }
6197
0
            }
6198
6199
0
            if (bComputeMinMax)
6200
0
            {
6201
0
                GUInt16 anMin[16];
6202
0
                GUInt16 anMax[16];
6203
6204
                // Unshift the result
6205
0
                ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6206
0
                ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6207
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6208
0
                                       ymm_min);
6209
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6210
0
                                       ymm_max);
6211
0
                for (int j = 0; j < 16; j++)
6212
0
                {
6213
0
                    if (anMin[j] < nMin)
6214
0
                        nMin = anMin[j];
6215
0
                    if (anMax[j] > nMax)
6216
0
                        nMax = anMax[j];
6217
0
                }
6218
0
            }
6219
6220
            if constexpr (COMPUTE_OTHER_STATS)
6221
0
            {
6222
0
                GUIntBig anSumSquare[4];
6223
0
                GDALmm256_storeu_si256(
6224
0
                    reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6225
0
                nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6226
0
                              anSumSquare[3];
6227
6228
                // Unshift the sum of squares
6229
0
                UnshiftSumSquare(nSumSquare, nSumThis,
6230
0
                                 static_cast<GUIntBig>(i));
6231
6232
0
                nSum += nSumThis;
6233
6234
0
                for (; i < nBlockPixels; i++)
6235
0
                {
6236
0
                    const GUInt32 nValue = pData[i];
6237
0
                    if (nValue < nMin)
6238
0
                        nMin = nValue;
6239
0
                    if (nValue > nMax)
6240
0
                        nMax = nValue;
6241
0
                    nSum += nValue;
6242
0
                    nSumSquare +=
6243
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6244
0
                        nValue;
6245
0
                }
6246
6247
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6248
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6249
0
            }
6250
0
        }
6251
0
        else
6252
0
        {
6253
0
            ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6254
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6255
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6256
0
        }
6257
0
    }
Unexecuted instantiation: ComputeStatisticsInternal<unsigned short, false>::f(int, int, int, unsigned short const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: ComputeStatisticsInternal<unsigned short, true>::f(int, int, int, unsigned short const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
6258
};
6259
6260
#endif
6261
// (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6262
// defined(_MSC_VER))
6263
6264
/************************************************************************/
6265
/*                          GetPixelValue()                             */
6266
/************************************************************************/
6267
6268
static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6269
                                   const void *pData, GPtrDiff_t iOffset,
6270
                                   const GDALNoDataValues &sNoDataValues,
6271
                                   bool &bValid)
6272
0
{
6273
0
    bValid = true;
6274
0
    double dfValue = 0;
6275
0
    switch (eDataType)
6276
0
    {
6277
0
        case GDT_Byte:
6278
0
        {
6279
0
            if (bSignedByte)
6280
0
                dfValue = static_cast<const signed char *>(pData)[iOffset];
6281
0
            else
6282
0
                dfValue = static_cast<const GByte *>(pData)[iOffset];
6283
0
            break;
6284
0
        }
6285
0
        case GDT_Int8:
6286
0
            dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6287
0
            break;
6288
0
        case GDT_UInt16:
6289
0
            dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6290
0
            break;
6291
0
        case GDT_Int16:
6292
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6293
0
            break;
6294
0
        case GDT_UInt32:
6295
0
            dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6296
0
            break;
6297
0
        case GDT_Int32:
6298
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6299
0
            break;
6300
0
        case GDT_UInt64:
6301
0
            dfValue = static_cast<double>(
6302
0
                static_cast<const std::uint64_t *>(pData)[iOffset]);
6303
0
            break;
6304
0
        case GDT_Int64:
6305
0
            dfValue = static_cast<double>(
6306
0
                static_cast<const std::int64_t *>(pData)[iOffset]);
6307
0
            break;
6308
0
        case GDT_Float16:
6309
0
        {
6310
0
            using namespace std;
6311
0
            const GFloat16 hfValue =
6312
0
                static_cast<const GFloat16 *>(pData)[iOffset];
6313
0
            if (isnan(hfValue) ||
6314
0
                (sNoDataValues.bGotFloat16NoDataValue &&
6315
0
                 ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6316
0
            {
6317
0
                bValid = false;
6318
0
                return 0.0;
6319
0
            }
6320
0
            dfValue = hfValue;
6321
0
            return dfValue;
6322
0
        }
6323
0
        case GDT_Float32:
6324
0
        {
6325
0
            const float fValue = static_cast<const float *>(pData)[iOffset];
6326
0
            if (std::isnan(fValue) ||
6327
0
                (sNoDataValues.bGotFloatNoDataValue &&
6328
0
                 ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6329
0
            {
6330
0
                bValid = false;
6331
0
                return 0.0;
6332
0
            }
6333
0
            dfValue = fValue;
6334
0
            return dfValue;
6335
0
        }
6336
0
        case GDT_Float64:
6337
0
            dfValue = static_cast<const double *>(pData)[iOffset];
6338
0
            if (std::isnan(dfValue))
6339
0
            {
6340
0
                bValid = false;
6341
0
                return 0.0;
6342
0
            }
6343
0
            break;
6344
0
        case GDT_CInt16:
6345
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6346
0
            break;
6347
0
        case GDT_CInt32:
6348
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6349
0
            break;
6350
0
        case GDT_CFloat16:
6351
0
            dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6352
0
            if (std::isnan(dfValue))
6353
0
            {
6354
0
                bValid = false;
6355
0
                return 0.0;
6356
0
            }
6357
0
            break;
6358
0
        case GDT_CFloat32:
6359
0
            dfValue = static_cast<const float *>(pData)[iOffset * 2];
6360
0
            if (std::isnan(dfValue))
6361
0
            {
6362
0
                bValid = false;
6363
0
                return 0.0;
6364
0
            }
6365
0
            break;
6366
0
        case GDT_CFloat64:
6367
0
            dfValue = static_cast<const double *>(pData)[iOffset * 2];
6368
0
            if (std::isnan(dfValue))
6369
0
            {
6370
0
                bValid = false;
6371
0
                return 0.0;
6372
0
            }
6373
0
            break;
6374
0
        case GDT_Unknown:
6375
0
        case GDT_TypeCount:
6376
0
            CPLAssert(false);
6377
0
            break;
6378
0
    }
6379
6380
0
    if (sNoDataValues.bGotNoDataValue &&
6381
0
        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6382
0
    {
6383
0
        bValid = false;
6384
0
        return 0.0;
6385
0
    }
6386
0
    return dfValue;
6387
0
}
6388
6389
/************************************************************************/
6390
/*                         SetValidPercent()                            */
6391
/************************************************************************/
6392
6393
//! @cond Doxygen_Suppress
6394
/**
6395
 * \brief Set percentage of valid (not nodata) pixels.
6396
 *
6397
 * Stores the percentage of valid pixels in the metadata item
6398
 * STATISTICS_VALID_PERCENT
6399
 *
6400
 * @param nSampleCount Number of sampled pixels.
6401
 *
6402
 * @param nValidCount Number of valid pixels.
6403
 */
6404
6405
void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6406
                                     GUIntBig nValidCount)
6407
0
{
6408
0
    if (nValidCount == 0)
6409
0
    {
6410
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6411
0
    }
6412
0
    else if (nValidCount == nSampleCount)
6413
0
    {
6414
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6415
0
    }
6416
0
    else /* nValidCount < nSampleCount */
6417
0
    {
6418
0
        char szValue[128] = {0};
6419
6420
        /* percentage is only an indicator: limit precision */
6421
0
        CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6422
0
                    100. * static_cast<double>(nValidCount) / nSampleCount);
6423
6424
0
        if (EQUAL(szValue, "100"))
6425
0
        {
6426
            /* don't set 100 percent valid
6427
             * because some of the sampled pixels were nodata */
6428
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6429
0
        }
6430
0
        else
6431
0
        {
6432
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6433
0
        }
6434
0
    }
6435
0
}
6436
6437
//! @endcond
6438
6439
/************************************************************************/
6440
/*                         ComputeStatistics()                          */
6441
/************************************************************************/
6442
6443
/**
6444
 * \brief Compute image statistics.
6445
 *
6446
 * Returns the minimum, maximum, mean and standard deviation of all
6447
 * pixel values in this band.  If approximate statistics are sufficient,
6448
 * the bApproxOK flag can be set to true in which case overviews, or a
6449
 * subset of image tiles may be used in computing the statistics.
6450
 *
6451
 * Once computed, the statistics will generally be "set" back on the
6452
 * raster band using SetStatistics().
6453
 *
6454
 * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6455
 *
6456
 * This method is the same as the C function GDALComputeRasterStatistics().
6457
 *
6458
 * @param bApproxOK If TRUE statistics may be computed based on overviews
6459
 * or a subset of all tiles.
6460
 *
6461
 * @param pdfMin Location into which to load image minimum (may be NULL).
6462
 *
6463
 * @param pdfMax Location into which to load image maximum (may be NULL).-
6464
 *
6465
 * @param pdfMean Location into which to load image mean (may be NULL).
6466
 *
6467
 * @param pdfStdDev Location into which to load image standard deviation
6468
 * (may be NULL).
6469
 *
6470
 * @param pfnProgress a function to call to report progress, or NULL.
6471
 *
6472
 * @param pProgressData application data to pass to the progress function.
6473
 *
6474
 * @return CE_None on success, or CE_Failure if an error occurs or processing
6475
 * is terminated by the user.
6476
 */
6477
6478
CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6479
                                         double *pdfMax, double *pdfMean,
6480
                                         double *pdfStdDev,
6481
                                         GDALProgressFunc pfnProgress,
6482
                                         void *pProgressData)
6483
6484
0
{
6485
0
    if (pfnProgress == nullptr)
6486
0
        pfnProgress = GDALDummyProgress;
6487
6488
    /* -------------------------------------------------------------------- */
6489
    /*      If we have overview bands, use them for statistics.             */
6490
    /* -------------------------------------------------------------------- */
6491
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6492
0
    {
6493
0
        GDALRasterBand *poBand =
6494
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6495
6496
0
        if (poBand != this)
6497
0
        {
6498
0
            CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6499
0
                                                    pdfMean, pdfStdDev,
6500
0
                                                    pfnProgress, pProgressData);
6501
0
            if (eErr == CE_None)
6502
0
            {
6503
0
                if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6504
0
                {
6505
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6506
0
                    SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6507
0
                }
6508
6509
                /* transfer metadata from overview band to this */
6510
0
                const char *pszPercentValid =
6511
0
                    poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6512
6513
0
                if (pszPercentValid != nullptr)
6514
0
                {
6515
0
                    SetMetadataItem("STATISTICS_VALID_PERCENT",
6516
0
                                    pszPercentValid);
6517
0
                }
6518
0
            }
6519
0
            return eErr;
6520
0
        }
6521
0
    }
6522
6523
0
    if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6524
0
    {
6525
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6526
0
        return CE_Failure;
6527
0
    }
6528
6529
    /* -------------------------------------------------------------------- */
6530
    /*      Read actual data and compute statistics.                        */
6531
    /* -------------------------------------------------------------------- */
6532
    // Using Welford algorithm:
6533
    // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6534
    // to compute standard deviation in a more numerically robust way than
6535
    // the difference of the sum of square values with the square of the sum.
6536
    // dfMean and dfM2 are updated at each sample.
6537
    // dfM2 is the sum of square of differences to the current mean.
6538
0
    double dfMin = std::numeric_limits<double>::infinity();
6539
0
    double dfMax = -std::numeric_limits<double>::infinity();
6540
0
    double dfMean = 0.0;
6541
0
    double dfM2 = 0.0;
6542
6543
0
    GDALRasterIOExtraArg sExtraArg;
6544
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6545
6546
0
    GDALNoDataValues sNoDataValues(this, eDataType);
6547
0
    GDALRasterBand *poMaskBand = nullptr;
6548
0
    if (!sNoDataValues.bGotNoDataValue)
6549
0
    {
6550
0
        const int l_nMaskFlags = GetMaskFlags();
6551
0
        if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
6552
0
            GetColorInterpretation() != GCI_AlphaBand)
6553
0
        {
6554
0
            poMaskBand = GetMaskBand();
6555
0
        }
6556
0
    }
6557
6558
0
    bool bSignedByte = false;
6559
0
    if (eDataType == GDT_Byte)
6560
0
    {
6561
0
        EnablePixelTypeSignedByteWarning(false);
6562
0
        const char *pszPixelType =
6563
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6564
0
        EnablePixelTypeSignedByteWarning(true);
6565
0
        bSignedByte =
6566
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6567
0
    }
6568
6569
0
    GUIntBig nSampleCount = 0;
6570
0
    GUIntBig nValidCount = 0;
6571
6572
0
    if (bApproxOK && HasArbitraryOverviews())
6573
0
    {
6574
        /* --------------------------------------------------------------------
6575
         */
6576
        /*      Figure out how much the image should be reduced to get an */
6577
        /*      approximate value. */
6578
        /* --------------------------------------------------------------------
6579
         */
6580
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6581
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6582
6583
0
        int nXReduced = nRasterXSize;
6584
0
        int nYReduced = nRasterYSize;
6585
0
        if (dfReduction > 1.0)
6586
0
        {
6587
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6588
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6589
6590
            // Catch the case of huge resizing ratios here
6591
0
            if (nXReduced == 0)
6592
0
                nXReduced = 1;
6593
0
            if (nYReduced == 0)
6594
0
                nYReduced = 1;
6595
0
        }
6596
6597
0
        void *pData = CPLMalloc(cpl::fits_on<int>(
6598
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6599
6600
0
        const CPLErr eErr =
6601
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6602
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6603
0
        if (eErr != CE_None)
6604
0
        {
6605
0
            CPLFree(pData);
6606
0
            return eErr;
6607
0
        }
6608
6609
0
        GByte *pabyMaskData = nullptr;
6610
0
        if (poMaskBand)
6611
0
        {
6612
0
            pabyMaskData =
6613
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6614
0
            if (!pabyMaskData)
6615
0
            {
6616
0
                CPLFree(pData);
6617
0
                return CE_Failure;
6618
0
            }
6619
6620
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6621
0
                                     pabyMaskData, nXReduced, nYReduced,
6622
0
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
6623
0
            {
6624
0
                CPLFree(pData);
6625
0
                CPLFree(pabyMaskData);
6626
0
                return CE_Failure;
6627
0
            }
6628
0
        }
6629
6630
        /* this isn't the fastest way to do this, but is easier for now */
6631
0
        for (int iY = 0; iY < nYReduced; iY++)
6632
0
        {
6633
0
            for (int iX = 0; iX < nXReduced; iX++)
6634
0
            {
6635
0
                const int iOffset = iX + iY * nXReduced;
6636
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
6637
0
                    continue;
6638
6639
0
                bool bValid = true;
6640
0
                double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
6641
0
                                               iOffset, sNoDataValues, bValid);
6642
0
                if (!bValid)
6643
0
                    continue;
6644
6645
0
                dfMin = std::min(dfMin, dfValue);
6646
0
                dfMax = std::max(dfMax, dfValue);
6647
6648
0
                nValidCount++;
6649
0
                if (dfMin == dfMax)
6650
0
                {
6651
0
                    if (nValidCount == 1)
6652
0
                        dfMean = dfMin;
6653
0
                }
6654
0
                else
6655
0
                {
6656
0
                    const double dfDelta = dfValue - dfMean;
6657
0
                    dfMean += dfDelta / nValidCount;
6658
0
                    dfM2 += dfDelta * (dfValue - dfMean);
6659
0
                }
6660
0
            }
6661
0
        }
6662
6663
0
        nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6664
6665
0
        CPLFree(pData);
6666
0
        CPLFree(pabyMaskData);
6667
0
    }
6668
6669
0
    else  // No arbitrary overviews.
6670
0
    {
6671
0
        if (!InitBlockInfo())
6672
0
            return CE_Failure;
6673
6674
        /* --------------------------------------------------------------------
6675
         */
6676
        /*      Figure out the ratio of blocks we will read to get an */
6677
        /*      approximate value. */
6678
        /* --------------------------------------------------------------------
6679
         */
6680
0
        int nSampleRate = 1;
6681
0
        if (bApproxOK)
6682
0
        {
6683
0
            nSampleRate = static_cast<int>(std::max(
6684
0
                1.0,
6685
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6686
            // We want to avoid probing only the first column of blocks for
6687
            // a square shaped raster, because it is not unlikely that it may
6688
            // be padding only (#6378)
6689
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6690
0
                nSampleRate += 1;
6691
0
        }
6692
0
        if (nSampleRate == 1)
6693
0
            bApproxOK = false;
6694
6695
        // Particular case for GDT_Byte that only use integral types for all
6696
        // intermediate computations. Only possible if the number of pixels
6697
        // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6698
        // can fit on a uint64. Should be 99.99999% of cases.
6699
        // For GUInt16, this limits to raster of 4 giga pixels
6700
0
        if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6701
0
             static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6702
0
                     nSampleRate <
6703
0
                 GUINTBIG_MAX / (255U * 255U) /
6704
0
                     (static_cast<GUInt64>(nBlockXSize) *
6705
0
                      static_cast<GUInt64>(nBlockYSize))) ||
6706
0
            (eDataType == GDT_UInt16 &&
6707
0
             static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6708
0
                     nSampleRate <
6709
0
                 GUINTBIG_MAX / (65535U * 65535U) /
6710
0
                     (static_cast<GUInt64>(nBlockXSize) *
6711
0
                      static_cast<GUInt64>(nBlockYSize))))
6712
0
        {
6713
0
            const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6714
0
            GUInt32 nMin = nMaxValueType;
6715
0
            GUInt32 nMax = 0;
6716
0
            GUIntBig nSum = 0;
6717
0
            GUIntBig nSumSquare = 0;
6718
            // If no valid nodata, map to invalid value (256 for Byte)
6719
0
            const GUInt32 nNoDataValue =
6720
0
                (sNoDataValues.bGotNoDataValue &&
6721
0
                 sNoDataValues.dfNoDataValue >= 0 &&
6722
0
                 sNoDataValues.dfNoDataValue <= nMaxValueType &&
6723
0
                 fabs(sNoDataValues.dfNoDataValue -
6724
0
                      static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
6725
0
                                           1e-10)) < 1e-10)
6726
0
                    ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
6727
0
                    : nMaxValueType + 1;
6728
6729
0
            for (GIntBig iSampleBlock = 0;
6730
0
                 iSampleBlock <
6731
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6732
0
                 iSampleBlock += nSampleRate)
6733
0
            {
6734
0
                const int iYBlock =
6735
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
6736
0
                const int iXBlock =
6737
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
6738
6739
0
                GDALRasterBlock *const poBlock =
6740
0
                    GetLockedBlockRef(iXBlock, iYBlock);
6741
0
                if (poBlock == nullptr)
6742
0
                    return CE_Failure;
6743
6744
0
                void *const pData = poBlock->GetDataRef();
6745
6746
0
                int nXCheck = 0, nYCheck = 0;
6747
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6748
6749
0
                if (eDataType == GDT_Byte)
6750
0
                {
6751
0
                    ComputeStatisticsInternal<
6752
0
                        GByte, /* COMPUTE_OTHER_STATS = */ true>::
6753
0
                        f(nXCheck, nBlockXSize, nYCheck,
6754
0
                          static_cast<const GByte *>(pData),
6755
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6756
0
                          nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6757
0
                }
6758
0
                else
6759
0
                {
6760
0
                    ComputeStatisticsInternal<
6761
0
                        GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6762
0
                        f(nXCheck, nBlockXSize, nYCheck,
6763
0
                          static_cast<const GUInt16 *>(pData),
6764
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6765
0
                          nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6766
0
                }
6767
6768
0
                poBlock->DropLock();
6769
6770
0
                if (!pfnProgress(static_cast<double>(iSampleBlock) /
6771
0
                                     (static_cast<double>(nBlocksPerRow) *
6772
0
                                      nBlocksPerColumn),
6773
0
                                 "Compute Statistics", pProgressData))
6774
0
                {
6775
0
                    ReportError(CE_Failure, CPLE_UserInterrupt,
6776
0
                                "User terminated");
6777
0
                    return CE_Failure;
6778
0
                }
6779
0
            }
6780
6781
0
            if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6782
0
            {
6783
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6784
0
                return CE_Failure;
6785
0
            }
6786
6787
            /* --------------------------------------------------------------------
6788
             */
6789
            /*      Save computed information. */
6790
            /* --------------------------------------------------------------------
6791
             */
6792
0
            if (nValidCount)
6793
0
                dfMean = static_cast<double>(nSum) / nValidCount;
6794
6795
            // To avoid potential precision issues when doing the difference,
6796
            // we need to do that computation on 128 bit rather than casting
6797
            // to double
6798
0
            const GDALUInt128 nTmpForStdDev(
6799
0
                GDALUInt128::Mul(nSumSquare, nValidCount) -
6800
0
                GDALUInt128::Mul(nSum, nSum));
6801
0
            const double dfStdDev =
6802
0
                nValidCount > 0
6803
0
                    ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6804
0
                    : 0.0;
6805
6806
0
            if (nValidCount > 0)
6807
0
            {
6808
0
                if (bApproxOK)
6809
0
                {
6810
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6811
0
                }
6812
0
                else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6813
0
                {
6814
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6815
0
                }
6816
0
                SetStatistics(nMin, nMax, dfMean, dfStdDev);
6817
0
            }
6818
6819
0
            SetValidPercent(nSampleCount, nValidCount);
6820
6821
            /* --------------------------------------------------------------------
6822
             */
6823
            /*      Record results. */
6824
            /* --------------------------------------------------------------------
6825
             */
6826
0
            if (pdfMin != nullptr)
6827
0
                *pdfMin = nValidCount ? nMin : 0;
6828
0
            if (pdfMax != nullptr)
6829
0
                *pdfMax = nValidCount ? nMax : 0;
6830
6831
0
            if (pdfMean != nullptr)
6832
0
                *pdfMean = dfMean;
6833
6834
0
            if (pdfStdDev != nullptr)
6835
0
                *pdfStdDev = dfStdDev;
6836
6837
0
            if (nValidCount > 0)
6838
0
                return CE_None;
6839
6840
0
            ReportError(CE_Failure, CPLE_AppDefined,
6841
0
                        "Failed to compute statistics, no valid pixels found "
6842
0
                        "in sampling.");
6843
0
            return CE_Failure;
6844
0
        }
6845
6846
0
        GByte *pabyMaskData = nullptr;
6847
0
        if (poMaskBand)
6848
0
        {
6849
0
            pabyMaskData = static_cast<GByte *>(
6850
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6851
0
            if (!pabyMaskData)
6852
0
            {
6853
0
                return CE_Failure;
6854
0
            }
6855
0
        }
6856
6857
0
        for (GIntBig iSampleBlock = 0;
6858
0
             iSampleBlock <
6859
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6860
0
             iSampleBlock += nSampleRate)
6861
0
        {
6862
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6863
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6864
6865
0
            GDALRasterBlock *const poBlock =
6866
0
                GetLockedBlockRef(iXBlock, iYBlock);
6867
0
            if (poBlock == nullptr)
6868
0
            {
6869
0
                CPLFree(pabyMaskData);
6870
0
                return CE_Failure;
6871
0
            }
6872
6873
0
            void *const pData = poBlock->GetDataRef();
6874
6875
0
            int nXCheck = 0, nYCheck = 0;
6876
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6877
6878
0
            if (poMaskBand &&
6879
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6880
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
6881
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6882
0
                                     0, nBlockXSize, nullptr) != CE_None)
6883
0
            {
6884
0
                CPLFree(pabyMaskData);
6885
0
                poBlock->DropLock();
6886
0
                return CE_Failure;
6887
0
            }
6888
6889
            // This isn't the fastest way to do this, but is easier for now.
6890
0
            for (int iY = 0; iY < nYCheck; iY++)
6891
0
            {
6892
0
                for (int iX = 0; iX < nXCheck; iX++)
6893
0
                {
6894
0
                    const GPtrDiff_t iOffset =
6895
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6896
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
6897
0
                        continue;
6898
6899
0
                    bool bValid = true;
6900
0
                    double dfValue =
6901
0
                        GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6902
0
                                      sNoDataValues, bValid);
6903
6904
0
                    if (!bValid)
6905
0
                        continue;
6906
6907
0
                    dfMin = std::min(dfMin, dfValue);
6908
0
                    dfMax = std::max(dfMax, dfValue);
6909
6910
0
                    nValidCount++;
6911
0
                    if (dfMin == dfMax)
6912
0
                    {
6913
0
                        if (nValidCount == 1)
6914
0
                            dfMean = dfMin;
6915
0
                    }
6916
0
                    else
6917
0
                    {
6918
0
                        const double dfDelta = dfValue - dfMean;
6919
0
                        dfMean += dfDelta / nValidCount;
6920
0
                        dfM2 += dfDelta * (dfValue - dfMean);
6921
0
                    }
6922
0
                }
6923
0
            }
6924
6925
0
            nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6926
6927
0
            poBlock->DropLock();
6928
6929
0
            if (!pfnProgress(
6930
0
                    static_cast<double>(iSampleBlock) /
6931
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6932
0
                    "Compute Statistics", pProgressData))
6933
0
            {
6934
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6935
0
                CPLFree(pabyMaskData);
6936
0
                return CE_Failure;
6937
0
            }
6938
0
        }
6939
6940
0
        CPLFree(pabyMaskData);
6941
0
    }
6942
6943
0
    if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6944
0
    {
6945
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6946
0
        return CE_Failure;
6947
0
    }
6948
6949
    /* -------------------------------------------------------------------- */
6950
    /*      Save computed information.                                      */
6951
    /* -------------------------------------------------------------------- */
6952
0
    const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
6953
6954
0
    if (nValidCount > 0)
6955
0
    {
6956
0
        if (bApproxOK)
6957
0
        {
6958
0
            SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6959
0
        }
6960
0
        else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6961
0
        {
6962
0
            SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6963
0
        }
6964
0
        SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6965
0
    }
6966
0
    else
6967
0
    {
6968
0
        dfMin = 0.0;
6969
0
        dfMax = 0.0;
6970
0
    }
6971
6972
0
    SetValidPercent(nSampleCount, nValidCount);
6973
6974
    /* -------------------------------------------------------------------- */
6975
    /*      Record results.                                                 */
6976
    /* -------------------------------------------------------------------- */
6977
0
    if (pdfMin != nullptr)
6978
0
        *pdfMin = dfMin;
6979
0
    if (pdfMax != nullptr)
6980
0
        *pdfMax = dfMax;
6981
6982
0
    if (pdfMean != nullptr)
6983
0
        *pdfMean = dfMean;
6984
6985
0
    if (pdfStdDev != nullptr)
6986
0
        *pdfStdDev = dfStdDev;
6987
6988
0
    if (nValidCount > 0)
6989
0
        return CE_None;
6990
6991
0
    ReportError(
6992
0
        CE_Failure, CPLE_AppDefined,
6993
0
        "Failed to compute statistics, no valid pixels found in sampling.");
6994
0
    return CE_Failure;
6995
0
}
6996
6997
/************************************************************************/
6998
/*                    GDALComputeRasterStatistics()                     */
6999
/************************************************************************/
7000
7001
/**
7002
 * \brief Compute image statistics.
7003
 *
7004
 * @see GDALRasterBand::ComputeStatistics()
7005
 */
7006
7007
CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7008
                                               int bApproxOK, double *pdfMin,
7009
                                               double *pdfMax, double *pdfMean,
7010
                                               double *pdfStdDev,
7011
                                               GDALProgressFunc pfnProgress,
7012
                                               void *pProgressData)
7013
7014
0
{
7015
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7016
7017
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7018
7019
0
    return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7020
0
                                     pdfStdDev, pfnProgress, pProgressData);
7021
0
}
7022
7023
/************************************************************************/
7024
/*                           SetStatistics()                            */
7025
/************************************************************************/
7026
7027
/**
7028
 * \brief Set statistics on band.
7029
 *
7030
 * This method can be used to store min/max/mean/standard deviation
7031
 * statistics on a raster band.
7032
 *
7033
 * The default implementation stores them as metadata, and will only work
7034
 * on formats that can save arbitrary metadata.  This method cannot detect
7035
 * whether metadata will be properly saved and so may return CE_None even
7036
 * if the statistics will never be saved.
7037
 *
7038
 * This method is the same as the C function GDALSetRasterStatistics().
7039
 *
7040
 * @param dfMin minimum pixel value.
7041
 *
7042
 * @param dfMax maximum pixel value.
7043
 *
7044
 * @param dfMean mean (average) of all pixel values.
7045
 *
7046
 * @param dfStdDev Standard deviation of all pixel values.
7047
 *
7048
 * @return CE_None on success or CE_Failure on failure.
7049
 */
7050
7051
CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7052
                                     double dfStdDev)
7053
7054
0
{
7055
0
    char szValue[128] = {0};
7056
7057
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7058
0
    SetMetadataItem("STATISTICS_MINIMUM", szValue);
7059
7060
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7061
0
    SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7062
7063
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7064
0
    SetMetadataItem("STATISTICS_MEAN", szValue);
7065
7066
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7067
0
    SetMetadataItem("STATISTICS_STDDEV", szValue);
7068
7069
0
    return CE_None;
7070
0
}
7071
7072
/************************************************************************/
7073
/*                      GDALSetRasterStatistics()                       */
7074
/************************************************************************/
7075
7076
/**
7077
 * \brief Set statistics on band.
7078
 *
7079
 * @see GDALRasterBand::SetStatistics()
7080
 */
7081
7082
CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7083
                                           double dfMax, double dfMean,
7084
                                           double dfStdDev)
7085
7086
0
{
7087
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7088
7089
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7090
0
    return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7091
0
}
7092
7093
/************************************************************************/
7094
/*                        ComputeRasterMinMax()                         */
7095
/************************************************************************/
7096
7097
template <class T, bool HAS_NODATA>
7098
static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7099
                          T *pMax)
7100
0
{
7101
0
    T min0 = *pMin;
7102
0
    T max0 = *pMax;
7103
0
    T min1 = *pMin;
7104
0
    T max1 = *pMax;
7105
0
    size_t i;
7106
0
    for (i = 0; i + 1 < nElts; i += 2)
7107
0
    {
7108
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
7109
0
        {
7110
0
            min0 = std::min(min0, buffer[i]);
7111
0
            max0 = std::max(max0, buffer[i]);
7112
0
        }
7113
0
        if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7114
0
        {
7115
0
            min1 = std::min(min1, buffer[i + 1]);
7116
0
            max1 = std::max(max1, buffer[i + 1]);
7117
0
        }
7118
0
    }
7119
0
    T min = std::min(min0, min1);
7120
0
    T max = std::max(max0, max1);
7121
0
    if (i < nElts)
7122
0
    {
7123
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
7124
0
        {
7125
0
            min = std::min(min, buffer[i]);
7126
0
            max = std::max(max, buffer[i]);
7127
0
        }
7128
0
    }
7129
0
    *pMin = min;
7130
0
    *pMax = max;
7131
0
}
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMax<short, true>(short const*, unsigned long, short, short*, short*)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMax<short, false>(short const*, unsigned long, short, short*, short*)
7132
7133
template <GDALDataType eDataType, bool bSignedByte>
7134
static void
7135
ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7136
                     int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7137
                     const GByte *pabyMaskData, double &dfMin, double &dfMax)
7138
0
{
7139
0
    double dfLocalMin = dfMin;
7140
0
    double dfLocalMax = dfMax;
7141
7142
0
    for (int iY = 0; iY < nYCheck; iY++)
7143
0
    {
7144
0
        for (int iX = 0; iX < nXCheck; iX++)
7145
0
        {
7146
0
            const GPtrDiff_t iOffset =
7147
0
                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7148
0
            if (pabyMaskData && pabyMaskData[iOffset] == 0)
7149
0
                continue;
7150
0
            bool bValid = true;
7151
0
            double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7152
0
                                           iOffset, sNoDataValues, bValid);
7153
0
            if (!bValid)
7154
0
                continue;
7155
7156
0
            dfLocalMin = std::min(dfLocalMin, dfValue);
7157
0
            dfLocalMax = std::max(dfLocalMax, dfValue);
7158
0
        }
7159
0
    }
7160
7161
0
    dfMin = dfLocalMin;
7162
0
    dfMax = dfLocalMax;
7163
0
}
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)1, true>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)1, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)14, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)2, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)3, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)4, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)5, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)12, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)13, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)15, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)6, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)7, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)8, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)9, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)16, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)10, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)11, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
7164
7165
static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
7166
                                 bool bSignedByte, int nXCheck, int nYCheck,
7167
                                 int nBlockXSize,
7168
                                 const GDALNoDataValues &sNoDataValues,
7169
                                 const GByte *pabyMaskData, double &dfMin,
7170
                                 double &dfMax)
7171
0
{
7172
0
    switch (eDataType)
7173
0
    {
7174
0
        case GDT_Unknown:
7175
0
            CPLAssert(false);
7176
0
            break;
7177
0
        case GDT_Byte:
7178
0
            if (bSignedByte)
7179
0
            {
7180
0
                ComputeMinMaxGeneric<GDT_Byte, true>(
7181
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7182
0
                    pabyMaskData, dfMin, dfMax);
7183
0
            }
7184
0
            else
7185
0
            {
7186
0
                ComputeMinMaxGeneric<GDT_Byte, false>(
7187
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7188
0
                    pabyMaskData, dfMin, dfMax);
7189
0
            }
7190
0
            break;
7191
0
        case GDT_Int8:
7192
0
            ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
7193
0
                                                  nBlockXSize, sNoDataValues,
7194
0
                                                  pabyMaskData, dfMin, dfMax);
7195
0
            break;
7196
0
        case GDT_UInt16:
7197
0
            ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
7198
0
                                                    nBlockXSize, sNoDataValues,
7199
0
                                                    pabyMaskData, dfMin, dfMax);
7200
0
            break;
7201
0
        case GDT_Int16:
7202
0
            ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
7203
0
                                                   nBlockXSize, sNoDataValues,
7204
0
                                                   pabyMaskData, dfMin, dfMax);
7205
0
            break;
7206
0
        case GDT_UInt32:
7207
0
            ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
7208
0
                                                    nBlockXSize, sNoDataValues,
7209
0
                                                    pabyMaskData, dfMin, dfMax);
7210
0
            break;
7211
0
        case GDT_Int32:
7212
0
            ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
7213
0
                                                   nBlockXSize, sNoDataValues,
7214
0
                                                   pabyMaskData, dfMin, dfMax);
7215
0
            break;
7216
0
        case GDT_UInt64:
7217
0
            ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
7218
0
                                                    nBlockXSize, sNoDataValues,
7219
0
                                                    pabyMaskData, dfMin, dfMax);
7220
0
            break;
7221
0
        case GDT_Int64:
7222
0
            ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
7223
0
                                                   nBlockXSize, sNoDataValues,
7224
0
                                                   pabyMaskData, dfMin, dfMax);
7225
0
            break;
7226
0
        case GDT_Float16:
7227
0
            ComputeMinMaxGeneric<GDT_Float16, false>(
7228
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7229
0
                pabyMaskData, dfMin, dfMax);
7230
0
            break;
7231
0
        case GDT_Float32:
7232
0
            ComputeMinMaxGeneric<GDT_Float32, false>(
7233
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7234
0
                pabyMaskData, dfMin, dfMax);
7235
0
            break;
7236
0
        case GDT_Float64:
7237
0
            ComputeMinMaxGeneric<GDT_Float64, false>(
7238
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7239
0
                pabyMaskData, dfMin, dfMax);
7240
0
            break;
7241
0
        case GDT_CInt16:
7242
0
            ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
7243
0
                                                    nBlockXSize, sNoDataValues,
7244
0
                                                    pabyMaskData, dfMin, dfMax);
7245
0
            break;
7246
0
        case GDT_CInt32:
7247
0
            ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
7248
0
                                                    nBlockXSize, sNoDataValues,
7249
0
                                                    pabyMaskData, dfMin, dfMax);
7250
0
            break;
7251
0
        case GDT_CFloat16:
7252
0
            ComputeMinMaxGeneric<GDT_CFloat16, false>(
7253
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7254
0
                pabyMaskData, dfMin, dfMax);
7255
0
            break;
7256
0
        case GDT_CFloat32:
7257
0
            ComputeMinMaxGeneric<GDT_CFloat32, false>(
7258
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7259
0
                pabyMaskData, dfMin, dfMax);
7260
0
            break;
7261
0
        case GDT_CFloat64:
7262
0
            ComputeMinMaxGeneric<GDT_CFloat64, false>(
7263
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7264
0
                pabyMaskData, dfMin, dfMax);
7265
0
            break;
7266
0
        case GDT_TypeCount:
7267
0
            CPLAssert(false);
7268
0
            break;
7269
0
    }
7270
0
}
7271
7272
static bool ComputeMinMaxGenericIterBlocks(
7273
    GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
7274
    GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
7275
    const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
7276
    double &dfMin, double &dfMax)
7277
7278
0
{
7279
0
    GByte *pabyMaskData = nullptr;
7280
0
    int nBlockXSize, nBlockYSize;
7281
0
    poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7282
7283
0
    if (poMaskBand)
7284
0
    {
7285
0
        pabyMaskData =
7286
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7287
0
        if (!pabyMaskData)
7288
0
        {
7289
0
            return false;
7290
0
        }
7291
0
    }
7292
7293
0
    for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7294
0
         iSampleBlock += nSampleRate)
7295
0
    {
7296
0
        const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7297
0
        const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7298
7299
0
        GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7300
0
        if (poBlock == nullptr)
7301
0
        {
7302
0
            CPLFree(pabyMaskData);
7303
0
            return false;
7304
0
        }
7305
7306
0
        void *const pData = poBlock->GetDataRef();
7307
7308
0
        int nXCheck = 0, nYCheck = 0;
7309
0
        poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7310
7311
0
        if (poMaskBand &&
7312
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7313
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
7314
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7315
0
                                 nBlockXSize, nullptr) != CE_None)
7316
0
        {
7317
0
            poBlock->DropLock();
7318
0
            CPLFree(pabyMaskData);
7319
0
            return false;
7320
0
        }
7321
7322
0
        ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7323
0
                             nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
7324
0
                             dfMax);
7325
7326
0
        poBlock->DropLock();
7327
0
    }
7328
7329
0
    CPLFree(pabyMaskData);
7330
0
    return true;
7331
0
}
7332
7333
/**
7334
 * \brief Compute the min/max values for a band.
7335
 *
7336
 * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7337
 * be trusted.  If it doesn't work, a subsample of blocks will be read to
7338
 * get an approximate min/max.  If the band has a nodata value it will
7339
 * be excluded from the minimum and maximum.
7340
 *
7341
 * If bApprox is FALSE, then all pixels will be read and used to compute
7342
 * an exact range.
7343
 *
7344
 * This method is the same as the C function GDALComputeRasterMinMax().
7345
 *
7346
 * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7347
 * FALSE.
7348
 * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7349
 * maximum (adfMinMax[1]) are returned.
7350
 *
7351
 * @return CE_None on success or CE_Failure on failure.
7352
 */
7353
7354
CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7355
0
{
7356
    /* -------------------------------------------------------------------- */
7357
    /*      Does the driver already know the min/max?                       */
7358
    /* -------------------------------------------------------------------- */
7359
0
    if (bApproxOK)
7360
0
    {
7361
0
        int bSuccessMin = FALSE;
7362
0
        int bSuccessMax = FALSE;
7363
7364
0
        double dfMin = GetMinimum(&bSuccessMin);
7365
0
        double dfMax = GetMaximum(&bSuccessMax);
7366
7367
0
        if (bSuccessMin && bSuccessMax)
7368
0
        {
7369
0
            adfMinMax[0] = dfMin;
7370
0
            adfMinMax[1] = dfMax;
7371
0
            return CE_None;
7372
0
        }
7373
0
    }
7374
7375
    /* -------------------------------------------------------------------- */
7376
    /*      If we have overview bands, use them for min/max.                */
7377
    /* -------------------------------------------------------------------- */
7378
    // cppcheck-suppress knownConditionTrueFalse
7379
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7380
0
    {
7381
0
        GDALRasterBand *poBand =
7382
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7383
7384
0
        if (poBand != this)
7385
0
            return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7386
0
    }
7387
7388
    /* -------------------------------------------------------------------- */
7389
    /*      Read actual data and compute minimum and maximum.               */
7390
    /* -------------------------------------------------------------------- */
7391
0
    GDALNoDataValues sNoDataValues(this, eDataType);
7392
0
    GDALRasterBand *poMaskBand = nullptr;
7393
0
    if (!sNoDataValues.bGotNoDataValue)
7394
0
    {
7395
0
        const int l_nMaskFlags = GetMaskFlags();
7396
0
        if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7397
0
            GetColorInterpretation() != GCI_AlphaBand)
7398
0
        {
7399
0
            poMaskBand = GetMaskBand();
7400
0
        }
7401
0
    }
7402
7403
0
    bool bSignedByte = false;
7404
0
    if (eDataType == GDT_Byte)
7405
0
    {
7406
0
        EnablePixelTypeSignedByteWarning(false);
7407
0
        const char *pszPixelType =
7408
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7409
0
        EnablePixelTypeSignedByteWarning(true);
7410
0
        bSignedByte =
7411
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7412
0
    }
7413
7414
0
    GDALRasterIOExtraArg sExtraArg;
7415
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7416
7417
0
    GUInt32 nMin = (eDataType == GDT_Byte)
7418
0
                       ? 255
7419
0
                       : 65535;  // used for GByte & GUInt16 cases
7420
0
    GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
7421
0
    GInt16 nMinInt16 =
7422
0
        std::numeric_limits<GInt16>::max();  // used for GInt16 case
7423
0
    GInt16 nMaxInt16 =
7424
0
        std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
7425
0
    double dfMin =
7426
0
        std::numeric_limits<double>::infinity();  // used for generic code path
7427
0
    double dfMax =
7428
0
        -std::numeric_limits<double>::infinity();  // used for generic code path
7429
0
    const bool bUseOptimizedPath =
7430
0
        !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7431
0
                        eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7432
7433
0
    const auto ComputeMinMaxForBlock =
7434
0
        [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
7435
0
         &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
7436
0
                     int nYCheck)
7437
0
    {
7438
0
        if (eDataType == GDT_Byte && !bSignedByte)
7439
0
        {
7440
0
            const bool bHasNoData =
7441
0
                sNoDataValues.bGotNoDataValue &&
7442
0
                GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
7443
0
                static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
7444
0
                    sNoDataValues.dfNoDataValue;
7445
0
            const GUInt32 nNoDataValue =
7446
0
                bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
7447
0
                           : 0;
7448
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
7449
0
            ComputeStatisticsInternal<GByte,
7450
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
7451
0
                f(nXCheck, nBufferWidth, nYCheck,
7452
0
                  static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7453
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7454
0
        }
7455
0
        else if (eDataType == GDT_UInt16)
7456
0
        {
7457
0
            const bool bHasNoData =
7458
0
                sNoDataValues.bGotNoDataValue &&
7459
0
                GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
7460
0
                static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
7461
0
                    sNoDataValues.dfNoDataValue;
7462
0
            const GUInt32 nNoDataValue =
7463
0
                bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
7464
0
                           : 0;
7465
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
7466
0
            ComputeStatisticsInternal<GUInt16,
7467
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
7468
0
                f(nXCheck, nBufferWidth, nYCheck,
7469
0
                  static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7470
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7471
0
        }
7472
0
        else if (eDataType == GDT_Int16)
7473
0
        {
7474
0
            const bool bHasNoData =
7475
0
                sNoDataValues.bGotNoDataValue &&
7476
0
                GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
7477
0
                static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
7478
0
                    sNoDataValues.dfNoDataValue;
7479
0
            if (bHasNoData)
7480
0
            {
7481
0
                const int16_t nNoDataValue =
7482
0
                    static_cast<int16_t>(sNoDataValues.dfNoDataValue);
7483
0
                for (int iY = 0; iY < nYCheck; iY++)
7484
0
                {
7485
0
                    ComputeMinMax<int16_t, true>(
7486
0
                        static_cast<const int16_t *>(pData) +
7487
0
                            static_cast<size_t>(iY) * nBufferWidth,
7488
0
                        nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7489
0
                }
7490
0
            }
7491
0
            else
7492
0
            {
7493
0
                for (int iY = 0; iY < nYCheck; iY++)
7494
0
                {
7495
0
                    ComputeMinMax<int16_t, false>(
7496
0
                        static_cast<const int16_t *>(pData) +
7497
0
                            static_cast<size_t>(iY) * nBufferWidth,
7498
0
                        nXCheck, 0, &nMinInt16, &nMaxInt16);
7499
0
                }
7500
0
            }
7501
0
        }
7502
0
    };
7503
7504
0
    if (bApproxOK && HasArbitraryOverviews())
7505
0
    {
7506
        /* --------------------------------------------------------------------
7507
         */
7508
        /*      Figure out how much the image should be reduced to get an */
7509
        /*      approximate value. */
7510
        /* --------------------------------------------------------------------
7511
         */
7512
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7513
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7514
7515
0
        int nXReduced = nRasterXSize;
7516
0
        int nYReduced = nRasterYSize;
7517
0
        if (dfReduction > 1.0)
7518
0
        {
7519
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7520
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7521
7522
            // Catch the case of huge resizing ratios here
7523
0
            if (nXReduced == 0)
7524
0
                nXReduced = 1;
7525
0
            if (nYReduced == 0)
7526
0
                nYReduced = 1;
7527
0
        }
7528
7529
0
        void *const pData = CPLMalloc(cpl::fits_on<int>(
7530
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7531
7532
0
        const CPLErr eErr =
7533
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7534
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7535
0
        if (eErr != CE_None)
7536
0
        {
7537
0
            CPLFree(pData);
7538
0
            return eErr;
7539
0
        }
7540
7541
0
        GByte *pabyMaskData = nullptr;
7542
0
        if (poMaskBand)
7543
0
        {
7544
0
            pabyMaskData =
7545
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7546
0
            if (!pabyMaskData)
7547
0
            {
7548
0
                CPLFree(pData);
7549
0
                return CE_Failure;
7550
0
            }
7551
7552
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7553
0
                                     pabyMaskData, nXReduced, nYReduced,
7554
0
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
7555
0
            {
7556
0
                CPLFree(pData);
7557
0
                CPLFree(pabyMaskData);
7558
0
                return CE_Failure;
7559
0
            }
7560
0
        }
7561
7562
0
        if (bUseOptimizedPath)
7563
0
        {
7564
0
            ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7565
0
        }
7566
0
        else
7567
0
        {
7568
0
            ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
7569
0
                                 nYReduced, nXReduced, sNoDataValues,
7570
0
                                 pabyMaskData, dfMin, dfMax);
7571
0
        }
7572
7573
0
        CPLFree(pData);
7574
0
        CPLFree(pabyMaskData);
7575
0
    }
7576
7577
0
    else  // No arbitrary overviews
7578
0
    {
7579
0
        if (!InitBlockInfo())
7580
0
            return CE_Failure;
7581
7582
        /* --------------------------------------------------------------------
7583
         */
7584
        /*      Figure out the ratio of blocks we will read to get an */
7585
        /*      approximate value. */
7586
        /* --------------------------------------------------------------------
7587
         */
7588
0
        int nSampleRate = 1;
7589
7590
0
        if (bApproxOK)
7591
0
        {
7592
0
            nSampleRate = static_cast<int>(std::max(
7593
0
                1.0,
7594
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7595
            // We want to avoid probing only the first column of blocks for
7596
            // a square shaped raster, because it is not unlikely that it may
7597
            // be padding only (#6378).
7598
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7599
0
                nSampleRate += 1;
7600
0
        }
7601
7602
0
        if (bUseOptimizedPath)
7603
0
        {
7604
0
            for (GIntBig iSampleBlock = 0;
7605
0
                 iSampleBlock <
7606
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7607
0
                 iSampleBlock += nSampleRate)
7608
0
            {
7609
0
                const int iYBlock =
7610
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
7611
0
                const int iXBlock =
7612
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
7613
7614
0
                GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7615
0
                if (poBlock == nullptr)
7616
0
                    return CE_Failure;
7617
7618
0
                void *const pData = poBlock->GetDataRef();
7619
7620
0
                int nXCheck = 0, nYCheck = 0;
7621
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7622
7623
0
                ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7624
7625
0
                poBlock->DropLock();
7626
7627
0
                if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7628
0
                    nMax == 255)
7629
0
                    break;
7630
0
            }
7631
0
        }
7632
0
        else
7633
0
        {
7634
0
            const GIntBig nTotalBlocks =
7635
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7636
0
            if (!ComputeMinMaxGenericIterBlocks(
7637
0
                    this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7638
0
                    nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
7639
0
            {
7640
0
                return CE_Failure;
7641
0
            }
7642
0
        }
7643
0
    }
7644
7645
0
    if (bUseOptimizedPath)
7646
0
    {
7647
0
        if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7648
0
        {
7649
0
            dfMin = nMin;
7650
0
            dfMax = nMax;
7651
0
        }
7652
0
        else if (eDataType == GDT_Int16)
7653
0
        {
7654
0
            dfMin = nMinInt16;
7655
0
            dfMax = nMaxInt16;
7656
0
        }
7657
0
    }
7658
7659
0
    if (dfMin > dfMax)
7660
0
    {
7661
0
        adfMinMax[0] = 0;
7662
0
        adfMinMax[1] = 0;
7663
0
        ReportError(
7664
0
            CE_Failure, CPLE_AppDefined,
7665
0
            "Failed to compute min/max, no valid pixels found in sampling.");
7666
0
        return CE_Failure;
7667
0
    }
7668
7669
0
    adfMinMax[0] = dfMin;
7670
0
    adfMinMax[1] = dfMax;
7671
7672
0
    return CE_None;
7673
0
}
7674
7675
/************************************************************************/
7676
/*                      GDALComputeRasterMinMax()                       */
7677
/************************************************************************/
7678
7679
/**
7680
 * \brief Compute the min/max values for a band.
7681
 *
7682
 * @see GDALRasterBand::ComputeRasterMinMax()
7683
 *
7684
 * @note Prior to GDAL 3.6, this function returned void
7685
 */
7686
7687
CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7688
                                           double adfMinMax[2])
7689
7690
0
{
7691
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7692
7693
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7694
0
    return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7695
0
}
7696
7697
/************************************************************************/
7698
/*                    ComputeRasterMinMaxLocation()                     */
7699
/************************************************************************/
7700
7701
/**
7702
 * \brief Compute the min/max values for a band, and their location.
7703
 *
7704
 * Pixels whose value matches the nodata value or are masked by the mask
7705
 * band are ignored.
7706
 *
7707
 * If the minimum or maximum value is hit in several locations, it is not
7708
 * specified which one will be returned.
7709
 *
7710
 * @param[out] pdfMin Pointer to the minimum value.
7711
 * @param[out] pdfMax Pointer to the maximum value.
7712
 * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7713
 * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7714
 * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7715
 * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7716
 *
7717
 * @return CE_None in case of success, CE_Warning if there are no valid values,
7718
 *         CE_Failure in case of error.
7719
 *
7720
 * @since GDAL 3.11
7721
 */
7722
7723
CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7724
                                                   double *pdfMax, int *pnMinX,
7725
                                                   int *pnMinY, int *pnMaxX,
7726
                                                   int *pnMaxY)
7727
0
{
7728
0
    int nMinX = -1;
7729
0
    int nMinY = -1;
7730
0
    int nMaxX = -1;
7731
0
    int nMaxY = -1;
7732
0
    double dfMin = std::numeric_limits<double>::infinity();
7733
0
    double dfMax = -std::numeric_limits<double>::infinity();
7734
0
    if (pdfMin)
7735
0
        *pdfMin = dfMin;
7736
0
    if (pdfMax)
7737
0
        *pdfMax = dfMax;
7738
0
    if (pnMinX)
7739
0
        *pnMinX = nMinX;
7740
0
    if (pnMinY)
7741
0
        *pnMinY = nMinY;
7742
0
    if (pnMaxX)
7743
0
        *pnMaxX = nMaxX;
7744
0
    if (pnMaxY)
7745
0
        *pnMaxY = nMaxY;
7746
7747
0
    if (GDALDataTypeIsComplex(eDataType))
7748
0
    {
7749
0
        CPLError(CE_Failure, CPLE_NotSupported,
7750
0
                 "Complex data type not supported");
7751
0
        return CE_Failure;
7752
0
    }
7753
7754
0
    if (!InitBlockInfo())
7755
0
        return CE_Failure;
7756
7757
0
    GDALNoDataValues sNoDataValues(this, eDataType);
7758
0
    GDALRasterBand *poMaskBand = nullptr;
7759
0
    if (!sNoDataValues.bGotNoDataValue)
7760
0
    {
7761
0
        const int l_nMaskFlags = GetMaskFlags();
7762
0
        if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7763
0
            GetColorInterpretation() != GCI_AlphaBand)
7764
0
        {
7765
0
            poMaskBand = GetMaskBand();
7766
0
        }
7767
0
    }
7768
7769
0
    bool bSignedByte = false;
7770
0
    if (eDataType == GDT_Byte)
7771
0
    {
7772
0
        EnablePixelTypeSignedByteWarning(false);
7773
0
        const char *pszPixelType =
7774
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7775
0
        EnablePixelTypeSignedByteWarning(true);
7776
0
        bSignedByte =
7777
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7778
0
    }
7779
7780
0
    GByte *pabyMaskData = nullptr;
7781
0
    if (poMaskBand)
7782
0
    {
7783
0
        pabyMaskData =
7784
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7785
0
        if (!pabyMaskData)
7786
0
        {
7787
0
            return CE_Failure;
7788
0
        }
7789
0
    }
7790
7791
0
    const GIntBig nTotalBlocks =
7792
0
        static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7793
0
    bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7794
0
    bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7795
0
    for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7796
0
    {
7797
0
        const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7798
0
        const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7799
7800
0
        GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7801
0
        if (poBlock == nullptr)
7802
0
        {
7803
0
            CPLFree(pabyMaskData);
7804
0
            return CE_Failure;
7805
0
        }
7806
7807
0
        void *const pData = poBlock->GetDataRef();
7808
7809
0
        int nXCheck = 0, nYCheck = 0;
7810
0
        GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7811
7812
0
        if (poMaskBand &&
7813
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7814
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
7815
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7816
0
                                 nBlockXSize, nullptr) != CE_None)
7817
0
        {
7818
0
            poBlock->DropLock();
7819
0
            CPLFree(pabyMaskData);
7820
0
            return CE_Failure;
7821
0
        }
7822
7823
0
        if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7824
0
        {
7825
0
            for (int iY = 0; iY < nYCheck; ++iY)
7826
0
            {
7827
0
                for (int iX = 0; iX < nXCheck; ++iX)
7828
0
                {
7829
0
                    const GPtrDiff_t iOffset =
7830
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7831
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
7832
0
                        continue;
7833
0
                    bool bValid = true;
7834
0
                    double dfValue =
7835
0
                        GetPixelValue(eDataType, bSignedByte, pData, iOffset,
7836
0
                                      sNoDataValues, bValid);
7837
0
                    if (!bValid)
7838
0
                        continue;
7839
0
                    if (dfValue < dfMin)
7840
0
                    {
7841
0
                        dfMin = dfValue;
7842
0
                        nMinX = iXBlock * nBlockXSize + iX;
7843
0
                        nMinY = iYBlock * nBlockYSize + iY;
7844
0
                    }
7845
0
                    if (dfValue > dfMax)
7846
0
                    {
7847
0
                        dfMax = dfValue;
7848
0
                        nMaxX = iXBlock * nBlockXSize + iX;
7849
0
                        nMaxY = iYBlock * nBlockYSize + iY;
7850
0
                    }
7851
0
                }
7852
0
            }
7853
0
        }
7854
0
        else
7855
0
        {
7856
0
            size_t pos_min = 0;
7857
0
            size_t pos_max = 0;
7858
0
            const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7859
0
            if (bNeedsMin && bNeedsMax)
7860
0
            {
7861
0
                std::tie(pos_min, pos_max) = gdal::minmax_element(
7862
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7863
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
7864
0
                    sNoDataValues.dfNoDataValue);
7865
0
            }
7866
0
            else if (bNeedsMin)
7867
0
            {
7868
0
                pos_min = gdal::min_element(
7869
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7870
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
7871
0
                    sNoDataValues.dfNoDataValue);
7872
0
            }
7873
0
            else if (bNeedsMax)
7874
0
            {
7875
0
                pos_max = gdal::max_element(
7876
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7877
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
7878
0
                    sNoDataValues.dfNoDataValue);
7879
0
            }
7880
7881
0
            if (bNeedsMin)
7882
0
            {
7883
0
                const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7884
0
                const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7885
0
                bool bValid = true;
7886
0
                const double dfMinValueBlock =
7887
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_min,
7888
0
                                  sNoDataValues, bValid);
7889
0
                if (bValid && dfMinValueBlock < dfMin)
7890
0
                {
7891
0
                    dfMin = dfMinValueBlock;
7892
0
                    nMinX = iXBlock * nBlockXSize + nMinXBlock;
7893
0
                    nMinY = iYBlock * nBlockYSize + nMinYBlock;
7894
0
                }
7895
0
            }
7896
7897
0
            if (bNeedsMax)
7898
0
            {
7899
0
                const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7900
0
                const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7901
0
                bool bValid = true;
7902
0
                const double dfMaxValueBlock =
7903
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_max,
7904
0
                                  sNoDataValues, bValid);
7905
0
                if (bValid && dfMaxValueBlock > dfMax)
7906
0
                {
7907
0
                    dfMax = dfMaxValueBlock;
7908
0
                    nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7909
0
                    nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7910
0
                }
7911
0
            }
7912
0
        }
7913
7914
0
        poBlock->DropLock();
7915
7916
0
        if (eDataType == GDT_Byte)
7917
0
        {
7918
0
            if (bNeedsMin && dfMin == 0)
7919
0
            {
7920
0
                bNeedsMin = false;
7921
0
            }
7922
0
            if (bNeedsMax && dfMax == 255)
7923
0
            {
7924
0
                bNeedsMax = false;
7925
0
            }
7926
0
            if (!bNeedsMin && !bNeedsMax)
7927
0
            {
7928
0
                break;
7929
0
            }
7930
0
        }
7931
0
    }
7932
7933
0
    CPLFree(pabyMaskData);
7934
7935
0
    if (pdfMin)
7936
0
        *pdfMin = dfMin;
7937
0
    if (pdfMax)
7938
0
        *pdfMax = dfMax;
7939
0
    if (pnMinX)
7940
0
        *pnMinX = nMinX;
7941
0
    if (pnMinY)
7942
0
        *pnMinY = nMinY;
7943
0
    if (pnMaxX)
7944
0
        *pnMaxX = nMaxX;
7945
0
    if (pnMaxY)
7946
0
        *pnMaxY = nMaxY;
7947
0
    return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
7948
0
                                                                  : CE_None;
7949
0
}
7950
7951
/************************************************************************/
7952
/*                    GDALComputeRasterMinMaxLocation()                 */
7953
/************************************************************************/
7954
7955
/**
7956
 * \brief Compute the min/max values for a band, and their location.
7957
 *
7958
 * @see GDALRasterBand::ComputeRasterMinMax()
7959
 * @since GDAL 3.11
7960
 */
7961
7962
CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
7963
                                       double *pdfMax, int *pnMinX, int *pnMinY,
7964
                                       int *pnMaxX, int *pnMaxY)
7965
7966
0
{
7967
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
7968
7969
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7970
0
    return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
7971
0
                                               pnMaxX, pnMaxY);
7972
0
}
7973
7974
/************************************************************************/
7975
/*                        SetDefaultHistogram()                         */
7976
/************************************************************************/
7977
7978
/* FIXME : add proper documentation */
7979
/**
7980
 * \brief Set default histogram.
7981
 *
7982
 * This method is the same as the C function GDALSetDefaultHistogram() and
7983
 * GDALSetDefaultHistogramEx()
7984
 */
7985
CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
7986
                                           double /* dfMax */,
7987
                                           int /* nBuckets */,
7988
                                           GUIntBig * /* panHistogram */)
7989
7990
0
{
7991
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
7992
0
        ReportError(CE_Failure, CPLE_NotSupported,
7993
0
                    "SetDefaultHistogram() not implemented for this format.");
7994
7995
0
    return CE_Failure;
7996
0
}
7997
7998
/************************************************************************/
7999
/*                      GDALSetDefaultHistogram()                       */
8000
/************************************************************************/
8001
8002
/**
8003
 * \brief Set default histogram.
8004
 *
8005
 * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8006
 * 2 billion.
8007
 *
8008
 * @see GDALRasterBand::SetDefaultHistogram()
8009
 * @see GDALSetRasterHistogramEx()
8010
 */
8011
8012
CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8013
                                           double dfMax, int nBuckets,
8014
                                           int *panHistogram)
8015
8016
0
{
8017
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8018
8019
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8020
8021
0
    GUIntBig *panHistogramTemp =
8022
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8023
0
    if (panHistogramTemp == nullptr)
8024
0
    {
8025
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8026
0
                            "Out of memory in GDALSetDefaultHistogram().");
8027
0
        return CE_Failure;
8028
0
    }
8029
8030
0
    for (int i = 0; i < nBuckets; ++i)
8031
0
    {
8032
0
        panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8033
0
    }
8034
8035
0
    const CPLErr eErr =
8036
0
        poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8037
8038
0
    CPLFree(panHistogramTemp);
8039
8040
0
    return eErr;
8041
0
}
8042
8043
/************************************************************************/
8044
/*                     GDALSetDefaultHistogramEx()                      */
8045
/************************************************************************/
8046
8047
/**
8048
 * \brief Set default histogram.
8049
 *
8050
 * @see GDALRasterBand::SetDefaultHistogram()
8051
 *
8052
 * @since GDAL 2.0
8053
 */
8054
8055
CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8056
                                             double dfMin, double dfMax,
8057
                                             int nBuckets,
8058
                                             GUIntBig *panHistogram)
8059
8060
0
{
8061
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8062
8063
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8064
0
    return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8065
0
}
8066
8067
/************************************************************************/
8068
/*                           GetDefaultRAT()                            */
8069
/************************************************************************/
8070
8071
/**
8072
 * \brief Fetch default Raster Attribute Table.
8073
 *
8074
 * A RAT will be returned if there is a default one associated with the
8075
 * band, otherwise NULL is returned.  The returned RAT is owned by the
8076
 * band and should not be deleted by the application.
8077
 *
8078
 * This method is the same as the C function GDALGetDefaultRAT().
8079
 *
8080
 * @return NULL, or a pointer to an internal RAT owned by the band.
8081
 */
8082
8083
GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8084
8085
0
{
8086
0
    return nullptr;
8087
0
}
8088
8089
/************************************************************************/
8090
/*                         GDALGetDefaultRAT()                          */
8091
/************************************************************************/
8092
8093
/**
8094
 * \brief Fetch default Raster Attribute Table.
8095
 *
8096
 * @see GDALRasterBand::GetDefaultRAT()
8097
 */
8098
8099
GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8100
8101
0
{
8102
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8103
8104
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8105
0
    return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8106
0
}
8107
8108
/************************************************************************/
8109
/*                           SetDefaultRAT()                            */
8110
/************************************************************************/
8111
8112
/**
8113
 * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8114
 * \brief Set default Raster Attribute Table.
8115
 *
8116
 * Associates a default RAT with the band.  If not implemented for the
8117
 * format a CPLE_NotSupported error will be issued.  If successful a copy
8118
 * of the RAT is made, the original remains owned by the caller.
8119
 *
8120
 * This method is the same as the C function GDALSetDefaultRAT().
8121
 *
8122
 * @param poRAT the RAT to assign to the band.
8123
 *
8124
 * @return CE_None on success or CE_Failure if unsupported or otherwise
8125
 * failing.
8126
 */
8127
8128
/**/
8129
/**/
8130
8131
CPLErr
8132
GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8133
0
{
8134
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8135
0
    {
8136
0
        CPLPushErrorHandler(CPLQuietErrorHandler);
8137
0
        ReportError(CE_Failure, CPLE_NotSupported,
8138
0
                    "SetDefaultRAT() not implemented for this format.");
8139
0
        CPLPopErrorHandler();
8140
0
    }
8141
0
    return CE_Failure;
8142
0
}
8143
8144
/************************************************************************/
8145
/*                         GDALSetDefaultRAT()                          */
8146
/************************************************************************/
8147
8148
/**
8149
 * \brief Set default Raster Attribute Table.
8150
 *
8151
 * @see GDALRasterBand::GDALSetDefaultRAT()
8152
 */
8153
8154
CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
8155
                                     GDALRasterAttributeTableH hRAT)
8156
8157
0
{
8158
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
8159
8160
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8161
8162
0
    return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
8163
0
}
8164
8165
/************************************************************************/
8166
/*                            GetMaskBand()                             */
8167
/************************************************************************/
8168
8169
/**
8170
 * \brief Return the mask band associated with the band.
8171
 *
8172
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
8173
 * that returns one of four default implementations :
8174
 * <ul>
8175
 * <li>If a corresponding .msk file exists it will be used for the mask band.
8176
 * </li>
8177
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8178
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8179
 * GMF_NODATA | GMF_PER_DATASET.
8180
 * </li>
8181
 * <li>If the band has a nodata value set, an instance of the new
8182
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8183
 * GMF_NODATA.
8184
 * </li>
8185
 * <li>If there is no nodata value, but the dataset has an alpha band that seems
8186
 * to apply to this band (specific rules yet to be determined) and that is of
8187
 * type GDT_Byte then that alpha band will be returned, and the flags
8188
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8189
 * </li>
8190
 * <li>If neither of the above apply, an instance of the new
8191
 * GDALAllValidRasterBand class will be returned that has 255 values for all
8192
 * pixels. The null flags will return GMF_ALL_VALID.
8193
 * </li>
8194
 * </ul>
8195
 *
8196
 * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
8197
 * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
8198
 *
8199
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8200
 * dataset, with the same name as the main dataset and suffixed with .msk,
8201
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8202
 * main dataset.
8203
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8204
 * level, where xx matches the band number of a band of the main dataset. The
8205
 * value of those items is a combination of the flags GMF_ALL_VALID,
8206
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8207
 * a band, then the other rules explained above will be used to generate a
8208
 * on-the-fly mask band.
8209
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8210
 *
8211
 * This method is the same as the C function GDALGetMaskBand().
8212
 *
8213
 * @return a valid mask band.
8214
 *
8215
 * @since GDAL 1.5.0
8216
 *
8217
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8218
 *
8219
 */
8220
GDALRasterBand *GDALRasterBand::GetMaskBand()
8221
8222
0
{
8223
0
    const auto HasNoData = [this]()
8224
0
    {
8225
0
        int bHaveNoDataRaw = FALSE;
8226
0
        bool bHaveNoData = false;
8227
0
        if (eDataType == GDT_Int64)
8228
0
        {
8229
0
            CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
8230
0
            bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8231
0
        }
8232
0
        else if (eDataType == GDT_UInt64)
8233
0
        {
8234
0
            CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
8235
0
            bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8236
0
        }
8237
0
        else
8238
0
        {
8239
0
            const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
8240
0
            if (bHaveNoDataRaw &&
8241
0
                GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
8242
0
            {
8243
0
                bHaveNoData = true;
8244
0
            }
8245
0
        }
8246
0
        return bHaveNoData;
8247
0
    };
8248
8249
0
    if (poMask != nullptr)
8250
0
    {
8251
0
        if (poMask.IsOwned())
8252
0
        {
8253
0
            if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
8254
0
            {
8255
0
                if (HasNoData())
8256
0
                {
8257
0
                    InvalidateMaskBand();
8258
0
                }
8259
0
            }
8260
0
            else if (auto poNoDataMaskBand =
8261
0
                         dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
8262
0
            {
8263
0
                int bHaveNoDataRaw = FALSE;
8264
0
                bool bIsSame = false;
8265
0
                if (eDataType == GDT_Int64)
8266
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
8267
0
                                  GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
8268
0
                              bHaveNoDataRaw;
8269
0
                else if (eDataType == GDT_UInt64)
8270
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8271
0
                                  GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8272
0
                              bHaveNoDataRaw;
8273
0
                else
8274
0
                {
8275
0
                    const double dfNoDataValue =
8276
0
                        GetNoDataValue(&bHaveNoDataRaw);
8277
0
                    if (bHaveNoDataRaw)
8278
0
                    {
8279
0
                        bIsSame =
8280
0
                            std::isnan(dfNoDataValue)
8281
0
                                ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8282
0
                                : poNoDataMaskBand->m_dfNoDataValue ==
8283
0
                                      dfNoDataValue;
8284
0
                    }
8285
0
                }
8286
0
                if (!bIsSame)
8287
0
                    InvalidateMaskBand();
8288
0
            }
8289
0
        }
8290
8291
0
        if (poMask)
8292
0
            return poMask.get();
8293
0
    }
8294
8295
    /* -------------------------------------------------------------------- */
8296
    /*      Check for a mask in a .msk file.                                */
8297
    /* -------------------------------------------------------------------- */
8298
0
    if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8299
0
    {
8300
0
        poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
8301
0
        if (poMask != nullptr)
8302
0
        {
8303
0
            nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8304
0
            return poMask.get();
8305
0
        }
8306
0
    }
8307
8308
    /* -------------------------------------------------------------------- */
8309
    /*      Check for NODATA_VALUES metadata.                               */
8310
    /* -------------------------------------------------------------------- */
8311
0
    if (poDS != nullptr)
8312
0
    {
8313
0
        const char *pszGDALNoDataValues =
8314
0
            poDS->GetMetadataItem("NODATA_VALUES");
8315
0
        if (pszGDALNoDataValues != nullptr)
8316
0
        {
8317
0
            char **papszGDALNoDataValues = CSLTokenizeStringComplex(
8318
0
                pszGDALNoDataValues, " ", FALSE, FALSE);
8319
8320
            // Make sure we have as many values as bands.
8321
0
            if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
8322
0
                poDS->GetRasterCount() != 0)
8323
0
            {
8324
                // Make sure that all bands have the same data type
8325
                // This is clearly not a fundamental condition, just a
8326
                // condition to make implementation easier.
8327
0
                GDALDataType eDT = GDT_Unknown;
8328
0
                int i = 0;  // Used after for.
8329
0
                for (; i < poDS->GetRasterCount(); ++i)
8330
0
                {
8331
0
                    if (i == 0)
8332
0
                        eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8333
0
                    else if (eDT !=
8334
0
                             poDS->GetRasterBand(i + 1)->GetRasterDataType())
8335
0
                    {
8336
0
                        break;
8337
0
                    }
8338
0
                }
8339
0
                if (i == poDS->GetRasterCount())
8340
0
                {
8341
0
                    nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8342
0
                    try
8343
0
                    {
8344
0
                        poMask.reset(
8345
0
                            std::make_unique<GDALNoDataValuesMaskBand>(poDS));
8346
0
                    }
8347
0
                    catch (const std::bad_alloc &)
8348
0
                    {
8349
0
                        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8350
0
                        poMask.reset();
8351
0
                    }
8352
0
                    CSLDestroy(papszGDALNoDataValues);
8353
0
                    return poMask.get();
8354
0
                }
8355
0
                else
8356
0
                {
8357
0
                    ReportError(CE_Warning, CPLE_AppDefined,
8358
0
                                "All bands should have the same type in "
8359
0
                                "order the NODATA_VALUES metadata item "
8360
0
                                "to be used as a mask.");
8361
0
                }
8362
0
            }
8363
0
            else
8364
0
            {
8365
0
                ReportError(
8366
0
                    CE_Warning, CPLE_AppDefined,
8367
0
                    "NODATA_VALUES metadata item doesn't have the same number "
8368
0
                    "of values as the number of bands.  "
8369
0
                    "Ignoring it for mask.");
8370
0
            }
8371
8372
0
            CSLDestroy(papszGDALNoDataValues);
8373
0
        }
8374
0
    }
8375
8376
    /* -------------------------------------------------------------------- */
8377
    /*      Check for nodata case.                                          */
8378
    /* -------------------------------------------------------------------- */
8379
0
    if (HasNoData())
8380
0
    {
8381
0
        nMaskFlags = GMF_NODATA;
8382
0
        try
8383
0
        {
8384
0
            poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
8385
0
        }
8386
0
        catch (const std::bad_alloc &)
8387
0
        {
8388
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8389
0
            poMask.reset();
8390
0
        }
8391
0
        return poMask.get();
8392
0
    }
8393
8394
    /* -------------------------------------------------------------------- */
8395
    /*      Check for alpha case.                                           */
8396
    /* -------------------------------------------------------------------- */
8397
0
    if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8398
0
        this == poDS->GetRasterBand(1) &&
8399
0
        poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8400
0
    {
8401
0
        if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8402
0
        {
8403
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8404
0
            poMask.resetNotOwned(poDS->GetRasterBand(2));
8405
0
            return poMask.get();
8406
0
        }
8407
0
        else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8408
0
        {
8409
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8410
0
            try
8411
0
            {
8412
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
8413
0
                    poDS->GetRasterBand(2)));
8414
0
            }
8415
0
            catch (const std::bad_alloc &)
8416
0
            {
8417
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8418
0
                poMask.reset();
8419
0
            }
8420
0
            return poMask.get();
8421
0
        }
8422
0
    }
8423
8424
0
    if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8425
0
        (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8426
0
         this == poDS->GetRasterBand(3)) &&
8427
0
        poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8428
0
    {
8429
0
        if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8430
0
        {
8431
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8432
0
            poMask.resetNotOwned(poDS->GetRasterBand(4));
8433
0
            return poMask.get();
8434
0
        }
8435
0
        else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8436
0
        {
8437
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8438
0
            try
8439
0
            {
8440
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
8441
0
                    poDS->GetRasterBand(4)));
8442
0
            }
8443
0
            catch (const std::bad_alloc &)
8444
0
            {
8445
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8446
0
                poMask.reset();
8447
0
            }
8448
0
            return poMask.get();
8449
0
        }
8450
0
    }
8451
8452
    /* -------------------------------------------------------------------- */
8453
    /*      Fallback to all valid case.                                     */
8454
    /* -------------------------------------------------------------------- */
8455
0
    nMaskFlags = GMF_ALL_VALID;
8456
0
    try
8457
0
    {
8458
0
        poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
8459
0
    }
8460
0
    catch (const std::bad_alloc &)
8461
0
    {
8462
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8463
0
        poMask.reset();
8464
0
    }
8465
8466
0
    return poMask.get();
8467
0
}
8468
8469
/************************************************************************/
8470
/*                          GDALGetMaskBand()                           */
8471
/************************************************************************/
8472
8473
/**
8474
 * \brief Return the mask band associated with the band.
8475
 *
8476
 * @see GDALRasterBand::GetMaskBand()
8477
 */
8478
8479
GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8480
8481
0
{
8482
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8483
8484
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8485
0
    return poBand->GetMaskBand();
8486
0
}
8487
8488
/************************************************************************/
8489
/*                            GetMaskFlags()                            */
8490
/************************************************************************/
8491
8492
/**
8493
 * \brief Return the status flags of the mask band associated with the band.
8494
 *
8495
 * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8496
 * the following available definitions that may be extended in the future:
8497
 * <ul>
8498
 * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8499
 * 255. When used this will normally be the only flag set.
8500
 * </li>
8501
 * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8502
 * dataset.
8503
 * </li>
8504
 * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8505
 * and may have values other than 0 and 255.
8506
 * </li>
8507
 * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8508
 * nodata values. (mutually exclusive of GMF_ALPHA)
8509
 * </li>
8510
 * </ul>
8511
 *
8512
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
8513
 * that returns one of four default implementations:
8514
 * <ul>
8515
 * <li>If a corresponding .msk file exists it will be used for the mask band.
8516
 * </li>
8517
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8518
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8519
 * GMF_NODATA | GMF_PER_DATASET.
8520
 * </li>
8521
 * <li>If the band has a nodata value set, an instance of the new
8522
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8523
 * GMF_NODATA.
8524
 * </li>
8525
 * <li>If there is no nodata value, but the dataset has an alpha band that
8526
 * seems to apply to this band (specific rules yet to be determined) and that is
8527
 * of type GDT_Byte then that alpha band will be returned, and the flags
8528
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8529
 * </li>
8530
 * <li>If neither of the above apply, an instance of the new
8531
 * GDALAllValidRasterBand class will be returned that has 255 values for all
8532
 * pixels. The null flags will return GMF_ALL_VALID.
8533
 * </li>
8534
 * </ul>
8535
 *
8536
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8537
 * dataset, with the same name as the main dataset and suffixed with .msk,
8538
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8539
 * main dataset.
8540
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8541
 * level, where xx matches the band number of a band of the main dataset. The
8542
 * value of those items is a combination of the flags GMF_ALL_VALID,
8543
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8544
 * a band, then the other rules explained above will be used to generate a
8545
 * on-the-fly mask band.
8546
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8547
 *
8548
 * This method is the same as the C function GDALGetMaskFlags().
8549
 *
8550
 * @since GDAL 1.5.0
8551
 *
8552
 * @return a valid mask band.
8553
 *
8554
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8555
 *
8556
 */
8557
int GDALRasterBand::GetMaskFlags()
8558
8559
0
{
8560
    // If we don't have a band yet, force this now so that the masks value
8561
    // will be initialized.
8562
8563
0
    if (poMask == nullptr)
8564
0
        GetMaskBand();
8565
8566
0
    return nMaskFlags;
8567
0
}
8568
8569
/************************************************************************/
8570
/*                          GDALGetMaskFlags()                          */
8571
/************************************************************************/
8572
8573
/**
8574
 * \brief Return the status flags of the mask band associated with the band.
8575
 *
8576
 * @see GDALRasterBand::GetMaskFlags()
8577
 */
8578
8579
int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8580
8581
0
{
8582
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8583
8584
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8585
0
    return poBand->GetMaskFlags();
8586
0
}
8587
8588
/************************************************************************/
8589
/*                         InvalidateMaskBand()                         */
8590
/************************************************************************/
8591
8592
//! @cond Doxygen_Suppress
8593
void GDALRasterBand::InvalidateMaskBand()
8594
0
{
8595
0
    poMask.reset();
8596
0
    nMaskFlags = 0;
8597
0
}
8598
8599
//! @endcond
8600
8601
/************************************************************************/
8602
/*                           CreateMaskBand()                           */
8603
/************************************************************************/
8604
8605
/**
8606
 * \brief Adds a mask band to the current band
8607
 *
8608
 * The default implementation of the CreateMaskBand() method is implemented
8609
 * based on similar rules to the .ovr handling implemented using the
8610
 * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8611
 * be created with the same basename as the original file, and it will have
8612
 * as many bands as the original image (or just one for GMF_PER_DATASET).
8613
 * The mask images will be deflate compressed tiled images with the same
8614
 * block size as the original image if possible.
8615
 * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8616
 * level, where xx matches the band number of a band of the main dataset. The
8617
 * value of those items will be the one of the nFlagsIn parameter.
8618
 *
8619
 * Note that if you got a mask band with a previous call to GetMaskBand(),
8620
 * it might be invalidated by CreateMaskBand(). So you have to call
8621
 * GetMaskBand() again.
8622
 *
8623
 * This method is the same as the C function GDALCreateMaskBand().
8624
 *
8625
 * @since GDAL 1.5.0
8626
 *
8627
 * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8628
 *
8629
 * @return CE_None on success or CE_Failure on an error.
8630
 *
8631
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8632
 * @see GDALDataset::CreateMaskBand()
8633
 *
8634
 */
8635
8636
CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8637
8638
0
{
8639
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8640
0
    {
8641
0
        const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8642
0
        if (eErr != CE_None)
8643
0
            return eErr;
8644
8645
0
        InvalidateMaskBand();
8646
8647
0
        return CE_None;
8648
0
    }
8649
8650
0
    ReportError(CE_Failure, CPLE_NotSupported,
8651
0
                "CreateMaskBand() not supported for this band.");
8652
8653
0
    return CE_Failure;
8654
0
}
8655
8656
/************************************************************************/
8657
/*                         GDALCreateMaskBand()                         */
8658
/************************************************************************/
8659
8660
/**
8661
 * \brief Adds a mask band to the current band
8662
 *
8663
 * @see GDALRasterBand::CreateMaskBand()
8664
 */
8665
8666
CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8667
8668
0
{
8669
0
    VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8670
8671
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8672
0
    return poBand->CreateMaskBand(nFlags);
8673
0
}
8674
8675
/************************************************************************/
8676
/*                            IsMaskBand()                              */
8677
/************************************************************************/
8678
8679
/**
8680
 * \brief Returns whether a band is a mask band.
8681
 *
8682
 * Mask band must be understood in the broad term: it can be a per-dataset
8683
 * mask band, an alpha band, or an implicit mask band.
8684
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8685
 *
8686
 * This method is the same as the C function GDALIsMaskBand().
8687
 *
8688
 * @return true if the band is a mask band.
8689
 *
8690
 * @see GDALDataset::CreateMaskBand()
8691
 *
8692
 * @since GDAL 3.5.0
8693
 *
8694
 */
8695
8696
bool GDALRasterBand::IsMaskBand() const
8697
0
{
8698
    // The GeoTIFF driver, among others, override this method to
8699
    // also handle external .msk bands.
8700
0
    return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8701
0
           GCI_AlphaBand;
8702
0
}
8703
8704
/************************************************************************/
8705
/*                            GDALIsMaskBand()                          */
8706
/************************************************************************/
8707
8708
/**
8709
 * \brief Returns whether a band is a mask band.
8710
 *
8711
 * Mask band must be understood in the broad term: it can be a per-dataset
8712
 * mask band, an alpha band, or an implicit mask band.
8713
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8714
 *
8715
 * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8716
 *
8717
 * @return true if the band is a mask band.
8718
 *
8719
 * @see GDALRasterBand::IsMaskBand()
8720
 *
8721
 * @since GDAL 3.5.0
8722
 *
8723
 */
8724
8725
bool GDALIsMaskBand(GDALRasterBandH hBand)
8726
8727
0
{
8728
0
    VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8729
8730
0
    const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8731
0
    return poBand->IsMaskBand();
8732
0
}
8733
8734
/************************************************************************/
8735
/*                         GetMaskValueRange()                          */
8736
/************************************************************************/
8737
8738
/**
8739
 * \brief Returns the range of values that a mask band can take.
8740
 *
8741
 * @return the range of values that a mask band can take.
8742
 *
8743
 * @since GDAL 3.5.0
8744
 *
8745
 */
8746
8747
GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8748
0
{
8749
0
    return GMVR_UNKNOWN;
8750
0
}
8751
8752
/************************************************************************/
8753
/*                    GetIndexColorTranslationTo()                      */
8754
/************************************************************************/
8755
8756
/**
8757
 * \brief Compute translation table for color tables.
8758
 *
8759
 * When the raster band has a palette index, it may be useful to compute
8760
 * the "translation" of this palette to the palette of another band.
8761
 * The translation tries to do exact matching first, and then approximate
8762
 * matching if no exact matching is possible.
8763
 * This method returns a table such that table[i] = j where i is an index
8764
 * of the 'this' rasterband and j the corresponding index for the reference
8765
 * rasterband.
8766
 *
8767
 * This method is thought as internal to GDAL and is used for drivers
8768
 * like RPFTOC.
8769
 *
8770
 * The implementation only supports 1-byte palette rasterbands.
8771
 *
8772
 * @param poReferenceBand the raster band
8773
 * @param pTranslationTable an already allocated translation table (at least 256
8774
 * bytes), or NULL to let the method allocate it
8775
 * @param pApproximateMatching a pointer to a flag that is set if the matching
8776
 *                              is approximate. May be NULL.
8777
 *
8778
 * @return a translation table if the two bands are palette index and that they
8779
 * do not match or NULL in other cases. The table must be freed with CPLFree if
8780
 * NULL was passed for pTranslationTable.
8781
 */
8782
8783
unsigned char *
8784
GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8785
                                           unsigned char *pTranslationTable,
8786
                                           int *pApproximateMatching)
8787
0
{
8788
0
    if (poReferenceBand == nullptr)
8789
0
        return nullptr;
8790
8791
    // cppcheck-suppress knownConditionTrueFalse
8792
0
    if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8793
        // cppcheck-suppress knownConditionTrueFalse
8794
0
        GetColorInterpretation() == GCI_PaletteIndex &&
8795
0
        poReferenceBand->GetRasterDataType() == GDT_Byte &&
8796
0
        GetRasterDataType() == GDT_Byte)
8797
0
    {
8798
0
        const GDALColorTable *srcColorTable = GetColorTable();
8799
0
        GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8800
0
        if (srcColorTable != nullptr && destColorTable != nullptr)
8801
0
        {
8802
0
            const int nEntries = srcColorTable->GetColorEntryCount();
8803
0
            const int nRefEntries = destColorTable->GetColorEntryCount();
8804
8805
0
            int bHasNoDataValueSrc = FALSE;
8806
0
            double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8807
0
            if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8808
0
                  dfNoDataValueSrc <= 255 &&
8809
0
                  dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8810
0
                bHasNoDataValueSrc = FALSE;
8811
0
            const int noDataValueSrc =
8812
0
                bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8813
8814
0
            int bHasNoDataValueRef = FALSE;
8815
0
            const double dfNoDataValueRef =
8816
0
                poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8817
0
            if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8818
0
                  dfNoDataValueRef <= 255 &&
8819
0
                  dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8820
0
                bHasNoDataValueRef = FALSE;
8821
0
            const int noDataValueRef =
8822
0
                bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8823
8824
0
            bool samePalette = false;
8825
8826
0
            if (pApproximateMatching)
8827
0
                *pApproximateMatching = FALSE;
8828
8829
0
            if (nEntries == nRefEntries &&
8830
0
                bHasNoDataValueSrc == bHasNoDataValueRef &&
8831
0
                (bHasNoDataValueSrc == FALSE ||
8832
0
                 noDataValueSrc == noDataValueRef))
8833
0
            {
8834
0
                samePalette = true;
8835
0
                for (int i = 0; i < nEntries; ++i)
8836
0
                {
8837
0
                    if (noDataValueSrc == i)
8838
0
                        continue;
8839
0
                    const GDALColorEntry *entry =
8840
0
                        srcColorTable->GetColorEntry(i);
8841
0
                    const GDALColorEntry *entryRef =
8842
0
                        destColorTable->GetColorEntry(i);
8843
0
                    if (entry->c1 != entryRef->c1 ||
8844
0
                        entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8845
0
                    {
8846
0
                        samePalette = false;
8847
0
                    }
8848
0
                }
8849
0
            }
8850
8851
0
            if (!samePalette)
8852
0
            {
8853
0
                if (pTranslationTable == nullptr)
8854
0
                {
8855
0
                    pTranslationTable = static_cast<unsigned char *>(
8856
0
                        VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8857
0
                    if (pTranslationTable == nullptr)
8858
0
                        return nullptr;
8859
0
                }
8860
8861
                // Trying to remap the product palette on the subdataset
8862
                // palette.
8863
0
                for (int i = 0; i < nEntries; ++i)
8864
0
                {
8865
0
                    if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8866
0
                        noDataValueSrc == i)
8867
0
                        continue;
8868
0
                    const GDALColorEntry *entry =
8869
0
                        srcColorTable->GetColorEntry(i);
8870
0
                    bool bMatchFound = false;
8871
0
                    for (int j = 0; j < nRefEntries; ++j)
8872
0
                    {
8873
0
                        if (bHasNoDataValueRef && noDataValueRef == j)
8874
0
                            continue;
8875
0
                        const GDALColorEntry *entryRef =
8876
0
                            destColorTable->GetColorEntry(j);
8877
0
                        if (entry->c1 == entryRef->c1 &&
8878
0
                            entry->c2 == entryRef->c2 &&
8879
0
                            entry->c3 == entryRef->c3)
8880
0
                        {
8881
0
                            pTranslationTable[i] =
8882
0
                                static_cast<unsigned char>(j);
8883
0
                            bMatchFound = true;
8884
0
                            break;
8885
0
                        }
8886
0
                    }
8887
0
                    if (!bMatchFound)
8888
0
                    {
8889
                        // No exact match. Looking for closest color now.
8890
0
                        int best_j = 0;
8891
0
                        int best_distance = 0;
8892
0
                        if (pApproximateMatching)
8893
0
                            *pApproximateMatching = TRUE;
8894
0
                        for (int j = 0; j < nRefEntries; ++j)
8895
0
                        {
8896
0
                            const GDALColorEntry *entryRef =
8897
0
                                destColorTable->GetColorEntry(j);
8898
0
                            int distance = (entry->c1 - entryRef->c1) *
8899
0
                                               (entry->c1 - entryRef->c1) +
8900
0
                                           (entry->c2 - entryRef->c2) *
8901
0
                                               (entry->c2 - entryRef->c2) +
8902
0
                                           (entry->c3 - entryRef->c3) *
8903
0
                                               (entry->c3 - entryRef->c3);
8904
0
                            if (j == 0 || distance < best_distance)
8905
0
                            {
8906
0
                                best_j = j;
8907
0
                                best_distance = distance;
8908
0
                            }
8909
0
                        }
8910
0
                        pTranslationTable[i] =
8911
0
                            static_cast<unsigned char>(best_j);
8912
0
                    }
8913
0
                }
8914
0
                if (bHasNoDataValueRef && bHasNoDataValueSrc)
8915
0
                    pTranslationTable[noDataValueSrc] =
8916
0
                        static_cast<unsigned char>(noDataValueRef);
8917
8918
0
                return pTranslationTable;
8919
0
            }
8920
0
        }
8921
0
    }
8922
0
    return nullptr;
8923
0
}
8924
8925
/************************************************************************/
8926
/*                         SetFlushBlockErr()                           */
8927
/************************************************************************/
8928
8929
/**
8930
 * \brief Store that an error occurred while writing a dirty block.
8931
 *
8932
 * This function stores the fact that an error occurred while writing a dirty
8933
 * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8934
 * flushed when the block cache get full, it is not convenient/possible to
8935
 * report that a dirty block could not be written correctly. This function
8936
 * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8937
 * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8938
 * places where the user can easily match the error with the relevant dataset.
8939
 */
8940
8941
void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8942
0
{
8943
0
    eFlushBlockErr = eErr;
8944
0
}
8945
8946
/************************************************************************/
8947
/*                         IncDirtyBlocks()                             */
8948
/************************************************************************/
8949
8950
/**
8951
 * \brief Increment/decrement the number of dirty blocks
8952
 */
8953
8954
void GDALRasterBand::IncDirtyBlocks(int nInc)
8955
0
{
8956
0
    if (poBandBlockCache)
8957
0
        poBandBlockCache->IncDirtyBlocks(nInc);
8958
0
}
8959
8960
/************************************************************************/
8961
/*                            ReportError()                             */
8962
/************************************************************************/
8963
8964
#ifndef DOXYGEN_XML
8965
/**
8966
 * \brief Emits an error related to a raster band.
8967
 *
8968
 * This function is a wrapper for regular CPLError(). The only difference
8969
 * with CPLError() is that it prepends the error message with the dataset
8970
 * name and the band number.
8971
 *
8972
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
8973
 * @param err_no the error number (CPLE_*) from cpl_error.h.
8974
 * @param fmt a printf() style format string.  Any additional arguments
8975
 * will be treated as arguments to fill in this format in a manner
8976
 * similar to printf().
8977
 *
8978
 * @since GDAL 1.9.0
8979
 */
8980
8981
void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
8982
                                 const char *fmt, ...) const
8983
0
{
8984
0
    va_list args;
8985
8986
0
    va_start(args, fmt);
8987
8988
0
    const char *pszDSName = poDS ? poDS->GetDescription() : "";
8989
0
    pszDSName = CPLGetFilename(pszDSName);
8990
0
    if (pszDSName[0] != '\0')
8991
0
    {
8992
0
        CPLError(eErrClass, err_no, "%s",
8993
0
                 CPLString()
8994
0
                     .Printf("%s, band %d: ", pszDSName, GetBand())
8995
0
                     .append(CPLString().vPrintf(fmt, args))
8996
0
                     .c_str());
8997
0
    }
8998
0
    else
8999
0
    {
9000
0
        CPLErrorV(eErrClass, err_no, fmt, args);
9001
0
    }
9002
9003
0
    va_end(args);
9004
0
}
9005
#endif
9006
9007
/************************************************************************/
9008
/*                           GetVirtualMemAuto()                        */
9009
/************************************************************************/
9010
9011
/** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9012
 *
9013
 * Only supported on Linux and Unix systems with mmap() for now.
9014
 *
9015
 * This method allows creating a virtual memory object for a GDALRasterBand,
9016
 * that exposes the whole image data as a virtual array.
9017
 *
9018
 * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9019
 * specialized implementation, such as for raw files, may also directly use
9020
 * mechanisms of the operating system to create a view of the underlying file
9021
 * into virtual memory ( CPLVirtualMemFileMapNew() )
9022
 *
9023
 * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9024
 * offer a specialized implementation with direct file mapping, provided that
9025
 * some requirements are met :
9026
 *   - for all drivers, the dataset must be backed by a "real" file in the file
9027
 *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9028
 *     must match the native ordering of the CPU.
9029
 *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9030
 * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9031
 * the file in sequential order, and be equally spaced (which is generally the
9032
 * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9033
 * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9034
 *
9035
 * The pointer returned remains valid until CPLVirtualMemFree() is called.
9036
 * CPLVirtualMemFree() must be called before the raster band object is
9037
 * destroyed.
9038
 *
9039
 * If p is such a pointer and base_type the type matching
9040
 * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9041
 * accessed with
9042
 * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9043
 *
9044
 * This method is the same as the C GDALGetVirtualMemAuto() function.
9045
 *
9046
 * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9047
 * read/write the band.
9048
 *
9049
 * @param pnPixelSpace Output parameter giving the byte offset from the start of
9050
 * one pixel value in the buffer to the start of the next pixel value within a
9051
 * scanline.
9052
 *
9053
 * @param pnLineSpace Output parameter giving the byte offset from the start of
9054
 * one scanline in the buffer to the start of the next.
9055
 *
9056
 * @param papszOptions NULL terminated list of options.
9057
 *                     If a specialized implementation exists, defining
9058
 * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9059
 * used. On the contrary, starting with GDAL 2.2, defining
9060
 * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9061
 * being used (thus only allowing efficient implementations to be used). When
9062
 * requiring or falling back to the default implementation, the following
9063
 *                     options are available : CACHE_SIZE (in bytes, defaults to
9064
 * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9065
 * to FALSE)
9066
 *
9067
 * @return a virtual memory object that must be unreferenced by
9068
 * CPLVirtualMemFree(), or NULL in case of failure.
9069
 *
9070
 * @since GDAL 1.11
9071
 */
9072
9073
CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9074
                                                 int *pnPixelSpace,
9075
                                                 GIntBig *pnLineSpace,
9076
                                                 char **papszOptions)
9077
0
{
9078
0
    const char *pszImpl = CSLFetchNameValueDef(
9079
0
        papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9080
0
    if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9081
0
        EQUAL(pszImpl, "FALSE"))
9082
0
    {
9083
0
        return nullptr;
9084
0
    }
9085
9086
0
    const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9087
0
    const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9088
0
    if (pnPixelSpace)
9089
0
        *pnPixelSpace = nPixelSpace;
9090
0
    if (pnLineSpace)
9091
0
        *pnLineSpace = nLineSpace;
9092
0
    const size_t nCacheSize =
9093
0
        atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9094
0
    const size_t nPageSizeHint =
9095
0
        atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9096
0
    const bool bSingleThreadUsage = CPLTestBool(
9097
0
        CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9098
0
    return GDALRasterBandGetVirtualMem(
9099
0
        GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9100
0
        nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9101
0
        nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9102
0
        papszOptions);
9103
0
}
9104
9105
/************************************************************************/
9106
/*                         GDALGetVirtualMemAuto()                      */
9107
/************************************************************************/
9108
9109
/**
9110
 * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9111
 *
9112
 * @see GDALRasterBand::GetVirtualMemAuto()
9113
 */
9114
9115
CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9116
                                     int *pnPixelSpace, GIntBig *pnLineSpace,
9117
                                     CSLConstList papszOptions)
9118
0
{
9119
0
    VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9120
9121
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9122
9123
0
    return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9124
0
                                     const_cast<char **>(papszOptions));
9125
0
}
9126
9127
/************************************************************************/
9128
/*                        GDALGetDataCoverageStatus()                   */
9129
/************************************************************************/
9130
9131
/**
9132
 * \brief Get the coverage status of a sub-window of the raster.
9133
 *
9134
 * Returns whether a sub-window of the raster contains only data, only empty
9135
 * blocks or a mix of both. This function can be used to determine quickly
9136
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9137
 * be sparse.
9138
 *
9139
 * Empty blocks are blocks that are generally not physically present in the
9140
 * file, and when read through GDAL, contain only pixels whose value is the
9141
 * nodata value when it is set, or whose value is 0 when the nodata value is
9142
 * not set.
9143
 *
9144
 * The query is done in an efficient way without reading the actual pixel
9145
 * values. If not possible, or not implemented at all by the driver,
9146
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9147
 * be returned.
9148
 *
9149
 * The values that can be returned by the function are the following,
9150
 * potentially combined with the binary or operator :
9151
 * <ul>
9152
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9153
 * GetDataCoverageStatus(). This flag should be returned together with
9154
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9155
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9156
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9157
 * the queried window. This is typically identified by the concept of missing
9158
 * block in formats that supports it.
9159
 * </li>
9160
 * </ul>
9161
 *
9162
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9163
 * should be interpreted more as hint of potential presence of data. For example
9164
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9165
 * nodata value), instead of using the missing block mechanism,
9166
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9167
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9168
 *
9169
 * The nMaskFlagStop should be generally set to 0. It can be set to a
9170
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9171
 * the function as soon as the computed mask matches the nMaskFlagStop. For
9172
 * example, you can issue a request on the whole raster with nMaskFlagStop =
9173
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9174
 * the function will exit, so that you can potentially refine the requested area
9175
 * to find which particular region(s) have missing blocks.
9176
 *
9177
 * @see GDALRasterBand::GetDataCoverageStatus()
9178
 *
9179
 * @param hBand raster band
9180
 *
9181
 * @param nXOff The pixel offset to the top left corner of the region
9182
 * of the band to be queried. This would be zero to start from the left side.
9183
 *
9184
 * @param nYOff The line offset to the top left corner of the region
9185
 * of the band to be queried. This would be zero to start from the top.
9186
 *
9187
 * @param nXSize The width of the region of the band to be queried in pixels.
9188
 *
9189
 * @param nYSize The height of the region of the band to be queried in lines.
9190
 *
9191
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9192
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9193
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9194
 * as the computation of the coverage matches the mask, the computation will be
9195
 * stopped. *pdfDataPct will not be valid in that case.
9196
 *
9197
 * @param pdfDataPct Optional output parameter whose pointed value will be set
9198
 * to the (approximate) percentage in [0,100] of pixels in the queried
9199
 * sub-window that have valid values. The implementation might not always be
9200
 * able to compute it, in which case it will be set to a negative value.
9201
 *
9202
 * @return a binary-or'ed combination of possible values
9203
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9204
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9205
 *
9206
 * @note Added in GDAL 2.2
9207
 */
9208
9209
int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
9210
                                          int nYOff, int nXSize, int nYSize,
9211
                                          int nMaskFlagStop, double *pdfDataPct)
9212
0
{
9213
0
    VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
9214
0
                      GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
9215
9216
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9217
9218
0
    return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
9219
0
                                         nMaskFlagStop, pdfDataPct);
9220
0
}
9221
9222
/************************************************************************/
9223
/*                          GetDataCoverageStatus()                     */
9224
/************************************************************************/
9225
9226
/**
9227
 * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
9228
 *                                           int nYOff,
9229
 *                                           int nXSize,
9230
 *                                           int nYSize,
9231
 *                                           int nMaskFlagStop,
9232
 *                                           double* pdfDataPct)
9233
 * \brief Get the coverage status of a sub-window of the raster.
9234
 *
9235
 * Returns whether a sub-window of the raster contains only data, only empty
9236
 * blocks or a mix of both. This function can be used to determine quickly
9237
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9238
 * be sparse.
9239
 *
9240
 * Empty blocks are blocks that contain only pixels whose value is the nodata
9241
 * value when it is set, or whose value is 0 when the nodata value is not set.
9242
 *
9243
 * The query is done in an efficient way without reading the actual pixel
9244
 * values. If not possible, or not implemented at all by the driver,
9245
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9246
 * be returned.
9247
 *
9248
 * The values that can be returned by the function are the following,
9249
 * potentially combined with the binary or operator :
9250
 * <ul>
9251
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9252
 * GetDataCoverageStatus(). This flag should be returned together with
9253
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9254
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9255
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9256
 * the queried window. This is typically identified by the concept of missing
9257
 * block in formats that supports it.
9258
 * </li>
9259
 * </ul>
9260
 *
9261
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9262
 * should be interpreted more as hint of potential presence of data. For example
9263
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9264
 * nodata value), instead of using the missing block mechanism,
9265
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9266
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9267
 *
9268
 * The nMaskFlagStop should be generally set to 0. It can be set to a
9269
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9270
 * the function as soon as the computed mask matches the nMaskFlagStop. For
9271
 * example, you can issue a request on the whole raster with nMaskFlagStop =
9272
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9273
 * the function will exit, so that you can potentially refine the requested area
9274
 * to find which particular region(s) have missing blocks.
9275
 *
9276
 * @see GDALGetDataCoverageStatus()
9277
 *
9278
 * @param nXOff The pixel offset to the top left corner of the region
9279
 * of the band to be queried. This would be zero to start from the left side.
9280
 *
9281
 * @param nYOff The line offset to the top left corner of the region
9282
 * of the band to be queried. This would be zero to start from the top.
9283
 *
9284
 * @param nXSize The width of the region of the band to be queried in pixels.
9285
 *
9286
 * @param nYSize The height of the region of the band to be queried in lines.
9287
 *
9288
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9289
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9290
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9291
 * as the computation of the coverage matches the mask, the computation will be
9292
 * stopped. *pdfDataPct will not be valid in that case.
9293
 *
9294
 * @param pdfDataPct Optional output parameter whose pointed value will be set
9295
 * to the (approximate) percentage in [0,100] of pixels in the queried
9296
 * sub-window that have valid values. The implementation might not always be
9297
 * able to compute it, in which case it will be set to a negative value.
9298
 *
9299
 * @return a binary-or'ed combination of possible values
9300
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9301
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9302
 *
9303
 * @note Added in GDAL 2.2
9304
 */
9305
9306
/**
9307
 * \brief Get the coverage status of a sub-window of the raster.
9308
 *
9309
 * Returns whether a sub-window of the raster contains only data, only empty
9310
 * blocks or a mix of both. This function can be used to determine quickly
9311
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9312
 * be sparse.
9313
 *
9314
 * Empty blocks are blocks that contain only pixels whose value is the nodata
9315
 * value when it is set, or whose value is 0 when the nodata value is not set.
9316
 *
9317
 * The query is done in an efficient way without reading the actual pixel
9318
 * values. If not possible, or not implemented at all by the driver,
9319
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9320
 * be returned.
9321
 *
9322
 * The values that can be returned by the function are the following,
9323
 * potentially combined with the binary or operator :
9324
 * <ul>
9325
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9326
 * GetDataCoverageStatus(). This flag should be returned together with
9327
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9328
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9329
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9330
 * the queried window. This is typically identified by the concept of missing
9331
 * block in formats that supports it.
9332
 * </li>
9333
 * </ul>
9334
 *
9335
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9336
 * should be interpreted more as hint of potential presence of data. For example
9337
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9338
 * nodata value), instead of using the missing block mechanism,
9339
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9340
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9341
 *
9342
 * The nMaskFlagStop should be generally set to 0. It can be set to a
9343
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9344
 * the function as soon as the computed mask matches the nMaskFlagStop. For
9345
 * example, you can issue a request on the whole raster with nMaskFlagStop =
9346
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9347
 * the function will exit, so that you can potentially refine the requested area
9348
 * to find which particular region(s) have missing blocks.
9349
 *
9350
 * @see GDALGetDataCoverageStatus()
9351
 *
9352
 * @param nXOff The pixel offset to the top left corner of the region
9353
 * of the band to be queried. This would be zero to start from the left side.
9354
 *
9355
 * @param nYOff The line offset to the top left corner of the region
9356
 * of the band to be queried. This would be zero to start from the top.
9357
 *
9358
 * @param nXSize The width of the region of the band to be queried in pixels.
9359
 *
9360
 * @param nYSize The height of the region of the band to be queried in lines.
9361
 *
9362
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9363
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9364
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9365
 * as the computation of the coverage matches the mask, the computation will be
9366
 * stopped. *pdfDataPct will not be valid in that case.
9367
 *
9368
 * @param pdfDataPct Optional output parameter whose pointed value will be set
9369
 * to the (approximate) percentage in [0,100] of pixels in the queried
9370
 * sub-window that have valid values. The implementation might not always be
9371
 * able to compute it, in which case it will be set to a negative value.
9372
 *
9373
 * @return a binary-or'ed combination of possible values
9374
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9375
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9376
 *
9377
 * @note Added in GDAL 2.2
9378
 */
9379
9380
int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9381
                                          int nYSize, int nMaskFlagStop,
9382
                                          double *pdfDataPct)
9383
0
{
9384
0
    if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9385
0
        nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9386
0
        nYOff + nYSize > nRasterYSize)
9387
0
    {
9388
0
        CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9389
0
        if (pdfDataPct)
9390
0
            *pdfDataPct = 0.0;
9391
0
        return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9392
0
               GDAL_DATA_COVERAGE_STATUS_EMPTY;
9393
0
    }
9394
0
    return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9395
0
                                  pdfDataPct);
9396
0
}
9397
9398
/************************************************************************/
9399
/*                         IGetDataCoverageStatus()                     */
9400
/************************************************************************/
9401
9402
int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9403
                                           int /*nXSize*/, int /*nYSize*/,
9404
                                           int /*nMaskFlagStop*/,
9405
                                           double *pdfDataPct)
9406
0
{
9407
0
    if (pdfDataPct != nullptr)
9408
0
        *pdfDataPct = 100.0;
9409
0
    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9410
0
           GDAL_DATA_COVERAGE_STATUS_DATA;
9411
0
}
9412
9413
//! @cond Doxygen_Suppress
9414
/************************************************************************/
9415
/*                          EnterReadWrite()                            */
9416
/************************************************************************/
9417
9418
int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9419
0
{
9420
0
    if (poDS != nullptr)
9421
0
        return poDS->EnterReadWrite(eRWFlag);
9422
0
    return FALSE;
9423
0
}
9424
9425
/************************************************************************/
9426
/*                         LeaveReadWrite()                             */
9427
/************************************************************************/
9428
9429
void GDALRasterBand::LeaveReadWrite()
9430
0
{
9431
0
    if (poDS != nullptr)
9432
0
        poDS->LeaveReadWrite();
9433
0
}
9434
9435
/************************************************************************/
9436
/*                           InitRWLock()                               */
9437
/************************************************************************/
9438
9439
void GDALRasterBand::InitRWLock()
9440
0
{
9441
0
    if (poDS != nullptr)
9442
0
        poDS->InitRWLock();
9443
0
}
9444
9445
//! @endcond
9446
9447
// clang-format off
9448
9449
/**
9450
 * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9451
 * \brief Set metadata.
9452
 *
9453
 * CAUTION: depending on the format, older values of the updated information
9454
 * might still be found in the file in a "ghost" state, even if no longer
9455
 * accessible through the GDAL API. This is for example the case of the GTiff
9456
 * format (this is not a exhaustive list)
9457
 *
9458
 * The C function GDALSetMetadata() does the same thing as this method.
9459
 *
9460
 * @param papszMetadata the metadata in name=value string list format to
9461
 * apply.
9462
 * @param pszDomain the domain of interest.  Use "" or NULL for the default
9463
 * domain.
9464
 * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9465
 * metadata has been accepted, but is likely not maintained persistently
9466
 * by the underlying object between sessions.
9467
 */
9468
9469
/**
9470
 * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9471
 * \brief Set single metadata item.
9472
 *
9473
 * CAUTION: depending on the format, older values of the updated information
9474
 * might still be found in the file in a "ghost" state, even if no longer
9475
 * accessible through the GDAL API. This is for example the case of the GTiff
9476
 * format (this is not a exhaustive list)
9477
 *
9478
 * The C function GDALSetMetadataItem() does the same thing as this method.
9479
 *
9480
 * @param pszName the key for the metadata item to fetch.
9481
 * @param pszValue the value to assign to the key.
9482
 * @param pszDomain the domain to set within, use NULL for the default domain.
9483
 *
9484
 * @return CE_None on success, or an error code on failure.
9485
 */
9486
9487
// clang-format on
9488
9489
//! @cond Doxygen_Suppress
9490
/************************************************************************/
9491
/*                    EnablePixelTypeSignedByteWarning()                */
9492
/************************************************************************/
9493
9494
void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9495
0
{
9496
0
    m_bEnablePixelTypeSignedByteWarning = b;
9497
0
}
9498
9499
void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9500
0
{
9501
0
    GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9502
0
}
9503
9504
//! @endcond
9505
9506
/************************************************************************/
9507
/*                           GetMetadataItem()                          */
9508
/************************************************************************/
9509
9510
const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9511
                                            const char *pszDomain)
9512
0
{
9513
    // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9514
0
    if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9515
0
        pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9516
0
        EQUAL(pszName, "PIXELTYPE"))
9517
0
    {
9518
0
        CPLError(CE_Warning, CPLE_AppDefined,
9519
0
                 "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9520
0
                 "used to signal signed 8-bit raster. Change your code to "
9521
0
                 "test for the new GDT_Int8 data type instead.");
9522
0
    }
9523
0
    return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9524
0
}
9525
9526
/************************************************************************/
9527
/*                     GDALMDArrayFromRasterBand                        */
9528
/************************************************************************/
9529
9530
class GDALMDArrayFromRasterBand final : public GDALMDArray
9531
{
9532
    CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9533
9534
    GDALDataset *m_poDS;
9535
    GDALRasterBand *m_poBand;
9536
    GDALExtendedDataType m_dt;
9537
    std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9538
    std::string m_osUnit;
9539
    std::vector<GByte> m_pabyNoData{};
9540
    std::shared_ptr<GDALMDArray> m_varX{};
9541
    std::shared_ptr<GDALMDArray> m_varY{};
9542
    std::string m_osFilename{};
9543
9544
    bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9545
                   const size_t *count, const GInt64 *arrayStep,
9546
                   const GPtrDiff_t *bufferStride,
9547
                   const GDALExtendedDataType &bufferDataType,
9548
                   void *pBuffer) const;
9549
9550
  protected:
9551
    GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9552
0
        : GDALAbstractMDArray(std::string(),
9553
0
                              std::string(poDS->GetDescription()) +
9554
0
                                  CPLSPrintf(" band %d", poBand->GetBand())),
9555
0
          GDALMDArray(std::string(),
9556
0
                      std::string(poDS->GetDescription()) +
9557
0
                          CPLSPrintf(" band %d", poBand->GetBand())),
9558
0
          m_poDS(poDS), m_poBand(poBand),
9559
0
          m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9560
0
          m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9561
0
    {
9562
0
        m_poDS->Reference();
9563
9564
0
        int bHasNoData = false;
9565
0
        if (m_poBand->GetRasterDataType() == GDT_Int64)
9566
0
        {
9567
0
            const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9568
0
            if (bHasNoData)
9569
0
            {
9570
0
                m_pabyNoData.resize(m_dt.GetSize());
9571
0
                GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9572
0
                                m_dt.GetNumericDataType(), 0, 1);
9573
0
            }
9574
0
        }
9575
0
        else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9576
0
        {
9577
0
            const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9578
0
            if (bHasNoData)
9579
0
            {
9580
0
                m_pabyNoData.resize(m_dt.GetSize());
9581
0
                GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9582
0
                                m_dt.GetNumericDataType(), 0, 1);
9583
0
            }
9584
0
        }
9585
0
        else
9586
0
        {
9587
0
            const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9588
0
            if (bHasNoData)
9589
0
            {
9590
0
                m_pabyNoData.resize(m_dt.GetSize());
9591
0
                GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9592
0
                                m_dt.GetNumericDataType(), 0, 1);
9593
0
            }
9594
0
        }
9595
9596
0
        const int nXSize = poBand->GetXSize();
9597
0
        const int nYSize = poBand->GetYSize();
9598
9599
0
        auto poSRS = m_poDS->GetSpatialRef();
9600
0
        std::string osTypeY;
9601
0
        std::string osTypeX;
9602
0
        std::string osDirectionY;
9603
0
        std::string osDirectionX;
9604
0
        if (poSRS && poSRS->GetAxesCount() == 2)
9605
0
        {
9606
0
            const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9607
0
            OGRAxisOrientation eOrientation1 = OAO_Other;
9608
0
            poSRS->GetAxis(nullptr, 0, &eOrientation1);
9609
0
            OGRAxisOrientation eOrientation2 = OAO_Other;
9610
0
            poSRS->GetAxis(nullptr, 1, &eOrientation2);
9611
0
            if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9612
0
            {
9613
0
                if (mapping == std::vector<int>{1, 2})
9614
0
                {
9615
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9616
0
                    osDirectionY = "NORTH";
9617
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9618
0
                    osDirectionX = "EAST";
9619
0
                }
9620
0
            }
9621
0
            else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9622
0
            {
9623
0
                if (mapping == std::vector<int>{2, 1})
9624
0
                {
9625
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9626
0
                    osDirectionY = "NORTH";
9627
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9628
0
                    osDirectionX = "EAST";
9629
0
                }
9630
0
            }
9631
0
        }
9632
9633
0
        m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9634
0
                      "/", "Y", osTypeY, osDirectionY, nYSize),
9635
0
                  std::make_shared<GDALDimensionWeakIndexingVar>(
9636
0
                      "/", "X", osTypeX, osDirectionX, nXSize)};
9637
9638
0
        double adfGeoTransform[6];
9639
0
        if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
9640
0
            adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
9641
0
        {
9642
0
            m_varX = GDALMDArrayRegularlySpaced::Create(
9643
0
                "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
9644
0
                0.5);
9645
0
            m_dims[1]->SetIndexingVariable(m_varX);
9646
9647
0
            m_varY = GDALMDArrayRegularlySpaced::Create(
9648
0
                "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
9649
0
                0.5);
9650
0
            m_dims[0]->SetIndexingVariable(m_varY);
9651
0
        }
9652
0
    }
9653
9654
    bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9655
               const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9656
               const GDALExtendedDataType &bufferDataType,
9657
               void *pDstBuffer) const override;
9658
9659
    bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9660
                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9661
                const GDALExtendedDataType &bufferDataType,
9662
                const void *pSrcBuffer) override
9663
0
    {
9664
0
        return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9665
0
                         bufferStride, bufferDataType,
9666
0
                         const_cast<void *>(pSrcBuffer));
9667
0
    }
9668
9669
  public:
9670
    ~GDALMDArrayFromRasterBand()
9671
0
    {
9672
0
        m_poDS->ReleaseRef();
9673
0
    }
9674
9675
    static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9676
                                               GDALRasterBand *poBand)
9677
0
    {
9678
0
        auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9679
0
            new GDALMDArrayFromRasterBand(poDS, poBand)));
9680
0
        array->SetSelf(array);
9681
0
        return array;
9682
0
    }
9683
9684
    bool IsWritable() const override
9685
0
    {
9686
0
        return m_poDS->GetAccess() == GA_Update;
9687
0
    }
9688
9689
    const std::string &GetFilename() const override
9690
0
    {
9691
0
        return m_osFilename;
9692
0
    }
9693
9694
    const std::vector<std::shared_ptr<GDALDimension>> &
9695
    GetDimensions() const override
9696
0
    {
9697
0
        return m_dims;
9698
0
    }
9699
9700
    const GDALExtendedDataType &GetDataType() const override
9701
0
    {
9702
0
        return m_dt;
9703
0
    }
9704
9705
    const std::string &GetUnit() const override
9706
0
    {
9707
0
        return m_osUnit;
9708
0
    }
9709
9710
    const void *GetRawNoDataValue() const override
9711
0
    {
9712
0
        return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9713
0
    }
9714
9715
    double GetOffset(bool *pbHasOffset,
9716
                     GDALDataType *peStorageType) const override
9717
0
    {
9718
0
        int bHasOffset = false;
9719
0
        double dfRes = m_poBand->GetOffset(&bHasOffset);
9720
0
        if (pbHasOffset)
9721
0
            *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9722
0
        if (peStorageType)
9723
0
            *peStorageType = GDT_Unknown;
9724
0
        return dfRes;
9725
0
    }
9726
9727
    double GetScale(bool *pbHasScale,
9728
                    GDALDataType *peStorageType) const override
9729
0
    {
9730
0
        int bHasScale = false;
9731
0
        double dfRes = m_poBand->GetScale(&bHasScale);
9732
0
        if (pbHasScale)
9733
0
            *pbHasScale = CPL_TO_BOOL(bHasScale);
9734
0
        if (peStorageType)
9735
0
            *peStorageType = GDT_Unknown;
9736
0
        return dfRes;
9737
0
    }
9738
9739
    std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9740
0
    {
9741
0
        auto poSrcSRS = m_poDS->GetSpatialRef();
9742
0
        if (!poSrcSRS)
9743
0
            return nullptr;
9744
0
        auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9745
9746
0
        auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9747
0
        constexpr int iYDim = 0;
9748
0
        constexpr int iXDim = 1;
9749
0
        for (auto &m : axisMapping)
9750
0
        {
9751
0
            if (m == 1)
9752
0
                m = iXDim + 1;
9753
0
            else if (m == 2)
9754
0
                m = iYDim + 1;
9755
0
            else
9756
0
                m = 0;
9757
0
        }
9758
0
        poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9759
0
        return poSRS;
9760
0
    }
9761
9762
    std::vector<GUInt64> GetBlockSize() const override
9763
0
    {
9764
0
        int nBlockXSize = 0;
9765
0
        int nBlockYSize = 0;
9766
0
        m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9767
0
        return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9768
0
                                    static_cast<GUInt64>(nBlockXSize)};
9769
0
    }
9770
9771
    class MDIAsAttribute : public GDALAttribute
9772
    {
9773
        std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9774
        const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
9775
        std::string m_osValue;
9776
9777
      public:
9778
        MDIAsAttribute(const std::string &name, const std::string &value)
9779
0
            : GDALAbstractMDArray(std::string(), name),
9780
0
              GDALAttribute(std::string(), name), m_osValue(value)
9781
0
        {
9782
0
        }
9783
9784
        const std::vector<std::shared_ptr<GDALDimension>> &
9785
        GetDimensions() const override;
9786
9787
        const GDALExtendedDataType &GetDataType() const override
9788
0
        {
9789
0
            return m_dt;
9790
0
        }
9791
9792
        bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
9793
                   const GPtrDiff_t *,
9794
                   const GDALExtendedDataType &bufferDataType,
9795
                   void *pDstBuffer) const override
9796
0
        {
9797
0
            const char *pszStr = m_osValue.c_str();
9798
0
            GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
9799
0
                                            bufferDataType);
9800
0
            return true;
9801
0
        }
9802
    };
9803
9804
    std::vector<std::shared_ptr<GDALAttribute>>
9805
    GetAttributes(CSLConstList) const override
9806
0
    {
9807
0
        std::vector<std::shared_ptr<GDALAttribute>> res;
9808
0
        auto papszMD = m_poBand->GetMetadata();
9809
0
        for (auto iter = papszMD; iter && iter[0]; ++iter)
9810
0
        {
9811
0
            char *pszKey = nullptr;
9812
0
            const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9813
0
            if (pszKey && pszValue)
9814
0
            {
9815
0
                res.emplace_back(
9816
0
                    std::make_shared<MDIAsAttribute>(pszKey, pszValue));
9817
0
            }
9818
0
            CPLFree(pszKey);
9819
0
        }
9820
0
        return res;
9821
0
    }
9822
};
9823
9824
bool GDALMDArrayFromRasterBand::IRead(
9825
    const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
9826
    const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
9827
    void *pDstBuffer) const
9828
0
{
9829
0
    return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9830
0
                     bufferDataType, pDstBuffer);
9831
0
}
9832
9833
const std::vector<std::shared_ptr<GDALDimension>> &
9834
GDALMDArrayFromRasterBand::MDIAsAttribute::GetDimensions() const
9835
0
{
9836
0
    return m_dims;
9837
0
}
9838
9839
/************************************************************************/
9840
/*                            ReadWrite()                               */
9841
/************************************************************************/
9842
9843
bool GDALMDArrayFromRasterBand::ReadWrite(
9844
    GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
9845
    const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9846
    const GDALExtendedDataType &bufferDataType, void *pBuffer) const
9847
0
{
9848
0
    constexpr size_t iDimX = 1;
9849
0
    constexpr size_t iDimY = 0;
9850
0
    return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
9851
0
                                  arrayStartIdx, count, arrayStep, bufferStride,
9852
0
                                  bufferDataType, pBuffer);
9853
0
}
9854
9855
/************************************************************************/
9856
/*                       GDALMDRasterIOFromBand()                       */
9857
/************************************************************************/
9858
9859
bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
9860
                            size_t iDimX, size_t iDimY,
9861
                            const GUInt64 *arrayStartIdx, const size_t *count,
9862
                            const GInt64 *arrayStep,
9863
                            const GPtrDiff_t *bufferStride,
9864
                            const GDALExtendedDataType &bufferDataType,
9865
                            void *pBuffer)
9866
0
{
9867
0
    const auto eDT(bufferDataType.GetNumericDataType());
9868
0
    const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
9869
0
    const int nX =
9870
0
        arrayStep[iDimX] > 0
9871
0
            ? static_cast<int>(arrayStartIdx[iDimX])
9872
0
            : static_cast<int>(arrayStartIdx[iDimX] -
9873
0
                               (count[iDimX] - 1) * -arrayStep[iDimX]);
9874
0
    const int nY =
9875
0
        arrayStep[iDimY] > 0
9876
0
            ? static_cast<int>(arrayStartIdx[iDimY])
9877
0
            : static_cast<int>(arrayStartIdx[iDimY] -
9878
0
                               (count[iDimY] - 1) * -arrayStep[iDimY]);
9879
0
    const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
9880
0
    const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
9881
0
    GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
9882
0
    int nStrideXSign = 1;
9883
0
    if (arrayStep[iDimX] < 0)
9884
0
    {
9885
0
        pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
9886
0
        nStrideXSign = -1;
9887
0
    }
9888
0
    int nStrideYSign = 1;
9889
0
    if (arrayStep[iDimY] < 0)
9890
0
    {
9891
0
        pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
9892
0
        nStrideYSign = -1;
9893
0
    }
9894
9895
0
    return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
9896
0
                            static_cast<int>(count[iDimX]),
9897
0
                            static_cast<int>(count[iDimY]), eDT,
9898
0
                            static_cast<GSpacing>(
9899
0
                                nStrideXSign * bufferStride[iDimX] * nDTSize),
9900
0
                            static_cast<GSpacing>(
9901
0
                                nStrideYSign * bufferStride[iDimY] * nDTSize),
9902
0
                            nullptr) == CE_None;
9903
0
}
9904
9905
/************************************************************************/
9906
/*                            AsMDArray()                               */
9907
/************************************************************************/
9908
9909
/** Return a view of this raster band as a 2D multidimensional GDALMDArray.
9910
 *
9911
 * The band must be linked to a GDALDataset. If this dataset is not already
9912
 * marked as shared, it will be, so that the returned array holds a reference
9913
 * to it.
9914
 *
9915
 * If the dataset has a geotransform attached, the X and Y dimensions of the
9916
 * returned array will have an associated indexing variable.
9917
 *
9918
 * This is the same as the C function GDALRasterBandAsMDArray().
9919
 *
9920
 * The "reverse" method is GDALMDArray::AsClassicDataset().
9921
 *
9922
 * @return a new array, or nullptr.
9923
 *
9924
 * @since GDAL 3.1
9925
 */
9926
std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
9927
0
{
9928
0
    if (!poDS)
9929
0
    {
9930
0
        CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
9931
0
        return nullptr;
9932
0
    }
9933
0
    if (!poDS->GetShared())
9934
0
    {
9935
0
        poDS->MarkAsShared();
9936
0
    }
9937
0
    return GDALMDArrayFromRasterBand::Create(
9938
0
        poDS, const_cast<GDALRasterBand *>(this));
9939
0
}
9940
9941
/************************************************************************/
9942
/*                             InterpolateAtPoint()                     */
9943
/************************************************************************/
9944
9945
/**
9946
 * \brief Interpolates the value between pixels using a resampling algorithm,
9947
 * taking pixel/line coordinates as input.
9948
 *
9949
 * @param dfPixel pixel coordinate as a double, where interpolation should be done.
9950
 * @param dfLine line coordinate as a double, where interpolation should be done.
9951
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
9952
 * @param pdfRealValue pointer to real part of interpolated value
9953
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
9954
 *
9955
 * @return CE_None on success, or an error code on failure.
9956
 * @since GDAL 3.10
9957
 */
9958
9959
CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
9960
                                          GDALRIOResampleAlg eInterpolation,
9961
                                          double *pdfRealValue,
9962
                                          double *pdfImagValue) const
9963
0
{
9964
0
    if (eInterpolation != GRIORA_NearestNeighbour &&
9965
0
        eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
9966
0
        eInterpolation != GRIORA_CubicSpline)
9967
0
    {
9968
0
        CPLError(CE_Failure, CPLE_AppDefined,
9969
0
                 "Only nearest, bilinear, cubic and cubicspline interpolation "
9970
0
                 "methods "
9971
0
                 "allowed");
9972
9973
0
        return CE_Failure;
9974
0
    }
9975
9976
0
    GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
9977
0
    if (!m_poPointsCache)
9978
0
        m_poPointsCache = new GDALDoublePointsCache();
9979
9980
0
    const bool res =
9981
0
        GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
9982
0
                               dfPixel, dfLine, pdfRealValue, pdfImagValue);
9983
9984
0
    return res ? CE_None : CE_Failure;
9985
0
}
9986
9987
/************************************************************************/
9988
/*                        GDALRasterInterpolateAtPoint()                */
9989
/************************************************************************/
9990
9991
/**
9992
 * \brief Interpolates the value between pixels using
9993
 * a resampling algorithm
9994
 *
9995
 * @see GDALRasterBand::InterpolateAtPoint()
9996
 * @since GDAL 3.10
9997
 */
9998
9999
CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10000
                                    double dfLine,
10001
                                    GDALRIOResampleAlg eInterpolation,
10002
                                    double *pdfRealValue, double *pdfImagValue)
10003
0
{
10004
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10005
10006
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10007
0
    return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10008
0
                                      pdfRealValue, pdfImagValue);
10009
0
}
10010
10011
/************************************************************************/
10012
/*                    InterpolateAtGeolocation()                        */
10013
/************************************************************************/
10014
10015
/**
10016
 * \brief Interpolates the value between pixels using a resampling algorithm,
10017
 * taking georeferenced coordinates as input.
10018
 *
10019
 * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
10020
 * must be in the "natural" SRS of the dataset, that is the one returned by
10021
 * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
10022
 * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
10023
 * array (generally WGS 84) if there is a geolocation array.
10024
 * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10025
 * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10026
 * be a easting, and dfGeolocY a northing.
10027
 *
10028
 * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10029
 * expressed in that CRS, and that tuple must be conformant with the
10030
 * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10031
 * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10032
 * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10033
 * before calling this method, and in that case, dfGeolocX must be a longitude
10034
 * or an easting value, and dfGeolocX a latitude or a northing value.
10035
 *
10036
 * The GDALDataset::GeolocationToPixelLine() will be used to transform from
10037
 * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
10038
 * it for details on how that transformation is done.
10039
 *
10040
 * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
10041
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10042
 * where interpolation should be done.
10043
 * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
10044
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10045
 * where interpolation should be done.
10046
 * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
10047
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10048
 * @param pdfRealValue pointer to real part of interpolated value
10049
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10050
 * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
10051
 *
10052
 * @return CE_None on success, or an error code on failure.
10053
 * @since GDAL 3.11
10054
 */
10055
10056
CPLErr GDALRasterBand::InterpolateAtGeolocation(
10057
    double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
10058
    GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
10059
    double *pdfImagValue, CSLConstList papszTransformerOptions) const
10060
0
{
10061
0
    double dfPixel;
10062
0
    double dfLine;
10063
0
    if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
10064
0
                                     &dfLine,
10065
0
                                     papszTransformerOptions) != CE_None)
10066
0
    {
10067
0
        return CE_Failure;
10068
0
    }
10069
0
    return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
10070
0
                              pdfImagValue);
10071
0
}
10072
10073
/************************************************************************/
10074
/*                  GDALRasterInterpolateAtGeolocation()                */
10075
/************************************************************************/
10076
10077
/**
10078
 * \brief Interpolates the value between pixels using a resampling algorithm,
10079
 * taking georeferenced coordinates as input.
10080
 *
10081
 * @see GDALRasterBand::InterpolateAtGeolocation()
10082
 * @since GDAL 3.11
10083
 */
10084
10085
CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
10086
                                          double dfGeolocX, double dfGeolocY,
10087
                                          OGRSpatialReferenceH hSRS,
10088
                                          GDALRIOResampleAlg eInterpolation,
10089
                                          double *pdfRealValue,
10090
                                          double *pdfImagValue,
10091
                                          CSLConstList papszTransformerOptions)
10092
0
{
10093
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
10094
10095
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10096
0
    return poBand->InterpolateAtGeolocation(
10097
0
        dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
10098
0
        eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
10099
0
}
10100
10101
/************************************************************************/
10102
/*                    GDALRasterBand::SplitRasterIO()                   */
10103
/************************************************************************/
10104
10105
//! @cond Doxygen_Suppress
10106
10107
/** Implements IRasterIO() by dividing the request in 2.
10108
 *
10109
 * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
10110
 *
10111
 * Return CE_Warning if the split could not be done, CE_None in case of
10112
 * success and CE_Failure in case of error.
10113
 *
10114
 * @since 3.12
10115
 */
10116
CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
10117
                                     [[maybe_unused]] int nXSize,
10118
                                     [[maybe_unused]] int nYSize, void *pData,
10119
                                     int nBufXSize, int nBufYSize,
10120
                                     GDALDataType eBufType,
10121
                                     GSpacing nPixelSpace, GSpacing nLineSpace,
10122
                                     GDALRasterIOExtraArg *psExtraArg)
10123
0
{
10124
0
    CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
10125
10126
0
    GByte *pabyData = static_cast<GByte *>(pData);
10127
0
    if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
10128
0
    {
10129
0
        GDALRasterIOExtraArg sArg;
10130
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
10131
0
        const int nHalfHeight = nBufYSize / 2;
10132
10133
0
        sArg.pfnProgress = GDALScaledProgress;
10134
0
        sArg.pProgressData = GDALCreateScaledProgress(
10135
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10136
0
        if (sArg.pProgressData == nullptr)
10137
0
            sArg.pfnProgress = nullptr;
10138
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
10139
0
                                pabyData, nBufXSize, nHalfHeight, eBufType,
10140
0
                                nPixelSpace, nLineSpace, &sArg);
10141
0
        GDALDestroyScaledProgress(sArg.pProgressData);
10142
10143
0
        if (eErr == CE_None)
10144
0
        {
10145
0
            sArg.pfnProgress = GDALScaledProgress;
10146
0
            sArg.pProgressData = GDALCreateScaledProgress(
10147
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10148
0
            if (sArg.pProgressData == nullptr)
10149
0
                sArg.pfnProgress = nullptr;
10150
0
            eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
10151
0
                             nBufYSize - nHalfHeight,
10152
0
                             pabyData + nHalfHeight * nLineSpace, nBufXSize,
10153
0
                             nBufYSize - nHalfHeight, eBufType, nPixelSpace,
10154
0
                             nLineSpace, &sArg);
10155
0
            GDALDestroyScaledProgress(sArg.pProgressData);
10156
0
        }
10157
0
        return eErr;
10158
0
    }
10159
0
    else if (nBufXSize >= 2)
10160
0
    {
10161
0
        GDALRasterIOExtraArg sArg;
10162
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
10163
0
        const int nHalfWidth = nBufXSize / 2;
10164
10165
0
        sArg.pfnProgress = GDALScaledProgress;
10166
0
        sArg.pProgressData = GDALCreateScaledProgress(
10167
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10168
0
        if (sArg.pProgressData == nullptr)
10169
0
            sArg.pfnProgress = nullptr;
10170
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
10171
0
                                pabyData, nHalfWidth, nBufYSize, eBufType,
10172
0
                                nPixelSpace, nLineSpace, &sArg);
10173
0
        GDALDestroyScaledProgress(sArg.pProgressData);
10174
10175
0
        if (eErr == CE_None)
10176
0
        {
10177
0
            sArg.pfnProgress = GDALScaledProgress;
10178
0
            sArg.pProgressData = GDALCreateScaledProgress(
10179
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10180
0
            if (sArg.pProgressData == nullptr)
10181
0
                sArg.pfnProgress = nullptr;
10182
0
            eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
10183
0
                             nBufXSize - nHalfWidth, nBufYSize,
10184
0
                             pabyData + nHalfWidth * nPixelSpace,
10185
0
                             nBufXSize - nHalfWidth, nBufYSize, eBufType,
10186
0
                             nPixelSpace, nLineSpace, &sArg);
10187
0
            GDALDestroyScaledProgress(sArg.pProgressData);
10188
0
        }
10189
0
        return eErr;
10190
0
    }
10191
10192
0
    return CE_Warning;
10193
0
}
10194
10195
//! @endcond
10196
10197
/************************************************************************/
10198
/*                         ThrowIfNotSameDimensions()                   */
10199
/************************************************************************/
10200
10201
//! @cond Doxygen_Suppress
10202
/* static */
10203
void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
10204
                                              const GDALRasterBand &second)
10205
0
{
10206
0
    if (first.GetXSize() != second.GetXSize() ||
10207
0
        first.GetYSize() != second.GetYSize())
10208
0
    {
10209
0
        throw std::runtime_error("Bands do not have the same dimensions");
10210
0
    }
10211
0
}
10212
10213
//! @endcond
10214
10215
/************************************************************************/
10216
/*                          GDALRasterBandUnaryOp()                     */
10217
/************************************************************************/
10218
10219
/** Apply a unary operation on this band.
10220
 *
10221
 * The resulting band is lazy evaluated. A reference is taken on the input
10222
 * dataset.
10223
 *
10224
 * @since 3.12
10225
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10226
 */
10227
GDALComputedRasterBandH
10228
GDALRasterBandUnaryOp(GDALRasterBandH hBand,
10229
                      GDALRasterAlgebraUnaryOperation eOp)
10230
0
{
10231
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
10232
0
    switch (eOp)
10233
0
    {
10234
0
        case GRAUO_LOGICAL_NOT:
10235
0
            break;
10236
0
    }
10237
0
    return new GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
10238
0
                                      *(GDALRasterBand::FromHandle(hBand)),
10239
0
                                      true);
10240
0
}
10241
10242
/************************************************************************/
10243
/*            ConvertGDALRasterAlgebraBinaryOperationToCpp()            */
10244
/************************************************************************/
10245
10246
static GDALComputedRasterBand::Operation
10247
ConvertGDALRasterAlgebraBinaryOperationToCpp(
10248
    GDALRasterAlgebraBinaryOperation eOp)
10249
0
{
10250
0
    switch (eOp)
10251
0
    {
10252
0
        case GRABO_ADD:
10253
0
            return GDALComputedRasterBand::Operation::OP_ADD;
10254
0
        case GRABO_SUB:
10255
0
            return GDALComputedRasterBand::Operation::OP_SUBTRACT;
10256
0
        case GRABO_MUL:
10257
0
            return GDALComputedRasterBand::Operation::OP_MULTIPLY;
10258
0
        case GRABO_DIV:
10259
0
            return GDALComputedRasterBand::Operation::OP_DIVIDE;
10260
0
        case GRABO_GT:
10261
0
            return GDALComputedRasterBand::Operation::OP_GT;
10262
0
        case GRABO_GE:
10263
0
            return GDALComputedRasterBand::Operation::OP_GE;
10264
0
        case GRABO_LT:
10265
0
            return GDALComputedRasterBand::Operation::OP_LT;
10266
0
        case GRABO_LE:
10267
0
            return GDALComputedRasterBand::Operation::OP_LE;
10268
0
        case GRABO_EQ:
10269
0
            return GDALComputedRasterBand::Operation::OP_EQ;
10270
0
        case GRABO_NE:
10271
0
            break;
10272
0
        case GRABO_LOGICAL_AND:
10273
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
10274
0
        case GRABO_LOGICAL_OR:
10275
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
10276
0
    }
10277
0
    return GDALComputedRasterBand::Operation::OP_NE;
10278
0
}
10279
10280
/************************************************************************/
10281
/*                     GDALRasterBandBinaryOpBand()                     */
10282
/************************************************************************/
10283
10284
/** Apply a binary operation on this band with another one.
10285
 *
10286
 * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
10287
 * "hBand1 - hBand2".
10288
 *
10289
 * The resulting band is lazy evaluated. A reference is taken on both input
10290
 * datasets.
10291
 *
10292
 * @since 3.12
10293
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10294
 */
10295
GDALComputedRasterBandH
10296
GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
10297
                           GDALRasterAlgebraBinaryOperation eOp,
10298
                           GDALRasterBandH hOtherBand)
10299
0
{
10300
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
10301
0
    VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
10302
0
#ifndef HAVE_MUPARSER
10303
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10304
0
    {
10305
0
        CPLError(
10306
0
            CE_Failure, CPLE_NotSupported,
10307
0
            "Band comparison operators not available on a GDAL build without "
10308
0
            "muparser");
10309
0
        return nullptr;
10310
0
    }
10311
0
#endif
10312
0
    auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
10313
0
    auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
10314
0
    try
10315
0
    {
10316
0
        GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
10317
0
    }
10318
0
    catch (const std::exception &e)
10319
0
    {
10320
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
10321
0
        return nullptr;
10322
0
    }
10323
0
    return new GDALComputedRasterBand(
10324
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
10325
0
        secondBand);
10326
0
}
10327
10328
/************************************************************************/
10329
/*                     GDALRasterBandBinaryOpDouble()                   */
10330
/************************************************************************/
10331
10332
/** Apply a binary operation on this band with a constant
10333
 *
10334
 * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
10335
 * "hBand - constant".
10336
 *
10337
 * The resulting band is lazy evaluated. A reference is taken on the input
10338
 * dataset.
10339
 *
10340
 * @since 3.12
10341
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10342
 */
10343
GDALComputedRasterBandH
10344
GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
10345
                             GDALRasterAlgebraBinaryOperation eOp,
10346
                             double constant)
10347
0
{
10348
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
10349
0
#ifndef HAVE_MUPARSER
10350
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10351
0
    {
10352
0
        CPLError(
10353
0
            CE_Failure, CPLE_NotSupported,
10354
0
            "Band comparison operators not available on a GDAL build without "
10355
0
            "muparser");
10356
0
        return nullptr;
10357
0
    }
10358
0
#endif
10359
0
    return new GDALComputedRasterBand(
10360
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
10361
0
        *(GDALRasterBand::FromHandle(hBand)), constant);
10362
0
}
10363
10364
/************************************************************************/
10365
/*                   GDALRasterBandBinaryOpDoubleToBand()               */
10366
/************************************************************************/
10367
10368
/** Apply a binary operation on the constant with this band
10369
 *
10370
 * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
10371
 * "constant - hBand".
10372
 *
10373
 * The resulting band is lazy evaluated. A reference is taken on the input
10374
 * dataset.
10375
 *
10376
 * @since 3.12
10377
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10378
 */
10379
GDALComputedRasterBandH
10380
GDALRasterBandBinaryOpDoubleToBand(double constant,
10381
                                   GDALRasterAlgebraBinaryOperation eOp,
10382
                                   GDALRasterBandH hBand)
10383
0
{
10384
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
10385
0
#ifndef HAVE_MUPARSER
10386
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10387
0
    {
10388
0
        CPLError(
10389
0
            CE_Failure, CPLE_NotSupported,
10390
0
            "Band comparison operators not available on a GDAL build without "
10391
0
            "muparser");
10392
0
        return nullptr;
10393
0
    }
10394
0
#endif
10395
0
    switch (eOp)
10396
0
    {
10397
0
        case GRABO_ADD:
10398
0
        case GRABO_MUL:
10399
0
        {
10400
0
            return new GDALComputedRasterBand(
10401
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
10402
0
                *(GDALRasterBand::FromHandle(hBand)), constant);
10403
0
        }
10404
10405
0
        case GRABO_DIV:
10406
0
        case GRABO_GT:
10407
0
        case GRABO_GE:
10408
0
        case GRABO_LT:
10409
0
        case GRABO_LE:
10410
0
        case GRABO_EQ:
10411
0
        case GRABO_NE:
10412
0
        case GRABO_LOGICAL_AND:
10413
0
        case GRABO_LOGICAL_OR:
10414
0
        {
10415
0
            return new GDALComputedRasterBand(
10416
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
10417
0
                *(GDALRasterBand::FromHandle(hBand)));
10418
0
        }
10419
10420
0
        case GRABO_SUB:
10421
0
        {
10422
0
            break;
10423
0
        }
10424
0
    }
10425
10426
0
    return new GDALComputedRasterBand(
10427
0
        GDALComputedRasterBand::Operation::OP_ADD,
10428
0
        GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
10429
0
                               *(GDALRasterBand::FromHandle(hBand)), -1.0),
10430
0
        constant);
10431
0
}
10432
10433
/************************************************************************/
10434
/*                           operator+()                                */
10435
/************************************************************************/
10436
10437
/** Add this band with another one.
10438
 *
10439
 * The resulting band is lazy evaluated. A reference is taken on both input
10440
 * datasets.
10441
 *
10442
 * @since 3.12
10443
 * @throw std::runtime_error if both bands do not have the same dimensions.
10444
 */
10445
GDALComputedRasterBand
10446
GDALRasterBand::operator+(const GDALRasterBand &other) const
10447
0
{
10448
0
    ThrowIfNotSameDimensions(*this, other);
10449
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
10450
0
                                  *this, other);
10451
0
}
10452
10453
/************************************************************************/
10454
/*                           operator+()                                */
10455
/************************************************************************/
10456
10457
/** Add this band with a constant.
10458
 *
10459
 * The resulting band is lazy evaluated. A reference is taken on the input
10460
 * dataset.
10461
 *
10462
 * @since 3.12
10463
 */
10464
GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
10465
0
{
10466
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
10467
0
                                  *this, constant);
10468
0
}
10469
10470
/************************************************************************/
10471
/*                           operator+()                                */
10472
/************************************************************************/
10473
10474
/** Add a band with a constant.
10475
 *
10476
 * The resulting band is lazy evaluated. A reference is taken on the input
10477
 * dataset.
10478
 *
10479
 * @since 3.12
10480
 */
10481
GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
10482
0
{
10483
0
    return other + constant;
10484
0
}
10485
10486
/************************************************************************/
10487
/*                           operator-()                                */
10488
/************************************************************************/
10489
10490
/** Subtract this band with another one.
10491
 *
10492
 * The resulting band is lazy evaluated. A reference is taken on both input
10493
 * datasets.
10494
 *
10495
 * @since 3.12
10496
 * @throw std::runtime_error if both bands do not have the same dimensions.
10497
 */
10498
GDALComputedRasterBand
10499
GDALRasterBand::operator-(const GDALRasterBand &other) const
10500
0
{
10501
0
    ThrowIfNotSameDimensions(*this, other);
10502
0
    return GDALComputedRasterBand(
10503
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
10504
0
}
10505
10506
/************************************************************************/
10507
/*                           operator-()                                */
10508
/************************************************************************/
10509
10510
/** Subtract this band with a constant.
10511
 *
10512
 * The resulting band is lazy evaluated. A reference is taken on the input
10513
 * dataset.
10514
 *
10515
 * @since 3.12
10516
 */
10517
GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
10518
0
{
10519
0
    return GDALComputedRasterBand(
10520
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
10521
0
}
10522
10523
/************************************************************************/
10524
/*                           operator-()                                */
10525
/************************************************************************/
10526
10527
/** Subtract a constant with a band.
10528
 *
10529
 * The resulting band is lazy evaluated. A reference is taken on the input
10530
 * dataset.
10531
 *
10532
 * @since 3.12
10533
 */
10534
GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
10535
0
{
10536
0
    return other * (-1.0) + constant;
10537
0
}
10538
10539
/************************************************************************/
10540
/*                           operator*()                                */
10541
/************************************************************************/
10542
10543
/** Multiply this band with another one.
10544
 *
10545
 * The resulting band is lazy evaluated. A reference is taken on both input
10546
 * datasets.
10547
 *
10548
 * @since 3.12
10549
 * @throw std::runtime_error if both bands do not have the same dimensions.
10550
 */
10551
GDALComputedRasterBand
10552
GDALRasterBand::operator*(const GDALRasterBand &other) const
10553
0
{
10554
0
    ThrowIfNotSameDimensions(*this, other);
10555
0
    return GDALComputedRasterBand(
10556
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
10557
0
}
10558
10559
/************************************************************************/
10560
/*                           operator*()                                */
10561
/************************************************************************/
10562
10563
/** Multiply this band by a constant.
10564
 *
10565
 * The resulting band is lazy evaluated. A reference is taken on the input
10566
 * dataset.
10567
 *
10568
 * @since 3.12
10569
 */
10570
GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
10571
0
{
10572
0
    return GDALComputedRasterBand(
10573
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
10574
0
}
10575
10576
/************************************************************************/
10577
/*                           operator*()                                */
10578
/************************************************************************/
10579
10580
/** Multiply a band with a constant.
10581
 *
10582
 * The resulting band is lazy evaluated. A reference is taken on the input
10583
 * dataset.
10584
 *
10585
 * @since 3.12
10586
 */
10587
GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
10588
0
{
10589
0
    return other * constant;
10590
0
}
10591
10592
/************************************************************************/
10593
/*                           operator/()                                */
10594
/************************************************************************/
10595
10596
/** Divide this band with another one.
10597
 *
10598
 * The resulting band is lazy evaluated. A reference is taken on both input
10599
 * datasets.
10600
 *
10601
 * @since 3.12
10602
 * @throw std::runtime_error if both bands do not have the same dimensions.
10603
 */
10604
GDALComputedRasterBand
10605
GDALRasterBand::operator/(const GDALRasterBand &other) const
10606
0
{
10607
0
    ThrowIfNotSameDimensions(*this, other);
10608
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10609
0
                                  *this, other);
10610
0
}
10611
10612
/************************************************************************/
10613
/*                           operator/()                                */
10614
/************************************************************************/
10615
10616
/** Divide this band by a constant.
10617
 *
10618
 * The resulting band is lazy evaluated. A reference is taken on the input
10619
 * dataset.
10620
 *
10621
 * @since 3.12
10622
 */
10623
GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
10624
0
{
10625
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10626
0
                                  *this, constant);
10627
0
}
10628
10629
/************************************************************************/
10630
/*                           operator/()                                */
10631
/************************************************************************/
10632
10633
/** Divide a constant by a band.
10634
 *
10635
 * The resulting band is lazy evaluated. A reference is taken on the input
10636
 * dataset.
10637
 *
10638
 * @since 3.12
10639
 */
10640
GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
10641
0
{
10642
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10643
0
                                  constant, other);
10644
0
}
10645
10646
/************************************************************************/
10647
/*                          ThrowIfNotMuparser()                        */
10648
/************************************************************************/
10649
10650
#ifndef HAVE_MUPARSER
10651
static GDALComputedRasterBand ThrowIfNotMuparser()
10652
0
{
10653
0
    throw std::runtime_error("Band comparison operators not available on a "
10654
0
                             "GDAL build without muparser");
10655
0
}
10656
#endif
10657
10658
/************************************************************************/
10659
/*                           operator>()                                */
10660
/************************************************************************/
10661
10662
/** Return a band whose value is 1 if the pixel value of the left operand
10663
 * is greater than the pixel value of the right operand.
10664
 *
10665
 * The resulting band is lazy evaluated. A reference is taken on the input
10666
 * dataset.
10667
 *
10668
 * @since 3.12
10669
 */
10670
GDALComputedRasterBand
10671
GDALRasterBand::operator>(const GDALRasterBand &other) const
10672
0
{
10673
0
#ifndef HAVE_MUPARSER
10674
0
    (void)other;
10675
0
    return ThrowIfNotMuparser();
10676
#else
10677
    ThrowIfNotSameDimensions(*this, other);
10678
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10679
                                  *this, other);
10680
#endif
10681
0
}
10682
10683
/************************************************************************/
10684
/*                           operator>()                                */
10685
/************************************************************************/
10686
10687
/** Return a band whose value is 1 if the pixel value of the left operand
10688
 * is greater than the constant.
10689
 *
10690
 * The resulting band is lazy evaluated. A reference is taken on the input
10691
 * dataset.
10692
 *
10693
 * @since 3.12
10694
 */
10695
GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
10696
0
{
10697
0
#ifndef HAVE_MUPARSER
10698
0
    (void)constant;
10699
0
    return ThrowIfNotMuparser();
10700
#else
10701
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10702
                                  *this, constant);
10703
#endif
10704
0
}
10705
10706
/************************************************************************/
10707
/*                           operator>()                                */
10708
/************************************************************************/
10709
10710
/** Return a band whose value is 1 if the constant is greater than the pixel
10711
 * value of the right operand.
10712
 *
10713
 * The resulting band is lazy evaluated. A reference is taken on the input
10714
 * dataset.
10715
 *
10716
 * @since 3.12
10717
 */
10718
GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
10719
0
{
10720
0
#ifndef HAVE_MUPARSER
10721
0
    (void)constant;
10722
0
    (void)other;
10723
0
    return ThrowIfNotMuparser();
10724
#else
10725
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10726
                                  constant, other);
10727
#endif
10728
0
}
10729
10730
/************************************************************************/
10731
/*                           operator>=()                               */
10732
/************************************************************************/
10733
10734
/** Return a band whose value is 1 if the pixel value of the left operand
10735
 * is greater or equal to the pixel value of the right operand.
10736
 *
10737
 * The resulting band is lazy evaluated. A reference is taken on the input
10738
 * dataset.
10739
 *
10740
 * @since 3.12
10741
 */
10742
GDALComputedRasterBand
10743
GDALRasterBand::operator>=(const GDALRasterBand &other) const
10744
0
{
10745
0
#ifndef HAVE_MUPARSER
10746
0
    (void)other;
10747
0
    return ThrowIfNotMuparser();
10748
#else
10749
    ThrowIfNotSameDimensions(*this, other);
10750
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10751
                                  *this, other);
10752
#endif
10753
0
}
10754
10755
/************************************************************************/
10756
/*                           operator>=()                               */
10757
/************************************************************************/
10758
10759
/** Return a band whose value is 1 if the pixel value of the left operand
10760
 * is greater or equal to the constant.
10761
 *
10762
 * The resulting band is lazy evaluated. A reference is taken on the input
10763
 * dataset.
10764
 *
10765
 * @since 3.12
10766
 */
10767
GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
10768
0
{
10769
0
#ifndef HAVE_MUPARSER
10770
0
    (void)constant;
10771
0
    return ThrowIfNotMuparser();
10772
#else
10773
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10774
                                  *this, constant);
10775
#endif
10776
0
}
10777
10778
/************************************************************************/
10779
/*                           operator>=()                               */
10780
/************************************************************************/
10781
10782
/** Return a band whose value is 1 if the constant is greater or equal to
10783
 * the pixel value of the right operand.
10784
 *
10785
 * The resulting band is lazy evaluated. A reference is taken on the input
10786
 * dataset.
10787
 *
10788
 * @since 3.12
10789
 */
10790
GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
10791
0
{
10792
0
#ifndef HAVE_MUPARSER
10793
0
    (void)constant;
10794
0
    (void)other;
10795
0
    return ThrowIfNotMuparser();
10796
#else
10797
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10798
                                  constant, other);
10799
#endif
10800
0
}
10801
10802
/************************************************************************/
10803
/*                           operator<()                                */
10804
/************************************************************************/
10805
10806
/** Return a band whose value is 1 if the pixel value of the left operand
10807
 * is lesser than the pixel value of the right operand.
10808
 *
10809
 * The resulting band is lazy evaluated. A reference is taken on the input
10810
 * dataset.
10811
 *
10812
 * @since 3.12
10813
 */
10814
GDALComputedRasterBand
10815
GDALRasterBand::operator<(const GDALRasterBand &other) const
10816
0
{
10817
0
#ifndef HAVE_MUPARSER
10818
0
    (void)other;
10819
0
    return ThrowIfNotMuparser();
10820
#else
10821
    ThrowIfNotSameDimensions(*this, other);
10822
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
10823
                                  *this, other);
10824
#endif
10825
0
}
10826
10827
/************************************************************************/
10828
/*                           operator<()                                */
10829
/************************************************************************/
10830
10831
/** Return a band whose value is 1 if the pixel value of the left operand
10832
 * is lesser than the constant.
10833
 *
10834
 * The resulting band is lazy evaluated. A reference is taken on the input
10835
 * dataset.
10836
 *
10837
 * @since 3.12
10838
 */
10839
GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
10840
0
{
10841
0
#ifndef HAVE_MUPARSER
10842
0
    (void)constant;
10843
0
    return ThrowIfNotMuparser();
10844
#else
10845
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
10846
                                  *this, constant);
10847
#endif
10848
0
}
10849
10850
/************************************************************************/
10851
/*                           operator<()                                */
10852
/************************************************************************/
10853
10854
/** Return a band whose value is 1 if the constant is lesser than the pixel
10855
 * value of the right operand.
10856
 *
10857
 * The resulting band is lazy evaluated. A reference is taken on the input
10858
 * dataset.
10859
 *
10860
 * @since 3.12
10861
 */
10862
GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
10863
0
{
10864
0
#ifndef HAVE_MUPARSER
10865
0
    (void)constant;
10866
0
    (void)other;
10867
0
    return ThrowIfNotMuparser();
10868
#else
10869
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
10870
                                  constant, other);
10871
#endif
10872
0
}
10873
10874
/************************************************************************/
10875
/*                           operator<=()                               */
10876
/************************************************************************/
10877
10878
/** Return a band whose value is 1 if the pixel value of the left operand
10879
 * is lesser or equal to the pixel value of the right operand.
10880
 *
10881
 * The resulting band is lazy evaluated. A reference is taken on the input
10882
 * dataset.
10883
 *
10884
 * @since 3.12
10885
 */
10886
GDALComputedRasterBand
10887
GDALRasterBand::operator<=(const GDALRasterBand &other) const
10888
0
{
10889
0
#ifndef HAVE_MUPARSER
10890
0
    (void)other;
10891
0
    return ThrowIfNotMuparser();
10892
#else
10893
    ThrowIfNotSameDimensions(*this, other);
10894
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
10895
                                  *this, other);
10896
#endif
10897
0
}
10898
10899
/************************************************************************/
10900
/*                           operator<=()                               */
10901
/************************************************************************/
10902
10903
/** Return a band whose value is 1 if the pixel value of the left operand
10904
 * is lesser or equal to the constant.
10905
 *
10906
 * The resulting band is lazy evaluated. A reference is taken on the input
10907
 * dataset.
10908
 *
10909
 * @since 3.12
10910
 */
10911
GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
10912
0
{
10913
0
#ifndef HAVE_MUPARSER
10914
0
    (void)constant;
10915
0
    return ThrowIfNotMuparser();
10916
#else
10917
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
10918
                                  *this, constant);
10919
#endif
10920
0
}
10921
10922
/************************************************************************/
10923
/*                           operator<=()                               */
10924
/************************************************************************/
10925
10926
/** Return a band whose value is 1 if the constant is lesser or equal to
10927
 * the pixel value of the right operand.
10928
 *
10929
 * The resulting band is lazy evaluated. A reference is taken on the input
10930
 * dataset.
10931
 *
10932
 * @since 3.12
10933
 */
10934
GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
10935
0
{
10936
0
#ifndef HAVE_MUPARSER
10937
0
    (void)constant;
10938
0
    (void)other;
10939
0
    return ThrowIfNotMuparser();
10940
#else
10941
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
10942
                                  constant, other);
10943
#endif
10944
0
}
10945
10946
/************************************************************************/
10947
/*                           operator==()                               */
10948
/************************************************************************/
10949
10950
/** Return a band whose value is 1 if the pixel value of the left operand
10951
 * is equal to the pixel value of the right operand.
10952
 *
10953
 * The resulting band is lazy evaluated. A reference is taken on the input
10954
 * dataset.
10955
 *
10956
 * @since 3.12
10957
 */
10958
GDALComputedRasterBand
10959
GDALRasterBand::operator==(const GDALRasterBand &other) const
10960
0
{
10961
0
#ifndef HAVE_MUPARSER
10962
0
    (void)other;
10963
0
    return ThrowIfNotMuparser();
10964
#else
10965
    ThrowIfNotSameDimensions(*this, other);
10966
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
10967
                                  *this, other);
10968
#endif
10969
0
}
10970
10971
/************************************************************************/
10972
/*                           operator==()                               */
10973
/************************************************************************/
10974
10975
/** Return a band whose value is 1 if the pixel value of the left operand
10976
 * is equal to the constant.
10977
 *
10978
 * The resulting band is lazy evaluated. A reference is taken on the input
10979
 * dataset.
10980
 *
10981
 * @since 3.12
10982
 */
10983
GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
10984
0
{
10985
0
#ifndef HAVE_MUPARSER
10986
0
    (void)constant;
10987
0
    return ThrowIfNotMuparser();
10988
#else
10989
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
10990
                                  *this, constant);
10991
#endif
10992
0
}
10993
10994
/************************************************************************/
10995
/*                           operator==()                               */
10996
/************************************************************************/
10997
10998
/** Return a band whose value is 1 if the constant is equal to
10999
 * the pixel value of the right operand.
11000
 *
11001
 * The resulting band is lazy evaluated. A reference is taken on the input
11002
 * dataset.
11003
 *
11004
 * @since 3.12
11005
 */
11006
GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
11007
0
{
11008
0
#ifndef HAVE_MUPARSER
11009
0
    (void)constant;
11010
0
    (void)other;
11011
0
    return ThrowIfNotMuparser();
11012
#else
11013
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11014
                                  constant, other);
11015
#endif
11016
0
}
11017
11018
/************************************************************************/
11019
/*                           operator!=()                               */
11020
/************************************************************************/
11021
11022
/** Return a band whose value is 1 if the pixel value of the left operand
11023
 * is different from the pixel value of the right operand.
11024
 *
11025
 * The resulting band is lazy evaluated. A reference is taken on the input
11026
 * dataset.
11027
 *
11028
 * @since 3.12
11029
 */
11030
GDALComputedRasterBand
11031
GDALRasterBand::operator!=(const GDALRasterBand &other) const
11032
0
{
11033
0
#ifndef HAVE_MUPARSER
11034
0
    (void)other;
11035
0
    return ThrowIfNotMuparser();
11036
#else
11037
    ThrowIfNotSameDimensions(*this, other);
11038
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11039
                                  *this, other);
11040
#endif
11041
0
}
11042
11043
/************************************************************************/
11044
/*                           operator!=()                               */
11045
/************************************************************************/
11046
11047
/** Return a band whose value is 1 if the pixel value of the left operand
11048
 * is different from the constant.
11049
 *
11050
 * The resulting band is lazy evaluated. A reference is taken on the input
11051
 * dataset.
11052
 *
11053
 * @since 3.12
11054
 */
11055
GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
11056
0
{
11057
0
#ifndef HAVE_MUPARSER
11058
0
    (void)constant;
11059
0
    return ThrowIfNotMuparser();
11060
#else
11061
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11062
                                  *this, constant);
11063
#endif
11064
0
}
11065
11066
/************************************************************************/
11067
/*                           operator!=()                               */
11068
/************************************************************************/
11069
11070
/** Return a band whose value is 1 if the constant is different from
11071
 * the pixel value of the right operand.
11072
 *
11073
 * The resulting band is lazy evaluated. A reference is taken on the input
11074
 * dataset.
11075
 *
11076
 * @since 3.12
11077
 */
11078
GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
11079
0
{
11080
0
#ifndef HAVE_MUPARSER
11081
0
    (void)constant;
11082
0
    (void)other;
11083
0
    return ThrowIfNotMuparser();
11084
#else
11085
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11086
                                  constant, other);
11087
#endif
11088
0
}
11089
11090
#if defined(__GNUC__)
11091
#pragma GCC diagnostic push
11092
#pragma GCC diagnostic ignored "-Weffc++"
11093
#endif
11094
11095
/************************************************************************/
11096
/*                           operator&&()                               */
11097
/************************************************************************/
11098
11099
/** Return a band whose value is 1 if the pixel value of the left and right
11100
 * operands is true.
11101
 *
11102
 * The resulting band is lazy evaluated. A reference is taken on the input
11103
 * dataset.
11104
 *
11105
 * @since 3.12
11106
 */
11107
GDALComputedRasterBand
11108
GDALRasterBand::operator&&(const GDALRasterBand &other) const
11109
0
{
11110
0
#ifndef HAVE_MUPARSER
11111
0
    (void)other;
11112
0
    return ThrowIfNotMuparser();
11113
#else
11114
    ThrowIfNotSameDimensions(*this, other);
11115
    return GDALComputedRasterBand(
11116
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
11117
#endif
11118
0
}
11119
11120
/************************************************************************/
11121
/*                           operator&&()                               */
11122
/************************************************************************/
11123
11124
/** Return a band whose value is 1 if the pixel value of the left operand
11125
 * is true, as well as the constant
11126
 *
11127
 * The resulting band is lazy evaluated. A reference is taken on the input
11128
 * dataset.
11129
 *
11130
 * @since 3.12
11131
 */
11132
GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
11133
0
{
11134
0
#ifndef HAVE_MUPARSER
11135
0
    (void)constant;
11136
0
    return ThrowIfNotMuparser();
11137
#else
11138
    return GDALComputedRasterBand(
11139
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
11140
#endif
11141
0
}
11142
11143
/************************************************************************/
11144
/*                           operator&&()                               */
11145
/************************************************************************/
11146
11147
/** Return a band whose value is 1 if the constant is true, as well as
11148
 * the pixel value of the right operand.
11149
 *
11150
 * The resulting band is lazy evaluated. A reference is taken on the input
11151
 * dataset.
11152
 *
11153
 * @since 3.12
11154
 */
11155
GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
11156
0
{
11157
0
#ifndef HAVE_MUPARSER
11158
0
    (void)constant;
11159
0
    (void)other;
11160
0
    return ThrowIfNotMuparser();
11161
#else
11162
    return GDALComputedRasterBand(
11163
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
11164
#endif
11165
0
}
11166
11167
/************************************************************************/
11168
/*                           operator||()                               */
11169
/************************************************************************/
11170
11171
/** Return a band whose value is 1 if the pixel value of the left or right
11172
 * operands is true.
11173
 *
11174
 * The resulting band is lazy evaluated. A reference is taken on the input
11175
 * dataset.
11176
 *
11177
 * @since 3.12
11178
 */
11179
GDALComputedRasterBand
11180
GDALRasterBand::operator||(const GDALRasterBand &other) const
11181
0
{
11182
0
#ifndef HAVE_MUPARSER
11183
0
    (void)other;
11184
0
    return ThrowIfNotMuparser();
11185
#else
11186
    ThrowIfNotSameDimensions(*this, other);
11187
    return GDALComputedRasterBand(
11188
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
11189
#endif
11190
0
}
11191
11192
/************************************************************************/
11193
/*                           operator||()                               */
11194
/************************************************************************/
11195
11196
/** Return a band whose value is 1 if the pixel value of the left operand
11197
 * is true, or if the constant is true
11198
 *
11199
 * The resulting band is lazy evaluated. A reference is taken on the input
11200
 * dataset.
11201
 *
11202
 * @since 3.12
11203
 */
11204
GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
11205
0
{
11206
0
#ifndef HAVE_MUPARSER
11207
0
    (void)constant;
11208
0
    return ThrowIfNotMuparser();
11209
#else
11210
    return GDALComputedRasterBand(
11211
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
11212
#endif
11213
0
}
11214
11215
/************************************************************************/
11216
/*                           operator||()                               */
11217
/************************************************************************/
11218
11219
/** Return a band whose value is 1 if the constant is true, or
11220
 * the pixel value of the right operand is true
11221
 *
11222
 * The resulting band is lazy evaluated. A reference is taken on the input
11223
 * dataset.
11224
 *
11225
 * @since 3.12
11226
 */
11227
GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
11228
0
{
11229
0
#ifndef HAVE_MUPARSER
11230
0
    (void)constant;
11231
0
    (void)other;
11232
0
    return ThrowIfNotMuparser();
11233
#else
11234
    return GDALComputedRasterBand(
11235
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
11236
#endif
11237
0
}
11238
11239
#if defined(__GNUC__)
11240
#pragma GCC diagnostic pop
11241
#endif
11242
11243
/************************************************************************/
11244
/*                            operator!()                               */
11245
/************************************************************************/
11246
11247
/** Return a band whose value is the logical negation of the pixel value
11248
 *
11249
 * The resulting band is lazy evaluated. A reference is taken on the input
11250
 * dataset.
11251
 *
11252
 * @since 3.12
11253
 */
11254
GDALComputedRasterBand GDALRasterBand::operator!() const
11255
0
{
11256
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11257
0
                                  *this, true);
11258
0
}
11259
11260
namespace gdal
11261
{
11262
11263
/************************************************************************/
11264
/*                           IfThenElse()                               */
11265
/************************************************************************/
11266
11267
/** Return a band whose value is thenBand if the corresponding pixel in condBand
11268
 * is not zero, or the one from elseBand otherwise.
11269
 *
11270
 * Variants of this method exits where thenBand and/or elseBand can be double
11271
 * values.
11272
 *
11273
 * The resulting band is lazy evaluated. A reference is taken on the input
11274
 * datasets.
11275
 *
11276
 * This method is the same as the C function GDALRasterBandIfThenElse()
11277
 *
11278
 * @since 3.12
11279
 */
11280
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11281
                                  const GDALRasterBand &thenBand,
11282
                                  const GDALRasterBand &elseBand)
11283
0
{
11284
0
#ifndef HAVE_MUPARSER
11285
0
    (void)condBand;
11286
0
    (void)thenBand;
11287
0
    (void)elseBand;
11288
0
    return ThrowIfNotMuparser();
11289
#else
11290
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11291
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11292
    return GDALComputedRasterBand(
11293
        GDALComputedRasterBand::Operation::OP_TERNARY,
11294
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11295
#endif
11296
0
}
11297
11298
//! @cond Doxygen_Suppress
11299
11300
/************************************************************************/
11301
/*                           IfThenElse()                               */
11302
/************************************************************************/
11303
11304
/** Return a band whose value is thenValue if the corresponding pixel in condBand
11305
 * is not zero, or the one from elseBand otherwise.
11306
 *
11307
 * The resulting band is lazy evaluated. A reference is taken on the input
11308
 * datasets.
11309
 *
11310
 * This method is the same as the C function GDALRasterBandIfThenElse(),
11311
 * with thenBand = (condBand * 0) + thenValue
11312
 *
11313
 * @since 3.12
11314
 */
11315
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11316
                                  double thenValue,
11317
                                  const GDALRasterBand &elseBand)
11318
0
{
11319
0
#ifndef HAVE_MUPARSER
11320
0
    (void)condBand;
11321
0
    (void)thenValue;
11322
0
    (void)elseBand;
11323
0
    return ThrowIfNotMuparser();
11324
#else
11325
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11326
    auto thenBand =
11327
        (condBand * 0)
11328
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
11329
        thenValue;
11330
    return GDALComputedRasterBand(
11331
        GDALComputedRasterBand::Operation::OP_TERNARY,
11332
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11333
#endif
11334
0
}
11335
11336
/************************************************************************/
11337
/*                           IfThenElse()                               */
11338
/************************************************************************/
11339
11340
/** Return a band whose value is thenBand if the corresponding pixel in condBand
11341
 * is not zero, or the one from elseValue otherwise.
11342
 *
11343
 * The resulting band is lazy evaluated. A reference is taken on the input
11344
 * datasets.
11345
 *
11346
 * This method is the same as the C function GDALRasterBandIfThenElse(),
11347
 * with elseBand = (condBand * 0) + elseValue
11348
11349
 * @since 3.12
11350
 */
11351
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11352
                                  const GDALRasterBand &thenBand,
11353
                                  double elseValue)
11354
0
{
11355
0
#ifndef HAVE_MUPARSER
11356
0
    (void)condBand;
11357
0
    (void)thenBand;
11358
0
    (void)elseValue;
11359
0
    return ThrowIfNotMuparser();
11360
#else
11361
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11362
    auto elseBand =
11363
        (condBand * 0)
11364
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
11365
        elseValue;
11366
    return GDALComputedRasterBand(
11367
        GDALComputedRasterBand::Operation::OP_TERNARY,
11368
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11369
#endif
11370
0
}
11371
11372
/************************************************************************/
11373
/*                           IfThenElse()                               */
11374
/************************************************************************/
11375
11376
/** Return a band whose value is thenValue if the corresponding pixel in condBand
11377
 * is not zero, or the one from elseValue otherwise.
11378
 *
11379
 * The resulting band is lazy evaluated. A reference is taken on the input
11380
 * datasets.
11381
 *
11382
 * This method is the same as the C function GDALRasterBandIfThenElse(),
11383
 * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
11384
 *
11385
 * @since 3.12
11386
 */
11387
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11388
                                  double thenValue, double elseValue)
11389
0
{
11390
0
#ifndef HAVE_MUPARSER
11391
0
    (void)condBand;
11392
0
    (void)thenValue;
11393
0
    (void)elseValue;
11394
0
    return ThrowIfNotMuparser();
11395
#else
11396
    auto thenBand =
11397
        (condBand * 0)
11398
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
11399
        thenValue;
11400
    auto elseBand =
11401
        (condBand * 0)
11402
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
11403
        elseValue;
11404
    return GDALComputedRasterBand(
11405
        GDALComputedRasterBand::Operation::OP_TERNARY,
11406
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11407
#endif
11408
0
}
11409
11410
//! @endcond
11411
11412
}  // namespace gdal
11413
11414
/************************************************************************/
11415
/*                     GDALRasterBandIfThenElse()                       */
11416
/************************************************************************/
11417
11418
/** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
11419
 * is not zero, or the one from hElseBand otherwise.
11420
 *
11421
 * The resulting band is lazy evaluated. A reference is taken on the input
11422
 * datasets.
11423
 *
11424
 * This function is the same as the C++ method gdal::IfThenElse()
11425
 *
11426
 * @since 3.12
11427
 */
11428
GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
11429
                                                 GDALRasterBandH hThenBand,
11430
                                                 GDALRasterBandH hElseBand)
11431
0
{
11432
0
    VALIDATE_POINTER1(hCondBand, __func__, nullptr);
11433
0
    VALIDATE_POINTER1(hThenBand, __func__, nullptr);
11434
0
    VALIDATE_POINTER1(hElseBand, __func__, nullptr);
11435
0
#ifndef HAVE_MUPARSER
11436
0
    CPLError(CE_Failure, CPLE_NotSupported,
11437
0
             "Band comparison operators not available on a GDAL build without "
11438
0
             "muparser");
11439
0
    return nullptr;
11440
#else
11441
11442
    auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
11443
    auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
11444
    auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
11445
    try
11446
    {
11447
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11448
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11449
    }
11450
    catch (const std::exception &e)
11451
    {
11452
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11453
        return nullptr;
11454
    }
11455
    return new GDALComputedRasterBand(
11456
        GDALComputedRasterBand::Operation::OP_TERNARY,
11457
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11458
#endif
11459
0
}
11460
11461
/************************************************************************/
11462
/*                       GDALRasterBand::AsType()                       */
11463
/************************************************************************/
11464
11465
/** Cast this band to another type.
11466
 *
11467
 * The resulting band is lazy evaluated. A reference is taken on the input
11468
 * dataset.
11469
 *
11470
 * This method is the same as the C function GDALRasterBandAsDataType()
11471
 *
11472
 * @since 3.12
11473
 */
11474
GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
11475
0
{
11476
0
    if (dt == GDT_Unknown)
11477
0
    {
11478
0
        throw std::runtime_error("AsType(GDT_Unknown) is not supported");
11479
0
    }
11480
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
11481
0
                                  *this, dt);
11482
0
}
11483
11484
/************************************************************************/
11485
/*                       GDALRasterBandAsDataType()                     */
11486
/************************************************************************/
11487
11488
/** Cast this band to another type.
11489
 *
11490
 * The resulting band is lazy evaluated. A reference is taken on the input
11491
 * dataset.
11492
 *
11493
 * This function is the same as the C++ method GDALRasterBand::AsType()
11494
 *
11495
 * @since 3.12
11496
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11497
 */
11498
GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
11499
                                                 GDALDataType eDT)
11500
0
{
11501
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11502
0
    if (eDT == GDT_Unknown)
11503
0
    {
11504
0
        CPLError(CE_Failure, CPLE_NotSupported,
11505
0
                 "GDALRasterBandAsDataType(GDT_Unknown) not supported");
11506
0
        return nullptr;
11507
0
    }
11508
0
    return new GDALComputedRasterBand(
11509
0
        GDALComputedRasterBand::Operation::OP_CAST,
11510
0
        *(GDALRasterBand::FromHandle(hBand)), eDT);
11511
0
}
11512
11513
/************************************************************************/
11514
/*                         GetBandVector()                              */
11515
/************************************************************************/
11516
11517
static std::vector<const GDALRasterBand *>
11518
GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
11519
0
{
11520
0
    std::vector<const GDALRasterBand *> bands;
11521
0
    for (size_t i = 0; i < nBandCount; ++i)
11522
0
    {
11523
0
        if (i > 0)
11524
0
        {
11525
0
            GDALRasterBand::ThrowIfNotSameDimensions(
11526
0
                *(GDALRasterBand::FromHandle(pahBands[0])),
11527
0
                *(GDALRasterBand::FromHandle(pahBands[i])));
11528
0
        }
11529
0
        bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
11530
0
    }
11531
0
    return bands;
11532
0
}
11533
11534
/************************************************************************/
11535
/*                       GDALOperationOnNBands()                        */
11536
/************************************************************************/
11537
11538
static GDALComputedRasterBandH
11539
GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
11540
                      GDALRasterBandH *pahBands)
11541
0
{
11542
0
    VALIDATE_POINTER1(pahBands, __func__, nullptr);
11543
0
    if (nBandCount == 0)
11544
0
    {
11545
0
        CPLError(CE_Failure, CPLE_AppDefined,
11546
0
                 "At least one band should be passed");
11547
0
        return nullptr;
11548
0
    }
11549
11550
0
    std::vector<const GDALRasterBand *> bands;
11551
0
    try
11552
0
    {
11553
0
        bands = GetBandVector(nBandCount, pahBands);
11554
0
    }
11555
0
    catch (const std::exception &e)
11556
0
    {
11557
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11558
0
        return nullptr;
11559
0
    }
11560
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
11561
0
}
11562
11563
/************************************************************************/
11564
/*                       GDALMaximumOfNBands()                          */
11565
/************************************************************************/
11566
11567
/** Return a band whose each pixel value is the maximum of the corresponding
11568
 * pixel values in the input bands.
11569
 *
11570
 * The resulting band is lazy evaluated. A reference is taken on input
11571
 * datasets.
11572
 *
11573
 * This function is the same as the C ++ method gdal::max()
11574
 *
11575
 * @since 3.12
11576
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11577
 */
11578
GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
11579
                                            GDALRasterBandH *pahBands)
11580
0
{
11581
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
11582
0
                                 nBandCount, pahBands);
11583
0
}
11584
11585
/************************************************************************/
11586
/*                               gdal::max()                            */
11587
/************************************************************************/
11588
11589
namespace gdal
11590
{
11591
/** Return a band whose each pixel value is the maximum of the corresponding
11592
 * pixel values in the inputs (bands or constants)
11593
 *
11594
 * The resulting band is lazy evaluated. A reference is taken on input
11595
 * datasets.
11596
 *
11597
 * Two or more bands can be passed.
11598
 *
11599
 * This method is the same as the C function GDALMaximumOfNBands()
11600
 *
11601
 * @since 3.12
11602
 * @throw std::runtime_error if bands do not have the same dimensions.
11603
 */
11604
GDALComputedRasterBand max(const GDALRasterBand &first,
11605
                           const GDALRasterBand &second)
11606
0
{
11607
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11608
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
11609
0
                                  first, second);
11610
0
}
11611
}  // namespace gdal
11612
11613
/************************************************************************/
11614
/*                     GDALRasterBandMaxConstant()                      */
11615
/************************************************************************/
11616
11617
/** Return a band whose each pixel value is the maximum of the corresponding
11618
 * pixel values in the input band and the constant.
11619
 *
11620
 * The resulting band is lazy evaluated. A reference is taken on the input
11621
 * dataset.
11622
 *
11623
 * This function is the same as the C ++ method gdal::max()
11624
 *
11625
 * @since 3.12
11626
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11627
 */
11628
GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
11629
                                                  double dfConstant)
11630
0
{
11631
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
11632
0
        GDALComputedRasterBand::Operation::OP_MAX,
11633
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
11634
0
        dfConstant));
11635
0
}
11636
11637
/************************************************************************/
11638
/*                       GDALMinimumOfNBands()                          */
11639
/************************************************************************/
11640
11641
/** Return a band whose each pixel value is the minimum of the corresponding
11642
 * pixel values in the input bands.
11643
 *
11644
 * The resulting band is lazy evaluated. A reference is taken on input
11645
 * datasets.
11646
 *
11647
 * This function is the same as the C ++ method gdal::min()
11648
 *
11649
 * @since 3.12
11650
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11651
 */
11652
GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
11653
                                            GDALRasterBandH *pahBands)
11654
0
{
11655
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
11656
0
                                 nBandCount, pahBands);
11657
0
}
11658
11659
/************************************************************************/
11660
/*                               gdal::min()                            */
11661
/************************************************************************/
11662
11663
namespace gdal
11664
{
11665
/** Return a band whose each pixel value is the minimum of the corresponding
11666
 * pixel values in the inputs (bands or constants)
11667
 *
11668
 * The resulting band is lazy evaluated. A reference is taken on input
11669
 * datasets.
11670
 *
11671
 * Two or more bands can be passed.
11672
 *
11673
 * This method is the same as the C function GDALMinimumOfNBands()
11674
 *
11675
 * @since 3.12
11676
 * @throw std::runtime_error if bands do not have the same dimensions.
11677
 */
11678
GDALComputedRasterBand min(const GDALRasterBand &first,
11679
                           const GDALRasterBand &second)
11680
0
{
11681
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11682
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
11683
0
                                  first, second);
11684
0
}
11685
}  // namespace gdal
11686
11687
/************************************************************************/
11688
/*                     GDALRasterBandMinConstant()                      */
11689
/************************************************************************/
11690
11691
/** Return a band whose each pixel value is the minimum of the corresponding
11692
 * pixel values in the input band and the constant.
11693
 *
11694
 * The resulting band is lazy evaluated. A reference is taken on the input
11695
 * dataset.
11696
 *
11697
 * This function is the same as the C ++ method gdal::min()
11698
 *
11699
 * @since 3.12
11700
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11701
 */
11702
GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
11703
                                                  double dfConstant)
11704
0
{
11705
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
11706
0
        GDALComputedRasterBand::Operation::OP_MIN,
11707
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
11708
0
        dfConstant));
11709
0
}
11710
11711
/************************************************************************/
11712
/*                         GDALMeanOfNBands()                           */
11713
/************************************************************************/
11714
11715
/** Return a band whose each pixel value is the arithmetic mean of the
11716
 * corresponding pixel values in the input bands.
11717
 *
11718
 * The resulting band is lazy evaluated. A reference is taken on input
11719
 * datasets.
11720
 *
11721
 * This function is the same as the C ++ method gdal::mean()
11722
 *
11723
 * @since 3.12
11724
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11725
 */
11726
GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
11727
                                         GDALRasterBandH *pahBands)
11728
0
{
11729
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
11730
0
                                 nBandCount, pahBands);
11731
0
}
11732
11733
/************************************************************************/
11734
/*                              gdal::mean()                            */
11735
/************************************************************************/
11736
11737
namespace gdal
11738
{
11739
11740
/** Return a band whose each pixel value is the arithmetic mean of the
11741
 * corresponding pixel values in the input bands.
11742
 *
11743
 * The resulting band is lazy evaluated. A reference is taken on input
11744
 * datasets.
11745
 *
11746
 * Two or more bands can be passed.
11747
 *
11748
 * This method is the same as the C function GDALMeanOfNBands()
11749
 *
11750
 * @since 3.12
11751
 * @throw std::runtime_error if bands do not have the same dimensions.
11752
 */
11753
GDALComputedRasterBand mean(const GDALRasterBand &first,
11754
                            const GDALRasterBand &second)
11755
0
{
11756
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11757
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
11758
0
                                  first, second);
11759
0
}
11760
}  // namespace gdal