Coverage Report

Created: 2025-08-28 06:57

/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 bGotInt64NoDataValue;
4057
    int64_t nInt64NoDataValue;
4058
4059
    bool bGotUInt64NoDataValue;
4060
    uint64_t nUInt64NoDataValue;
4061
4062
    bool bGotFloatNoDataValue;
4063
    float fNoDataValue;
4064
4065
    bool bGotFloat16NoDataValue;
4066
    GFloat16 hfNoDataValue;
4067
4068
    GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4069
0
        : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4070
0
          bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4071
0
          bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4072
0
          bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4073
0
          bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4074
0
    {
4075
0
        if (eDataType == GDT_Int64)
4076
0
        {
4077
0
            int nGot = false;
4078
0
            nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4079
0
            bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4080
0
            if (bGotInt64NoDataValue)
4081
0
            {
4082
0
                dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4083
0
                bGotNoDataValue =
4084
0
                    nInt64NoDataValue <=
4085
0
                        std::numeric_limits<int64_t>::max() - 1024 &&
4086
0
                    static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4087
0
            }
4088
0
            else
4089
0
                dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4090
0
        }
4091
0
        else if (eDataType == GDT_UInt64)
4092
0
        {
4093
0
            int nGot = false;
4094
0
            nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4095
0
            bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4096
0
            if (bGotUInt64NoDataValue)
4097
0
            {
4098
0
                dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4099
0
                bGotNoDataValue =
4100
0
                    nUInt64NoDataValue <=
4101
0
                        std::numeric_limits<uint64_t>::max() - 2048 &&
4102
0
                    static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4103
0
            }
4104
0
            else
4105
0
                dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4106
0
        }
4107
0
        else
4108
0
        {
4109
0
            dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4110
0
            bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4111
4112
0
            ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4113
0
                                    fNoDataValue, bGotFloatNoDataValue);
4114
4115
0
            ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4116
0
                                      hfNoDataValue, bGotFloat16NoDataValue);
4117
0
        }
4118
0
    }
4119
};
4120
4121
/************************************************************************/
4122
/*                            ARE_REAL_EQUAL()                          */
4123
/************************************************************************/
4124
4125
inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4126
0
{
4127
0
    using std::abs;
4128
0
    return dfVal1 == dfVal2 || /* Should cover infinity */
4129
0
           abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4130
0
                                      abs(dfVal1 + dfVal2) * ulp;
4131
0
}
4132
4133
/************************************************************************/
4134
/*                            GetHistogram()                            */
4135
/************************************************************************/
4136
4137
/**
4138
 * \brief Compute raster histogram.
4139
 *
4140
 * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4141
 *
4142
 * For example to compute a simple 256 entry histogram of eight bit data,
4143
 * the following would be suitable.  The unusual bounds are to ensure that
4144
 * bucket boundaries don't fall right on integer values causing possible errors
4145
 * due to rounding after scaling.
4146
\code{.cpp}
4147
    GUIntBig anHistogram[256];
4148
4149
    poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4150
                          GDALDummyProgress, nullptr );
4151
\endcode
4152
 *
4153
 * Note that setting bApproxOK will generally result in a subsampling of the
4154
 * file, and will utilize overviews if available.  It should generally
4155
 * produce a representative histogram for the data that is suitable for use
4156
 * in generating histogram based luts for instance.  Generally bApproxOK is
4157
 * much faster than an exactly computed histogram.
4158
 *
4159
 * This method is the same as the C functions GDALGetRasterHistogram() and
4160
 * GDALGetRasterHistogramEx().
4161
 *
4162
 * @param dfMin the lower bound of the histogram.
4163
 * @param dfMax the upper bound of the histogram.
4164
 * @param nBuckets the number of buckets in panHistogram.
4165
 * @param panHistogram array into which the histogram totals are placed.
4166
 * @param bIncludeOutOfRange if TRUE values below the histogram range will
4167
 * mapped into panHistogram[0], and values above will be mapped into
4168
 * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4169
 * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4170
 * @param pfnProgress function to report progress to completion.
4171
 * @param pProgressData application data to pass to pfnProgress.
4172
 *
4173
 * @return CE_None on success, or CE_Failure if something goes wrong.
4174
 */
4175
4176
CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4177
                                    GUIntBig *panHistogram,
4178
                                    int bIncludeOutOfRange, int bApproxOK,
4179
                                    GDALProgressFunc pfnProgress,
4180
                                    void *pProgressData)
4181
4182
0
{
4183
0
    CPLAssert(nullptr != panHistogram);
4184
4185
0
    if (pfnProgress == nullptr)
4186
0
        pfnProgress = GDALDummyProgress;
4187
4188
    /* -------------------------------------------------------------------- */
4189
    /*      If we have overviews, use them for the histogram.               */
4190
    /* -------------------------------------------------------------------- */
4191
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4192
0
    {
4193
        // FIXME: should we use the most reduced overview here or use some
4194
        // minimum number of samples like GDALRasterBand::ComputeStatistics()
4195
        // does?
4196
0
        GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4197
4198
0
        if (poBestOverview != this)
4199
0
        {
4200
0
            return poBestOverview->GetHistogram(
4201
0
                dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4202
0
                bApproxOK, pfnProgress, pProgressData);
4203
0
        }
4204
0
    }
4205
4206
    /* -------------------------------------------------------------------- */
4207
    /*      Read actual data and build histogram.                           */
4208
    /* -------------------------------------------------------------------- */
4209
0
    if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4210
0
    {
4211
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4212
0
        return CE_Failure;
4213
0
    }
4214
4215
    // Written this way to deal with NaN
4216
0
    if (!(dfMax > dfMin))
4217
0
    {
4218
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4219
0
                    "dfMax should be strictly greater than dfMin");
4220
0
        return CE_Failure;
4221
0
    }
4222
4223
0
    GDALRasterIOExtraArg sExtraArg;
4224
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4225
4226
0
    const double dfScale = nBuckets / (dfMax - dfMin);
4227
0
    if (dfScale == 0 || !std::isfinite(dfScale))
4228
0
    {
4229
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4230
0
                    "dfMin and dfMax should be finite values such that "
4231
0
                    "nBuckets / (dfMax - dfMin) is non-zero");
4232
0
        return CE_Failure;
4233
0
    }
4234
0
    memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4235
4236
0
    GDALNoDataValues sNoDataValues(this, eDataType);
4237
0
    GDALRasterBand *poMaskBand = nullptr;
4238
0
    if (!sNoDataValues.bGotNoDataValue)
4239
0
    {
4240
0
        const int l_nMaskFlags = GetMaskFlags();
4241
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
4242
0
            GetColorInterpretation() != GCI_AlphaBand)
4243
0
        {
4244
0
            poMaskBand = GetMaskBand();
4245
0
        }
4246
0
    }
4247
4248
0
    bool bSignedByte = false;
4249
0
    if (eDataType == GDT_Byte)
4250
0
    {
4251
0
        EnablePixelTypeSignedByteWarning(false);
4252
0
        const char *pszPixelType =
4253
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4254
0
        EnablePixelTypeSignedByteWarning(true);
4255
0
        bSignedByte =
4256
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4257
0
    }
4258
4259
0
    if (bApproxOK && HasArbitraryOverviews())
4260
0
    {
4261
        /* --------------------------------------------------------------------
4262
         */
4263
        /*      Figure out how much the image should be reduced to get an */
4264
        /*      approximate value. */
4265
        /* --------------------------------------------------------------------
4266
         */
4267
0
        const double dfReduction =
4268
0
            sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4269
0
                 GDALSTAT_APPROX_NUMSAMPLES);
4270
4271
0
        int nXReduced = nRasterXSize;
4272
0
        int nYReduced = nRasterYSize;
4273
0
        if (dfReduction > 1.0)
4274
0
        {
4275
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4276
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4277
4278
            // Catch the case of huge resizing ratios here
4279
0
            if (nXReduced == 0)
4280
0
                nXReduced = 1;
4281
0
            if (nYReduced == 0)
4282
0
                nYReduced = 1;
4283
0
        }
4284
4285
0
        void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4286
0
                                          nXReduced, nYReduced);
4287
0
        if (!pData)
4288
0
            return CE_Failure;
4289
4290
0
        const CPLErr eErr =
4291
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4292
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4293
0
        if (eErr != CE_None)
4294
0
        {
4295
0
            CPLFree(pData);
4296
0
            return eErr;
4297
0
        }
4298
4299
0
        GByte *pabyMaskData = nullptr;
4300
0
        if (poMaskBand)
4301
0
        {
4302
0
            pabyMaskData =
4303
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4304
0
            if (!pabyMaskData)
4305
0
            {
4306
0
                CPLFree(pData);
4307
0
                return CE_Failure;
4308
0
            }
4309
4310
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4311
0
                                     pabyMaskData, nXReduced, nYReduced,
4312
0
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
4313
0
            {
4314
0
                CPLFree(pData);
4315
0
                CPLFree(pabyMaskData);
4316
0
                return CE_Failure;
4317
0
            }
4318
0
        }
4319
4320
        // This isn't the fastest way to do this, but is easier for now.
4321
0
        for (int iY = 0; iY < nYReduced; iY++)
4322
0
        {
4323
0
            for (int iX = 0; iX < nXReduced; iX++)
4324
0
            {
4325
0
                const int iOffset = iX + iY * nXReduced;
4326
0
                double dfValue = 0.0;
4327
4328
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
4329
0
                    continue;
4330
4331
0
                switch (eDataType)
4332
0
                {
4333
0
                    case GDT_Byte:
4334
0
                    {
4335
0
                        if (bSignedByte)
4336
0
                            dfValue =
4337
0
                                static_cast<signed char *>(pData)[iOffset];
4338
0
                        else
4339
0
                            dfValue = static_cast<GByte *>(pData)[iOffset];
4340
0
                        break;
4341
0
                    }
4342
0
                    case GDT_Int8:
4343
0
                        dfValue = static_cast<GInt8 *>(pData)[iOffset];
4344
0
                        break;
4345
0
                    case GDT_UInt16:
4346
0
                        dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4347
0
                        break;
4348
0
                    case GDT_Int16:
4349
0
                        dfValue = static_cast<GInt16 *>(pData)[iOffset];
4350
0
                        break;
4351
0
                    case GDT_UInt32:
4352
0
                        dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4353
0
                        break;
4354
0
                    case GDT_Int32:
4355
0
                        dfValue = static_cast<GInt32 *>(pData)[iOffset];
4356
0
                        break;
4357
0
                    case GDT_UInt64:
4358
0
                        dfValue = static_cast<double>(
4359
0
                            static_cast<GUInt64 *>(pData)[iOffset]);
4360
0
                        break;
4361
0
                    case GDT_Int64:
4362
0
                        dfValue = static_cast<double>(
4363
0
                            static_cast<GInt64 *>(pData)[iOffset]);
4364
0
                        break;
4365
0
                    case GDT_Float16:
4366
0
                    {
4367
0
                        using namespace std;
4368
0
                        const GFloat16 hfValue =
4369
0
                            static_cast<GFloat16 *>(pData)[iOffset];
4370
0
                        if (isnan(hfValue) ||
4371
0
                            (sNoDataValues.bGotFloat16NoDataValue &&
4372
0
                             ARE_REAL_EQUAL(hfValue,
4373
0
                                            sNoDataValues.hfNoDataValue)))
4374
0
                            continue;
4375
0
                        dfValue = hfValue;
4376
0
                        break;
4377
0
                    }
4378
0
                    case GDT_Float32:
4379
0
                    {
4380
0
                        const float fValue =
4381
0
                            static_cast<float *>(pData)[iOffset];
4382
0
                        if (std::isnan(fValue) ||
4383
0
                            (sNoDataValues.bGotFloatNoDataValue &&
4384
0
                             ARE_REAL_EQUAL(fValue,
4385
0
                                            sNoDataValues.fNoDataValue)))
4386
0
                            continue;
4387
0
                        dfValue = fValue;
4388
0
                        break;
4389
0
                    }
4390
0
                    case GDT_Float64:
4391
0
                        dfValue = static_cast<double *>(pData)[iOffset];
4392
0
                        if (std::isnan(dfValue))
4393
0
                            continue;
4394
0
                        break;
4395
0
                    case GDT_CInt16:
4396
0
                    {
4397
0
                        const double dfReal =
4398
0
                            static_cast<GInt16 *>(pData)[iOffset * 2];
4399
0
                        const double dfImag =
4400
0
                            static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4401
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4402
0
                            continue;
4403
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4404
0
                    }
4405
0
                    break;
4406
0
                    case GDT_CInt32:
4407
0
                    {
4408
0
                        const double dfReal =
4409
0
                            static_cast<GInt32 *>(pData)[iOffset * 2];
4410
0
                        const double dfImag =
4411
0
                            static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4412
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4413
0
                            continue;
4414
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4415
0
                    }
4416
0
                    break;
4417
0
                    case GDT_CFloat16:
4418
0
                    {
4419
0
                        const double dfReal =
4420
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2];
4421
0
                        const double dfImag =
4422
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4423
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4424
0
                            continue;
4425
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4426
0
                        break;
4427
0
                    }
4428
0
                    case GDT_CFloat32:
4429
0
                    {
4430
0
                        const double dfReal =
4431
0
                            static_cast<float *>(pData)[iOffset * 2];
4432
0
                        const double dfImag =
4433
0
                            static_cast<float *>(pData)[iOffset * 2 + 1];
4434
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4435
0
                            continue;
4436
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4437
0
                        break;
4438
0
                    }
4439
0
                    case GDT_CFloat64:
4440
0
                    {
4441
0
                        const double dfReal =
4442
0
                            static_cast<double *>(pData)[iOffset * 2];
4443
0
                        const double dfImag =
4444
0
                            static_cast<double *>(pData)[iOffset * 2 + 1];
4445
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4446
0
                            continue;
4447
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4448
0
                        break;
4449
0
                    }
4450
0
                    case GDT_Unknown:
4451
0
                    case GDT_TypeCount:
4452
0
                        CPLAssert(false);
4453
0
                }
4454
4455
0
                if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4456
0
                    sNoDataValues.bGotNoDataValue &&
4457
0
                    ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4458
0
                    continue;
4459
4460
                // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4461
                // finite, the result of the multiplication cannot be NaN
4462
0
                const double dfIndex = floor((dfValue - dfMin) * dfScale);
4463
4464
0
                if (dfIndex < 0)
4465
0
                {
4466
0
                    if (bIncludeOutOfRange)
4467
0
                        panHistogram[0]++;
4468
0
                }
4469
0
                else if (dfIndex >= nBuckets)
4470
0
                {
4471
0
                    if (bIncludeOutOfRange)
4472
0
                        ++panHistogram[nBuckets - 1];
4473
0
                }
4474
0
                else
4475
0
                {
4476
0
                    ++panHistogram[static_cast<int>(dfIndex)];
4477
0
                }
4478
0
            }
4479
0
        }
4480
4481
0
        CPLFree(pData);
4482
0
        CPLFree(pabyMaskData);
4483
0
    }
4484
0
    else  // No arbitrary overviews.
4485
0
    {
4486
0
        if (!InitBlockInfo())
4487
0
            return CE_Failure;
4488
4489
        /* --------------------------------------------------------------------
4490
         */
4491
        /*      Figure out the ratio of blocks we will read to get an */
4492
        /*      approximate value. */
4493
        /* --------------------------------------------------------------------
4494
         */
4495
4496
0
        int nSampleRate = 1;
4497
0
        if (bApproxOK)
4498
0
        {
4499
0
            nSampleRate = static_cast<int>(std::max(
4500
0
                1.0,
4501
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4502
            // We want to avoid probing only the first column of blocks for
4503
            // a square shaped raster, because it is not unlikely that it may
4504
            // be padding only (#6378).
4505
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4506
0
                nSampleRate += 1;
4507
0
        }
4508
4509
0
        GByte *pabyMaskData = nullptr;
4510
0
        if (poMaskBand)
4511
0
        {
4512
0
            pabyMaskData = static_cast<GByte *>(
4513
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4514
0
            if (!pabyMaskData)
4515
0
            {
4516
0
                return CE_Failure;
4517
0
            }
4518
0
        }
4519
4520
        /* --------------------------------------------------------------------
4521
         */
4522
        /*      Read the blocks, and add to histogram. */
4523
        /* --------------------------------------------------------------------
4524
         */
4525
0
        for (GIntBig iSampleBlock = 0;
4526
0
             iSampleBlock <
4527
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4528
0
             iSampleBlock += nSampleRate)
4529
0
        {
4530
0
            if (!pfnProgress(
4531
0
                    static_cast<double>(iSampleBlock) /
4532
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4533
0
                    "Compute Histogram", pProgressData))
4534
0
            {
4535
0
                CPLFree(pabyMaskData);
4536
0
                return CE_Failure;
4537
0
            }
4538
4539
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4540
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4541
4542
0
            int nXCheck = 0, nYCheck = 0;
4543
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4544
4545
0
            if (poMaskBand &&
4546
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4547
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
4548
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4549
0
                                     0, nBlockXSize, nullptr) != CE_None)
4550
0
            {
4551
0
                CPLFree(pabyMaskData);
4552
0
                return CE_Failure;
4553
0
            }
4554
4555
0
            GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4556
0
            if (poBlock == nullptr)
4557
0
            {
4558
0
                CPLFree(pabyMaskData);
4559
0
                return CE_Failure;
4560
0
            }
4561
4562
0
            void *pData = poBlock->GetDataRef();
4563
4564
            // this is a special case for a common situation.
4565
0
            if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4566
0
                (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4567
0
                nXCheck == nBlockXSize && nBuckets == 256)
4568
0
            {
4569
0
                const GPtrDiff_t nPixels =
4570
0
                    static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4571
0
                GByte *pabyData = static_cast<GByte *>(pData);
4572
4573
0
                for (GPtrDiff_t i = 0; i < nPixels; i++)
4574
0
                {
4575
0
                    if (pabyMaskData && pabyMaskData[i] == 0)
4576
0
                        continue;
4577
0
                    if (!(sNoDataValues.bGotNoDataValue &&
4578
0
                          (pabyData[i] ==
4579
0
                           static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4580
0
                    {
4581
0
                        panHistogram[pabyData[i]]++;
4582
0
                    }
4583
0
                }
4584
4585
0
                poBlock->DropLock();
4586
0
                continue;  // To next sample block.
4587
0
            }
4588
4589
            // This isn't the fastest way to do this, but is easier for now.
4590
0
            for (int iY = 0; iY < nYCheck; iY++)
4591
0
            {
4592
0
                for (int iX = 0; iX < nXCheck; iX++)
4593
0
                {
4594
0
                    const GPtrDiff_t iOffset =
4595
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4596
4597
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
4598
0
                        continue;
4599
4600
0
                    double dfValue = 0.0;
4601
4602
0
                    switch (eDataType)
4603
0
                    {
4604
0
                        case GDT_Byte:
4605
0
                        {
4606
0
                            if (bSignedByte)
4607
0
                                dfValue =
4608
0
                                    static_cast<signed char *>(pData)[iOffset];
4609
0
                            else
4610
0
                                dfValue = static_cast<GByte *>(pData)[iOffset];
4611
0
                            break;
4612
0
                        }
4613
0
                        case GDT_Int8:
4614
0
                            dfValue = static_cast<GInt8 *>(pData)[iOffset];
4615
0
                            break;
4616
0
                        case GDT_UInt16:
4617
0
                            dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4618
0
                            break;
4619
0
                        case GDT_Int16:
4620
0
                            dfValue = static_cast<GInt16 *>(pData)[iOffset];
4621
0
                            break;
4622
0
                        case GDT_UInt32:
4623
0
                            dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4624
0
                            break;
4625
0
                        case GDT_Int32:
4626
0
                            dfValue = static_cast<GInt32 *>(pData)[iOffset];
4627
0
                            break;
4628
0
                        case GDT_UInt64:
4629
0
                            dfValue = static_cast<double>(
4630
0
                                static_cast<GUInt64 *>(pData)[iOffset]);
4631
0
                            break;
4632
0
                        case GDT_Int64:
4633
0
                            dfValue = static_cast<double>(
4634
0
                                static_cast<GInt64 *>(pData)[iOffset]);
4635
0
                            break;
4636
0
                        case GDT_Float16:
4637
0
                        {
4638
0
                            using namespace std;
4639
0
                            const GFloat16 hfValue =
4640
0
                                static_cast<GFloat16 *>(pData)[iOffset];
4641
0
                            if (isnan(hfValue) ||
4642
0
                                (sNoDataValues.bGotFloat16NoDataValue &&
4643
0
                                 ARE_REAL_EQUAL(hfValue,
4644
0
                                                sNoDataValues.hfNoDataValue)))
4645
0
                                continue;
4646
0
                            dfValue = hfValue;
4647
0
                            break;
4648
0
                        }
4649
0
                        case GDT_Float32:
4650
0
                        {
4651
0
                            const float fValue =
4652
0
                                static_cast<float *>(pData)[iOffset];
4653
0
                            if (std::isnan(fValue) ||
4654
0
                                (sNoDataValues.bGotFloatNoDataValue &&
4655
0
                                 ARE_REAL_EQUAL(fValue,
4656
0
                                                sNoDataValues.fNoDataValue)))
4657
0
                                continue;
4658
0
                            dfValue = fValue;
4659
0
                            break;
4660
0
                        }
4661
0
                        case GDT_Float64:
4662
0
                            dfValue = static_cast<double *>(pData)[iOffset];
4663
0
                            if (std::isnan(dfValue))
4664
0
                                continue;
4665
0
                            break;
4666
0
                        case GDT_CInt16:
4667
0
                        {
4668
0
                            double dfReal =
4669
0
                                static_cast<GInt16 *>(pData)[iOffset * 2];
4670
0
                            double dfImag =
4671
0
                                static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4672
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4673
0
                            break;
4674
0
                        }
4675
0
                        case GDT_CInt32:
4676
0
                        {
4677
0
                            double dfReal =
4678
0
                                static_cast<GInt32 *>(pData)[iOffset * 2];
4679
0
                            double dfImag =
4680
0
                                static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4681
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4682
0
                            break;
4683
0
                        }
4684
0
                        case GDT_CFloat16:
4685
0
                        {
4686
0
                            double dfReal =
4687
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2];
4688
0
                            double dfImag =
4689
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4690
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4691
0
                                continue;
4692
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4693
0
                            break;
4694
0
                        }
4695
0
                        case GDT_CFloat32:
4696
0
                        {
4697
0
                            double dfReal =
4698
0
                                static_cast<float *>(pData)[iOffset * 2];
4699
0
                            double dfImag =
4700
0
                                static_cast<float *>(pData)[iOffset * 2 + 1];
4701
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4702
0
                                continue;
4703
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4704
0
                            break;
4705
0
                        }
4706
0
                        case GDT_CFloat64:
4707
0
                        {
4708
0
                            double dfReal =
4709
0
                                static_cast<double *>(pData)[iOffset * 2];
4710
0
                            double dfImag =
4711
0
                                static_cast<double *>(pData)[iOffset * 2 + 1];
4712
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4713
0
                                continue;
4714
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4715
0
                            break;
4716
0
                        }
4717
0
                        case GDT_Unknown:
4718
0
                        case GDT_TypeCount:
4719
0
                            CPLAssert(false);
4720
0
                            CPLFree(pabyMaskData);
4721
0
                            return CE_Failure;
4722
0
                    }
4723
4724
0
                    if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4725
0
                        sNoDataValues.bGotNoDataValue &&
4726
0
                        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4727
0
                        continue;
4728
4729
                    // Given that dfValue and dfMin are not NaN, and dfScale > 0
4730
                    // and finite, the result of the multiplication cannot be
4731
                    // NaN
4732
0
                    const double dfIndex = floor((dfValue - dfMin) * dfScale);
4733
4734
0
                    if (dfIndex < 0)
4735
0
                    {
4736
0
                        if (bIncludeOutOfRange)
4737
0
                            panHistogram[0]++;
4738
0
                    }
4739
0
                    else if (dfIndex >= nBuckets)
4740
0
                    {
4741
0
                        if (bIncludeOutOfRange)
4742
0
                            ++panHistogram[nBuckets - 1];
4743
0
                    }
4744
0
                    else
4745
0
                    {
4746
0
                        ++panHistogram[static_cast<int>(dfIndex)];
4747
0
                    }
4748
0
                }
4749
0
            }
4750
4751
0
            poBlock->DropLock();
4752
0
        }
4753
4754
0
        CPLFree(pabyMaskData);
4755
0
    }
4756
4757
0
    pfnProgress(1.0, "Compute Histogram", pProgressData);
4758
4759
0
    return CE_None;
4760
0
}
4761
4762
/************************************************************************/
4763
/*                       GDALGetRasterHistogram()                       */
4764
/************************************************************************/
4765
4766
/**
4767
 * \brief Compute raster histogram.
4768
 *
4769
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4770
 * exceeding 2 billion.
4771
 *
4772
 * @see GDALRasterBand::GetHistogram()
4773
 * @see GDALGetRasterHistogramEx()
4774
 */
4775
4776
CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4777
                                          double dfMax, int nBuckets,
4778
                                          int *panHistogram,
4779
                                          int bIncludeOutOfRange, int bApproxOK,
4780
                                          GDALProgressFunc pfnProgress,
4781
                                          void *pProgressData)
4782
4783
0
{
4784
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4785
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4786
4787
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4788
4789
0
    GUIntBig *panHistogramTemp =
4790
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4791
0
    if (panHistogramTemp == nullptr)
4792
0
    {
4793
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4794
0
                            "Out of memory in GDALGetRasterHistogram().");
4795
0
        return CE_Failure;
4796
0
    }
4797
4798
0
    CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4799
0
                                       bIncludeOutOfRange, bApproxOK,
4800
0
                                       pfnProgress, pProgressData);
4801
4802
0
    if (eErr == CE_None)
4803
0
    {
4804
0
        for (int i = 0; i < nBuckets; i++)
4805
0
        {
4806
0
            if (panHistogramTemp[i] > INT_MAX)
4807
0
            {
4808
0
                CPLError(CE_Warning, CPLE_AppDefined,
4809
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
4810
0
                         " exceeds maximum 32 bit value",
4811
0
                         i, panHistogramTemp[i]);
4812
0
                panHistogram[i] = INT_MAX;
4813
0
            }
4814
0
            else
4815
0
            {
4816
0
                panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4817
0
            }
4818
0
        }
4819
0
    }
4820
4821
0
    CPLFree(panHistogramTemp);
4822
4823
0
    return eErr;
4824
0
}
4825
4826
/************************************************************************/
4827
/*                      GDALGetRasterHistogramEx()                      */
4828
/************************************************************************/
4829
4830
/**
4831
 * \brief Compute raster histogram.
4832
 *
4833
 * @see GDALRasterBand::GetHistogram()
4834
 *
4835
 * @since GDAL 2.0
4836
 */
4837
4838
CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4839
    GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4840
    GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4841
    GDALProgressFunc pfnProgress, void *pProgressData)
4842
4843
0
{
4844
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4845
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4846
4847
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4848
4849
0
    return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4850
0
                                bIncludeOutOfRange, bApproxOK, pfnProgress,
4851
0
                                pProgressData);
4852
0
}
4853
4854
/************************************************************************/
4855
/*                        GetDefaultHistogram()                         */
4856
/************************************************************************/
4857
4858
/**
4859
 * \brief Fetch default raster histogram.
4860
 *
4861
 * The default method in GDALRasterBand will compute a default histogram. This
4862
 * method is overridden by derived classes (such as GDALPamRasterBand,
4863
 * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4864
 * stored histogram.
4865
 *
4866
 * This method is the same as the C functions GDALGetDefaultHistogram() and
4867
 * GDALGetDefaultHistogramEx().
4868
 *
4869
 * @param pdfMin pointer to double value that will contain the lower bound of
4870
 * the histogram.
4871
 * @param pdfMax pointer to double value that will contain the upper bound of
4872
 * the histogram.
4873
 * @param pnBuckets pointer to int value that will contain the number of buckets
4874
 * in *ppanHistogram.
4875
 * @param ppanHistogram pointer to array into which the histogram totals are
4876
 * placed. To be freed with VSIFree
4877
 * @param bForce TRUE to force the computation. If FALSE and no default
4878
 * histogram is available, the method will return CE_Warning
4879
 * @param pfnProgress function to report progress to completion.
4880
 * @param pProgressData application data to pass to pfnProgress.
4881
 *
4882
 * @return CE_None on success, CE_Failure if something goes wrong, or
4883
 * CE_Warning if no default histogram is available.
4884
 */
4885
4886
CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4887
                                           int *pnBuckets,
4888
                                           GUIntBig **ppanHistogram, int bForce,
4889
                                           GDALProgressFunc pfnProgress,
4890
                                           void *pProgressData)
4891
4892
0
{
4893
0
    CPLAssert(nullptr != pnBuckets);
4894
0
    CPLAssert(nullptr != ppanHistogram);
4895
0
    CPLAssert(nullptr != pdfMin);
4896
0
    CPLAssert(nullptr != pdfMax);
4897
4898
0
    *pnBuckets = 0;
4899
0
    *ppanHistogram = nullptr;
4900
4901
0
    if (!bForce)
4902
0
        return CE_Warning;
4903
4904
0
    int nBuckets = 256;
4905
4906
0
    bool bSignedByte = false;
4907
0
    if (eDataType == GDT_Byte)
4908
0
    {
4909
0
        EnablePixelTypeSignedByteWarning(false);
4910
0
        const char *pszPixelType =
4911
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4912
0
        EnablePixelTypeSignedByteWarning(true);
4913
0
        bSignedByte =
4914
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4915
0
    }
4916
4917
0
    if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4918
0
    {
4919
0
        *pdfMin = -0.5;
4920
0
        *pdfMax = 255.5;
4921
0
    }
4922
0
    else if (GetRasterDataType() == GDT_Int8)
4923
0
    {
4924
0
        *pdfMin = -128 - 0.5;
4925
0
        *pdfMax = 127 + 0.5;
4926
0
    }
4927
0
    else
4928
0
    {
4929
4930
0
        const CPLErr eErr =
4931
0
            GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4932
0
        if (eErr != CE_None)
4933
0
            return eErr;
4934
0
        if (*pdfMin == *pdfMax)
4935
0
        {
4936
0
            nBuckets = 1;
4937
0
            *pdfMin -= 0.5;
4938
0
            *pdfMax += 0.5;
4939
0
        }
4940
0
        else
4941
0
        {
4942
0
            const double dfHalfBucket =
4943
0
                (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4944
0
            *pdfMin -= dfHalfBucket;
4945
0
            *pdfMax += dfHalfBucket;
4946
0
        }
4947
0
    }
4948
4949
0
    *ppanHistogram =
4950
0
        static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4951
0
    if (*ppanHistogram == nullptr)
4952
0
    {
4953
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
4954
0
                    "Out of memory in InitBlockInfo().");
4955
0
        return CE_Failure;
4956
0
    }
4957
4958
0
    *pnBuckets = nBuckets;
4959
0
    CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4960
0
                               TRUE, FALSE, pfnProgress, pProgressData);
4961
0
    if (eErr != CE_None)
4962
0
    {
4963
0
        *pnBuckets = 0;
4964
0
    }
4965
0
    return eErr;
4966
0
}
4967
4968
/************************************************************************/
4969
/*                      GDALGetDefaultHistogram()                       */
4970
/************************************************************************/
4971
4972
/**
4973
 * \brief Fetch default raster histogram.
4974
 *
4975
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4976
 * exceeding 2 billion.
4977
 *
4978
 * @see GDALRasterBand::GDALGetDefaultHistogram()
4979
 * @see GDALGetRasterHistogramEx()
4980
 */
4981
4982
CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4983
                                           double *pdfMin, double *pdfMax,
4984
                                           int *pnBuckets, int **ppanHistogram,
4985
                                           int bForce,
4986
                                           GDALProgressFunc pfnProgress,
4987
                                           void *pProgressData)
4988
4989
0
{
4990
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4991
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4992
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4993
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4994
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4995
4996
0
    GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4997
0
    GUIntBig *panHistogramTemp = nullptr;
4998
0
    CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
4999
0
                                              &panHistogramTemp, bForce,
5000
0
                                              pfnProgress, pProgressData);
5001
0
    if (eErr == CE_None)
5002
0
    {
5003
0
        const int nBuckets = *pnBuckets;
5004
0
        *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5005
0
        if (*ppanHistogram == nullptr)
5006
0
        {
5007
0
            poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5008
0
                                "Out of memory in GDALGetDefaultHistogram().");
5009
0
            VSIFree(panHistogramTemp);
5010
0
            return CE_Failure;
5011
0
        }
5012
5013
0
        for (int i = 0; i < nBuckets; ++i)
5014
0
        {
5015
0
            if (panHistogramTemp[i] > INT_MAX)
5016
0
            {
5017
0
                CPLError(CE_Warning, CPLE_AppDefined,
5018
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
5019
0
                         " exceeds maximum 32 bit value",
5020
0
                         i, panHistogramTemp[i]);
5021
0
                (*ppanHistogram)[i] = INT_MAX;
5022
0
            }
5023
0
            else
5024
0
            {
5025
0
                (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5026
0
            }
5027
0
        }
5028
5029
0
        CPLFree(panHistogramTemp);
5030
0
    }
5031
0
    else
5032
0
    {
5033
0
        *ppanHistogram = nullptr;
5034
0
    }
5035
5036
0
    return eErr;
5037
0
}
5038
5039
/************************************************************************/
5040
/*                      GDALGetDefaultHistogramEx()                     */
5041
/************************************************************************/
5042
5043
/**
5044
 * \brief Fetch default raster histogram.
5045
 *
5046
 * @see GDALRasterBand::GetDefaultHistogram()
5047
 *
5048
 * @since GDAL 2.0
5049
 */
5050
5051
CPLErr CPL_STDCALL
5052
GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5053
                          int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5054
                          GDALProgressFunc pfnProgress, void *pProgressData)
5055
5056
0
{
5057
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5058
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5059
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5060
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5061
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5062
5063
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5064
0
    return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5065
0
                                       bForce, pfnProgress, pProgressData);
5066
0
}
5067
5068
/************************************************************************/
5069
/*                             AdviseRead()                             */
5070
/************************************************************************/
5071
5072
/**
5073
 * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5074
 * \brief Advise driver of upcoming read requests.
5075
 *
5076
 * Some GDAL drivers operate more efficiently if they know in advance what
5077
 * set of upcoming read requests will be made.  The AdviseRead() method allows
5078
 * an application to notify the driver of the region of interest,
5079
 * and at what resolution the region will be read.
5080
 *
5081
 * Many drivers just ignore the AdviseRead() call, but it can dramatically
5082
 * accelerate access via some drivers.
5083
 *
5084
 * Depending on call paths, drivers might receive several calls to
5085
 * AdviseRead() with the same parameters.
5086
 *
5087
 * @param nXOff The pixel offset to the top left corner of the region
5088
 * of the band to be accessed.  This would be zero to start from the left side.
5089
 *
5090
 * @param nYOff The line offset to the top left corner of the region
5091
 * of the band to be accessed.  This would be zero to start from the top.
5092
 *
5093
 * @param nXSize The width of the region of the band to be accessed in pixels.
5094
 *
5095
 * @param nYSize The height of the region of the band to be accessed in lines.
5096
 *
5097
 * @param nBufXSize the width of the buffer image into which the desired region
5098
 * is to be read, or from which it is to be written.
5099
 *
5100
 * @param nBufYSize the height of the buffer image into which the desired
5101
 * region is to be read, or from which it is to be written.
5102
 *
5103
 * @param eBufType the type of the pixel values in the pData data buffer.  The
5104
 * pixel values will automatically be translated to/from the GDALRasterBand
5105
 * data type as needed.
5106
 *
5107
 * @param papszOptions a list of name=value strings with special control
5108
 * options.  Normally this is NULL.
5109
 *
5110
 * @return CE_Failure if the request is invalid and CE_None if it works or
5111
 * is ignored.
5112
 */
5113
5114
/**/
5115
/**/
5116
5117
CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5118
                                  int /*nYSize*/, int /*nBufXSize*/,
5119
                                  int /*nBufYSize*/, GDALDataType /*eBufType*/,
5120
                                  char ** /*papszOptions*/)
5121
0
{
5122
0
    return CE_None;
5123
0
}
5124
5125
/************************************************************************/
5126
/*                        GDALRasterAdviseRead()                        */
5127
/************************************************************************/
5128
5129
/**
5130
 * \brief Advise driver of upcoming read requests.
5131
 *
5132
 * @see GDALRasterBand::AdviseRead()
5133
 */
5134
5135
CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5136
                                        int nYOff, int nXSize, int nYSize,
5137
                                        int nBufXSize, int nBufYSize,
5138
                                        GDALDataType eDT,
5139
                                        CSLConstList papszOptions)
5140
5141
0
{
5142
0
    VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5143
5144
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5145
0
    return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5146
0
                              nBufYSize, eDT,
5147
0
                              const_cast<char **>(papszOptions));
5148
0
}
5149
5150
/************************************************************************/
5151
/*                           GetStatistics()                            */
5152
/************************************************************************/
5153
5154
/**
5155
 * \brief Fetch image statistics.
5156
 *
5157
 * Returns the minimum, maximum, mean and standard deviation of all
5158
 * pixel values in this band.  If approximate statistics are sufficient,
5159
 * the bApproxOK flag can be set to true in which case overviews, or a
5160
 * subset of image tiles may be used in computing the statistics.
5161
 *
5162
 * If bForce is FALSE results will only be returned if it can be done
5163
 * quickly (i.e. without scanning the image, typically by using pre-existing
5164
 * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5165
 * returned efficiently, the method will return CE_Warning but no warning will
5166
 * be issued. This is a non-standard use of the CE_Warning return value
5167
 * to indicate "nothing done".
5168
 *
5169
 * If bForce is TRUE, and results are quickly available without scanning the
5170
 * image, they will be used. If bForce is TRUE and results are not quickly
5171
 * available, GetStatistics() forwards the computation to ComputeStatistics(),
5172
 * which will scan the image.
5173
 *
5174
 * To always force recomputation of statistics, use ComputeStatistics() instead
5175
 * of this method.
5176
 *
5177
 * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5178
 * will generally cache statistics in the .pam file allowing fast fetch
5179
 * after the first request.
5180
 *
5181
 * This method is the same as the C function GDALGetRasterStatistics().
5182
 *
5183
 * @param bApproxOK If TRUE statistics may be computed based on overviews
5184
 * or a subset of all tiles.
5185
 *
5186
 * @param bForce If FALSE statistics will only be returned if it can
5187
 * be done without rescanning the image. If TRUE, statistics computation will
5188
 * be forced if pre-existing values are not quickly available.
5189
 *
5190
 * @param pdfMin Location into which to load image minimum (may be NULL).
5191
 *
5192
 * @param pdfMax Location into which to load image maximum (may be NULL).-
5193
 *
5194
 * @param pdfMean Location into which to load image mean (may be NULL).
5195
 *
5196
 * @param pdfStdDev Location into which to load image standard deviation
5197
 * (may be NULL).
5198
 *
5199
 * @return CE_None on success, CE_Warning if no values returned,
5200
 * CE_Failure if an error occurs.
5201
 */
5202
5203
CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5204
                                     double *pdfMax, double *pdfMean,
5205
                                     double *pdfStdDev)
5206
5207
0
{
5208
    /* -------------------------------------------------------------------- */
5209
    /*      Do we already have metadata items for the requested values?     */
5210
    /* -------------------------------------------------------------------- */
5211
0
    if ((pdfMin == nullptr ||
5212
0
         GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5213
0
        (pdfMax == nullptr ||
5214
0
         GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5215
0
        (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5216
0
        (pdfStdDev == nullptr ||
5217
0
         GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5218
0
    {
5219
0
        if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5220
0
        {
5221
0
            if (pdfMin != nullptr)
5222
0
                *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5223
0
            if (pdfMax != nullptr)
5224
0
                *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5225
0
            if (pdfMean != nullptr)
5226
0
                *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5227
0
            if (pdfStdDev != nullptr)
5228
0
                *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5229
5230
0
            return CE_None;
5231
0
        }
5232
0
    }
5233
5234
    /* -------------------------------------------------------------------- */
5235
    /*      Does the driver already know the min/max?                       */
5236
    /* -------------------------------------------------------------------- */
5237
0
    if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5238
0
    {
5239
0
        int bSuccessMin = FALSE;
5240
0
        int bSuccessMax = FALSE;
5241
5242
0
        const double dfMin = GetMinimum(&bSuccessMin);
5243
0
        const double dfMax = GetMaximum(&bSuccessMax);
5244
5245
0
        if (bSuccessMin && bSuccessMax)
5246
0
        {
5247
0
            if (pdfMin != nullptr)
5248
0
                *pdfMin = dfMin;
5249
0
            if (pdfMax != nullptr)
5250
0
                *pdfMax = dfMax;
5251
0
            return CE_None;
5252
0
        }
5253
0
    }
5254
5255
    /* -------------------------------------------------------------------- */
5256
    /*      Either return without results, or force computation.            */
5257
    /* -------------------------------------------------------------------- */
5258
0
    if (!bForce)
5259
0
        return CE_Warning;
5260
0
    else
5261
0
        return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5262
0
                                 GDALDummyProgress, nullptr);
5263
0
}
5264
5265
/************************************************************************/
5266
/*                      GDALGetRasterStatistics()                       */
5267
/************************************************************************/
5268
5269
/**
5270
 * \brief Fetch image statistics.
5271
 *
5272
 * @see GDALRasterBand::GetStatistics()
5273
 */
5274
5275
CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5276
                                           int bForce, double *pdfMin,
5277
                                           double *pdfMax, double *pdfMean,
5278
                                           double *pdfStdDev)
5279
5280
0
{
5281
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5282
5283
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5284
0
    return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5285
0
                                 pdfStdDev);
5286
0
}
5287
5288
/************************************************************************/
5289
/*                         GDALUInt128                                  */
5290
/************************************************************************/
5291
5292
#ifdef HAVE_UINT128_T
5293
class GDALUInt128
5294
{
5295
    __uint128_t val;
5296
5297
0
    explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5298
0
    {
5299
0
    }
5300
5301
  public:
5302
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5303
0
    {
5304
        // Evaluates to just a single mul on x86_64
5305
0
        return GDALUInt128(static_cast<__uint128_t>(first) * second);
5306
0
    }
5307
5308
    GDALUInt128 operator-(const GDALUInt128 &other) const
5309
0
    {
5310
0
        return GDALUInt128(val - other.val);
5311
0
    }
5312
5313
    operator double() const
5314
0
    {
5315
0
        return static_cast<double>(val);
5316
0
    }
5317
};
5318
#else
5319
5320
#if defined(_MSC_VER) && defined(_M_X64)
5321
#include <intrin.h>
5322
#endif
5323
5324
class GDALUInt128
5325
{
5326
    GUIntBig low, high;
5327
5328
    GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5329
    {
5330
    }
5331
5332
  public:
5333
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5334
    {
5335
#if defined(_MSC_VER) && defined(_M_X64)
5336
        GUIntBig highRes;
5337
        GUIntBig lowRes = _umul128(first, second, &highRes);
5338
        return GDALUInt128(lowRes, highRes);
5339
#else
5340
        const GUInt32 firstLow = static_cast<GUInt32>(first);
5341
        const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5342
        const GUInt32 secondLow = static_cast<GUInt32>(second);
5343
        const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5344
        GUIntBig highRes = 0;
5345
        const GUIntBig firstLowSecondHigh =
5346
            static_cast<GUIntBig>(firstLow) * secondHigh;
5347
        const GUIntBig firstHighSecondLow =
5348
            static_cast<GUIntBig>(firstHigh) * secondLow;
5349
        const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5350
        if (middleTerm < firstLowSecondHigh)  // check for overflow
5351
            highRes += static_cast<GUIntBig>(1) << 32;
5352
        const GUIntBig firstLowSecondLow =
5353
            static_cast<GUIntBig>(firstLow) * secondLow;
5354
        GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5355
        if (lowRes < firstLowSecondLow)  // check for overflow
5356
            highRes++;
5357
        highRes +=
5358
            (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5359
        return GDALUInt128(lowRes, highRes);
5360
#endif
5361
    }
5362
5363
    GDALUInt128 operator-(const GDALUInt128 &other) const
5364
    {
5365
        GUIntBig highRes = high - other.high;
5366
        GUIntBig lowRes = low - other.low;
5367
        if (lowRes > low)  // check for underflow
5368
            --highRes;
5369
        return GDALUInt128(lowRes, highRes);
5370
    }
5371
5372
    operator double() const
5373
    {
5374
        const double twoPow64 = 18446744073709551616.0;
5375
        return high * twoPow64 + low;
5376
    }
5377
};
5378
#endif
5379
5380
/************************************************************************/
5381
/*                    ComputeStatisticsInternal()                       */
5382
/************************************************************************/
5383
5384
// Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5385
// not needed.
5386
0
#define static_cast_for_coverity_scan static_cast
5387
5388
// The rationale for below optimizations is detailed in statistics.txt
5389
5390
// Use with T = GByte or GUInt16 only !
5391
template <class T, bool COMPUTE_OTHER_STATS>
5392
struct ComputeStatisticsInternalGeneric
5393
{
5394
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5395
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5396
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5397
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5398
0
    {
5399
0
        static_assert(std::is_same<T, GByte>::value ||
5400
0
                          std::is_same<T, GUInt16>::value,
5401
0
                      "bad type for T");
5402
0
        if (bHasNoData)
5403
0
        {
5404
            // General case
5405
0
            for (int iY = 0; iY < nYCheck; iY++)
5406
0
            {
5407
0
                for (int iX = 0; iX < nXCheck; iX++)
5408
0
                {
5409
0
                    const GPtrDiff_t iOffset =
5410
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5411
0
                    const GUInt32 nValue = pData[iOffset];
5412
0
                    if (nValue == nNoDataValue)
5413
0
                        continue;
5414
0
                    if (nValue < nMin)
5415
0
                        nMin = nValue;
5416
0
                    if (nValue > nMax)
5417
0
                        nMax = nValue;
5418
                    if constexpr (COMPUTE_OTHER_STATS)
5419
0
                    {
5420
0
                        nValidCount++;
5421
0
                        nSum += nValue;
5422
0
                        nSumSquare +=
5423
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5424
0
                            nValue;
5425
0
                    }
5426
0
                }
5427
0
            }
5428
            if constexpr (COMPUTE_OTHER_STATS)
5429
0
            {
5430
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5431
0
            }
5432
0
        }
5433
0
        else if (nMin == std::numeric_limits<T>::lowest() &&
5434
0
                 nMax == std::numeric_limits<T>::max())
5435
0
        {
5436
            if constexpr (COMPUTE_OTHER_STATS)
5437
0
            {
5438
                // Optimization when there is no nodata and we know we have already
5439
                // reached the min and max
5440
0
                for (int iY = 0; iY < nYCheck; iY++)
5441
0
                {
5442
0
                    int iX;
5443
0
                    for (iX = 0; iX + 3 < nXCheck; iX += 4)
5444
0
                    {
5445
0
                        const GPtrDiff_t iOffset =
5446
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5447
0
                        const GUIntBig nValue = pData[iOffset];
5448
0
                        const GUIntBig nValue2 = pData[iOffset + 1];
5449
0
                        const GUIntBig nValue3 = pData[iOffset + 2];
5450
0
                        const GUIntBig nValue4 = pData[iOffset + 3];
5451
0
                        nSum += nValue;
5452
0
                        nSumSquare += nValue * nValue;
5453
0
                        nSum += nValue2;
5454
0
                        nSumSquare += nValue2 * nValue2;
5455
0
                        nSum += nValue3;
5456
0
                        nSumSquare += nValue3 * nValue3;
5457
0
                        nSum += nValue4;
5458
0
                        nSumSquare += nValue4 * nValue4;
5459
0
                    }
5460
0
                    for (; iX < nXCheck; ++iX)
5461
0
                    {
5462
0
                        const GPtrDiff_t iOffset =
5463
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5464
0
                        const GUIntBig nValue = pData[iOffset];
5465
0
                        nSum += nValue;
5466
0
                        nSumSquare += nValue * nValue;
5467
0
                    }
5468
0
                }
5469
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5470
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5471
0
            }
5472
0
        }
5473
0
        else
5474
0
        {
5475
0
            for (int iY = 0; iY < nYCheck; iY++)
5476
0
            {
5477
0
                int iX;
5478
0
                for (iX = 0; iX + 1 < nXCheck; iX += 2)
5479
0
                {
5480
0
                    const GPtrDiff_t iOffset =
5481
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5482
0
                    const GUInt32 nValue = pData[iOffset];
5483
0
                    const GUInt32 nValue2 = pData[iOffset + 1];
5484
0
                    if (nValue < nValue2)
5485
0
                    {
5486
0
                        if (nValue < nMin)
5487
0
                            nMin = nValue;
5488
0
                        if (nValue2 > nMax)
5489
0
                            nMax = nValue2;
5490
0
                    }
5491
0
                    else
5492
0
                    {
5493
0
                        if (nValue2 < nMin)
5494
0
                            nMin = nValue2;
5495
0
                        if (nValue > nMax)
5496
0
                            nMax = nValue;
5497
0
                    }
5498
                    if constexpr (COMPUTE_OTHER_STATS)
5499
0
                    {
5500
0
                        nSum += nValue;
5501
0
                        nSumSquare +=
5502
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5503
0
                            nValue;
5504
0
                        nSum += nValue2;
5505
0
                        nSumSquare +=
5506
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5507
0
                            nValue2;
5508
0
                    }
5509
0
                }
5510
0
                if (iX < nXCheck)
5511
0
                {
5512
0
                    const GPtrDiff_t iOffset =
5513
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5514
0
                    const GUInt32 nValue = pData[iOffset];
5515
0
                    if (nValue < nMin)
5516
0
                        nMin = nValue;
5517
0
                    if (nValue > nMax)
5518
0
                        nMax = nValue;
5519
0
                    if (COMPUTE_OTHER_STATS)
5520
0
                    {
5521
0
                        nSum += nValue;
5522
0
                        nSumSquare +=
5523
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5524
0
                            nValue;
5525
0
                    }
5526
0
                }
5527
0
            }
5528
            if constexpr (COMPUTE_OTHER_STATS)
5529
0
            {
5530
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5531
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5532
0
            }
5533
0
        }
5534
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&)
5535
};
5536
5537
// Specialization for Byte that is mostly 32 bit friendly as it avoids
5538
// using 64bit accumulators in internal loops. This also slightly helps in
5539
// 64bit mode.
5540
template <bool COMPUTE_OTHER_STATS>
5541
struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5542
{
5543
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5544
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5545
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5546
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5547
0
    {
5548
0
        int nOuterLoops = nXCheck / 65536;
5549
0
        if (nXCheck % 65536)
5550
0
            nOuterLoops++;
5551
5552
0
        if (bHasNoData)
5553
0
        {
5554
            // General case
5555
0
            for (int iY = 0; iY < nYCheck; iY++)
5556
0
            {
5557
0
                int iX = 0;
5558
0
                for (int k = 0; k < nOuterLoops; k++)
5559
0
                {
5560
0
                    int iMax = iX + 65536;
5561
0
                    if (iMax > nXCheck)
5562
0
                        iMax = nXCheck;
5563
0
                    GUInt32 nSum32bit = 0;
5564
0
                    GUInt32 nSumSquare32bit = 0;
5565
0
                    GUInt32 nValidCount32bit = 0;
5566
0
                    GUInt32 nSampleCount32bit = 0;
5567
0
                    for (; iX < iMax; iX++)
5568
0
                    {
5569
0
                        const GPtrDiff_t iOffset =
5570
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5571
0
                        const GUInt32 nValue = pData[iOffset];
5572
5573
0
                        nSampleCount32bit++;
5574
0
                        if (nValue == nNoDataValue)
5575
0
                            continue;
5576
0
                        if (nValue < nMin)
5577
0
                            nMin = nValue;
5578
0
                        if (nValue > nMax)
5579
0
                            nMax = nValue;
5580
                        if constexpr (COMPUTE_OTHER_STATS)
5581
0
                        {
5582
0
                            nValidCount32bit++;
5583
0
                            nSum32bit += nValue;
5584
0
                            nSumSquare32bit += nValue * nValue;
5585
0
                        }
5586
0
                    }
5587
                    if constexpr (COMPUTE_OTHER_STATS)
5588
0
                    {
5589
0
                        nSampleCount += nSampleCount32bit;
5590
0
                        nValidCount += nValidCount32bit;
5591
0
                        nSum += nSum32bit;
5592
0
                        nSumSquare += nSumSquare32bit;
5593
0
                    }
5594
0
                }
5595
0
            }
5596
0
        }
5597
0
        else if (nMin == 0 && nMax == 255)
5598
0
        {
5599
            if constexpr (COMPUTE_OTHER_STATS)
5600
0
            {
5601
                // Optimization when there is no nodata and we know we have already
5602
                // reached the min and max
5603
0
                for (int iY = 0; iY < nYCheck; iY++)
5604
0
                {
5605
0
                    int iX = 0;
5606
0
                    for (int k = 0; k < nOuterLoops; k++)
5607
0
                    {
5608
0
                        int iMax = iX + 65536;
5609
0
                        if (iMax > nXCheck)
5610
0
                            iMax = nXCheck;
5611
0
                        GUInt32 nSum32bit = 0;
5612
0
                        GUInt32 nSumSquare32bit = 0;
5613
0
                        for (; iX + 3 < iMax; iX += 4)
5614
0
                        {
5615
0
                            const GPtrDiff_t iOffset =
5616
0
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5617
0
                            const GUInt32 nValue = pData[iOffset];
5618
0
                            const GUInt32 nValue2 = pData[iOffset + 1];
5619
0
                            const GUInt32 nValue3 = pData[iOffset + 2];
5620
0
                            const GUInt32 nValue4 = pData[iOffset + 3];
5621
0
                            nSum32bit += nValue;
5622
0
                            nSumSquare32bit += nValue * nValue;
5623
0
                            nSum32bit += nValue2;
5624
0
                            nSumSquare32bit += nValue2 * nValue2;
5625
0
                            nSum32bit += nValue3;
5626
0
                            nSumSquare32bit += nValue3 * nValue3;
5627
0
                            nSum32bit += nValue4;
5628
0
                            nSumSquare32bit += nValue4 * nValue4;
5629
0
                        }
5630
0
                        nSum += nSum32bit;
5631
0
                        nSumSquare += nSumSquare32bit;
5632
0
                    }
5633
0
                    for (; iX < nXCheck; ++iX)
5634
0
                    {
5635
0
                        const GPtrDiff_t iOffset =
5636
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5637
0
                        const GUIntBig nValue = pData[iOffset];
5638
0
                        nSum += nValue;
5639
0
                        nSumSquare += nValue * nValue;
5640
0
                    }
5641
0
                }
5642
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5643
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5644
0
            }
5645
0
        }
5646
0
        else
5647
0
        {
5648
0
            for (int iY = 0; iY < nYCheck; iY++)
5649
0
            {
5650
0
                int iX = 0;
5651
0
                for (int k = 0; k < nOuterLoops; k++)
5652
0
                {
5653
0
                    int iMax = iX + 65536;
5654
0
                    if (iMax > nXCheck)
5655
0
                        iMax = nXCheck;
5656
0
                    GUInt32 nSum32bit = 0;
5657
0
                    GUInt32 nSumSquare32bit = 0;
5658
0
                    for (; iX + 1 < iMax; iX += 2)
5659
0
                    {
5660
0
                        const GPtrDiff_t iOffset =
5661
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5662
0
                        const GUInt32 nValue = pData[iOffset];
5663
0
                        const GUInt32 nValue2 = pData[iOffset + 1];
5664
0
                        if (nValue < nValue2)
5665
0
                        {
5666
0
                            if (nValue < nMin)
5667
0
                                nMin = nValue;
5668
0
                            if (nValue2 > nMax)
5669
0
                                nMax = nValue2;
5670
0
                        }
5671
0
                        else
5672
0
                        {
5673
0
                            if (nValue2 < nMin)
5674
0
                                nMin = nValue2;
5675
0
                            if (nValue > nMax)
5676
0
                                nMax = nValue;
5677
0
                        }
5678
                        if constexpr (COMPUTE_OTHER_STATS)
5679
0
                        {
5680
0
                            nSum32bit += nValue;
5681
0
                            nSumSquare32bit += nValue * nValue;
5682
0
                            nSum32bit += nValue2;
5683
0
                            nSumSquare32bit += nValue2 * nValue2;
5684
0
                        }
5685
0
                    }
5686
                    if constexpr (COMPUTE_OTHER_STATS)
5687
0
                    {
5688
0
                        nSum += nSum32bit;
5689
0
                        nSumSquare += nSumSquare32bit;
5690
0
                    }
5691
0
                }
5692
0
                if (iX < nXCheck)
5693
0
                {
5694
0
                    const GPtrDiff_t iOffset =
5695
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5696
0
                    const GUInt32 nValue = pData[iOffset];
5697
0
                    if (nValue < nMin)
5698
0
                        nMin = nValue;
5699
0
                    if (nValue > nMax)
5700
0
                        nMax = nValue;
5701
                    if constexpr (COMPUTE_OTHER_STATS)
5702
0
                    {
5703
0
                        nSum += nValue;
5704
0
                        nSumSquare +=
5705
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5706
0
                            nValue;
5707
0
                    }
5708
0
                }
5709
0
            }
5710
            if constexpr (COMPUTE_OTHER_STATS)
5711
0
            {
5712
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5713
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5714
0
            }
5715
0
        }
5716
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&)
5717
};
5718
5719
template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5720
{
5721
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5722
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5723
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5724
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5725
    {
5726
        ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5727
            nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5728
            nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5729
    }
5730
};
5731
5732
#if (defined(__x86_64__) || defined(_M_X64)) &&                                \
5733
    (defined(__GNUC__) || defined(_MSC_VER))
5734
5735
#include "gdal_avx2_emulation.hpp"
5736
5737
0
#define ZERO256 GDALmm256_setzero_si256()
5738
5739
template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5740
static void
5741
ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5742
                              // assumed to be aligned on 256 bits
5743
                              const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5744
                              GUIntBig &nSum, GUIntBig &nSumSquare,
5745
                              GUIntBig &nSampleCount, GUIntBig &nValidCount)
5746
0
{
5747
    // 32-byte alignment may not be enforced by linker, so do it at hand
5748
0
    GByte
5749
0
        aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5750
0
    GByte *paby32ByteAligned =
5751
0
        aby32ByteUnaligned +
5752
0
        (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5753
0
    GByte *pabyMin = paby32ByteAligned;
5754
0
    GByte *pabyMax = paby32ByteAligned + 32;
5755
0
    GUInt32 *panSum =
5756
0
        COMPUTE_OTHER_STATS
5757
0
            ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5758
0
            : nullptr;
5759
0
    GUInt32 *panSumSquare =
5760
0
        COMPUTE_OTHER_STATS
5761
0
            ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5762
0
            : nullptr;
5763
5764
0
    CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5765
5766
0
    GPtrDiff_t i = 0;
5767
    // Make sure that sumSquare can fit on uint32
5768
    // * 8 since we can hold 8 sums per vector register
5769
0
    const int nMaxIterationsPerInnerLoop =
5770
0
        8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5771
0
    GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5772
0
    if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5773
0
        nOuterLoops++;
5774
5775
0
    GDALm256i ymm_min =
5776
0
        GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5777
0
    GDALm256i ymm_max = ymm_min;
5778
0
    [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5779
5780
0
    for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5781
0
    {
5782
0
        const auto iMax =
5783
0
            std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5784
5785
        // holds 4 uint32 sums in [0], [2], [4] and [6]
5786
0
        [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5787
0
        [[maybe_unused]] GDALm256i ymm_sumsquare =
5788
0
            ZERO256;  // holds 8 uint32 sums
5789
0
        for (; i + 31 < iMax; i += 32)
5790
0
        {
5791
0
            const GDALm256i ymm = GDALmm256_load_si256(
5792
0
                reinterpret_cast<const GDALm256i *>(pData + i));
5793
0
            if (COMPUTE_MIN)
5794
0
            {
5795
0
                ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5796
0
            }
5797
0
            if (COMPUTE_MAX)
5798
0
            {
5799
0
                ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5800
0
            }
5801
5802
            if constexpr (COMPUTE_OTHER_STATS)
5803
0
            {
5804
                // Extract even-8bit values
5805
0
                const GDALm256i ymm_even =
5806
0
                    GDALmm256_and_si256(ymm, ymm_mask_8bits);
5807
                // Compute square of those 16 values as 32 bit result
5808
                // and add adjacent pairs
5809
0
                const GDALm256i ymm_even_square =
5810
0
                    GDALmm256_madd_epi16(ymm_even, ymm_even);
5811
                // Add to the sumsquare accumulator
5812
0
                ymm_sumsquare =
5813
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5814
5815
                // Extract odd-8bit values
5816
0
                const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5817
0
                const GDALm256i ymm_odd_square =
5818
0
                    GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5819
0
                ymm_sumsquare =
5820
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5821
5822
                // Now compute the sums
5823
0
                ymm_sum = GDALmm256_add_epi32(ymm_sum,
5824
0
                                              GDALmm256_sad_epu8(ymm, ZERO256));
5825
0
            }
5826
0
        }
5827
5828
        if constexpr (COMPUTE_OTHER_STATS)
5829
0
        {
5830
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5831
0
                                  ymm_sum);
5832
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5833
0
                                  ymm_sumsquare);
5834
5835
0
            nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5836
0
            nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5837
0
                          panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5838
0
                          panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5839
0
                          panSumSquare[7];
5840
0
        }
5841
0
    }
5842
5843
    if constexpr (COMPUTE_MIN)
5844
0
    {
5845
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5846
0
    }
5847
    if constexpr (COMPUTE_MAX)
5848
0
    {
5849
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5850
0
    }
5851
    if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5852
0
    {
5853
0
        for (int j = 0; j < 32; j++)
5854
0
        {
5855
            if constexpr (COMPUTE_MIN)
5856
0
            {
5857
0
                if (pabyMin[j] < nMin)
5858
0
                    nMin = pabyMin[j];
5859
0
            }
5860
            if constexpr (COMPUTE_MAX)
5861
0
            {
5862
0
                if (pabyMax[j] > nMax)
5863
0
                    nMax = pabyMax[j];
5864
0
            }
5865
0
        }
5866
0
    }
5867
5868
0
    for (; i < nBlockPixels; i++)
5869
0
    {
5870
0
        const GUInt32 nValue = pData[i];
5871
        if constexpr (COMPUTE_MIN)
5872
0
        {
5873
0
            if (nValue < nMin)
5874
0
                nMin = nValue;
5875
0
        }
5876
        if constexpr (COMPUTE_MAX)
5877
0
        {
5878
0
            if (nValue > nMax)
5879
0
                nMax = nValue;
5880
0
        }
5881
        if constexpr (COMPUTE_OTHER_STATS)
5882
0
        {
5883
0
            nSum += nValue;
5884
0
            nSumSquare +=
5885
0
                static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5886
0
        }
5887
0
    }
5888
5889
    if constexpr (COMPUTE_OTHER_STATS)
5890
0
    {
5891
0
        nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5892
0
        nValidCount += static_cast<GUIntBig>(nBlockPixels);
5893
0
    }
5894
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&)
5895
5896
// SSE2/AVX2 optimization for GByte case
5897
// In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5898
// penaly in using the emulation, because, given the mm256 intrinsics used here,
5899
// there are strictly equivalent to 2 parallel SSE2 streams.
5900
template <bool COMPUTE_OTHER_STATS>
5901
struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5902
{
5903
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
5904
                  // assumed to be aligned on 256 bits
5905
                  const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5906
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5907
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5908
                  GUIntBig &nValidCount)
5909
0
    {
5910
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5911
0
        if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5912
0
            nMin <= nMax)
5913
0
        {
5914
            // 32-byte alignment may not be enforced by linker, so do it at hand
5915
0
            GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5916
0
            GByte *paby32ByteAligned =
5917
0
                aby32ByteUnaligned +
5918
0
                (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5919
0
            GByte *pabyMin = paby32ByteAligned;
5920
0
            GByte *pabyMax = paby32ByteAligned + 32;
5921
0
            GUInt32 *panSum =
5922
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5923
0
            GUInt32 *panSumSquare =
5924
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5925
5926
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5927
5928
0
            GPtrDiff_t i = 0;
5929
            // Make sure that sumSquare can fit on uint32
5930
            // * 8 since we can hold 8 sums per vector register
5931
0
            const int nMaxIterationsPerInnerLoop =
5932
0
                8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5933
0
            auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5934
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5935
0
                nOuterLoops++;
5936
5937
0
            const GDALm256i ymm_nodata =
5938
0
                GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5939
            // any non noData value in [min,max] would do.
5940
0
            const GDALm256i ymm_neutral =
5941
0
                GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5942
0
            GDALm256i ymm_min = ymm_neutral;
5943
0
            GDALm256i ymm_max = ymm_neutral;
5944
0
            [[maybe_unused]] const auto ymm_mask_8bits =
5945
0
                GDALmm256_set1_epi16(0xFF);
5946
5947
0
            const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5948
0
            const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5949
0
            const bool bComputeMinMax =
5950
0
                nMin > nMinThreshold || nMax < nMaxThreshold;
5951
5952
0
            for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5953
0
            {
5954
0
                const auto iMax =
5955
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5956
5957
                // holds 4 uint32 sums in [0], [2], [4] and [6]
5958
0
                [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5959
                // holds 8 uint32 sums
5960
0
                [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5961
                // holds 4 uint32 sums in [0], [2], [4] and [6]
5962
0
                [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5963
0
                const auto iInit = i;
5964
0
                for (; i + 31 < iMax; i += 32)
5965
0
                {
5966
0
                    const GDALm256i ymm = GDALmm256_load_si256(
5967
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
5968
5969
                    // Check which values are nodata
5970
0
                    const GDALm256i ymm_eq_nodata =
5971
0
                        GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5972
                    if constexpr (COMPUTE_OTHER_STATS)
5973
0
                    {
5974
                        // Count how many values are nodata (due to cmpeq
5975
                        // putting 255 when condition is met, this will actually
5976
                        // be 255 times the number of nodata value, spread in 4
5977
                        // 64 bits words). We can use add_epi32 as the counter
5978
                        // will not overflow uint32
5979
0
                        ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5980
0
                            ymm_count_nodata_mul_255,
5981
0
                            GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5982
0
                    }
5983
                    // Replace all nodata values by zero for the purpose of sum
5984
                    // and sumquare.
5985
0
                    const GDALm256i ymm_nodata_by_zero =
5986
0
                        GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5987
0
                    if (bComputeMinMax)
5988
0
                    {
5989
                        // Replace all nodata values by a neutral value for the
5990
                        // purpose of min and max.
5991
0
                        const GDALm256i ymm_nodata_by_neutral =
5992
0
                            GDALmm256_or_si256(
5993
0
                                GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5994
0
                                ymm_nodata_by_zero);
5995
5996
0
                        ymm_min =
5997
0
                            GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5998
0
                        ymm_max =
5999
0
                            GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6000
0
                    }
6001
6002
                    if constexpr (COMPUTE_OTHER_STATS)
6003
0
                    {
6004
                        // Extract even-8bit values
6005
0
                        const GDALm256i ymm_even = GDALmm256_and_si256(
6006
0
                            ymm_nodata_by_zero, ymm_mask_8bits);
6007
                        // Compute square of those 16 values as 32 bit result
6008
                        // and add adjacent pairs
6009
0
                        const GDALm256i ymm_even_square =
6010
0
                            GDALmm256_madd_epi16(ymm_even, ymm_even);
6011
                        // Add to the sumsquare accumulator
6012
0
                        ymm_sumsquare =
6013
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6014
6015
                        // Extract odd-8bit values
6016
0
                        const GDALm256i ymm_odd =
6017
0
                            GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6018
0
                        const GDALm256i ymm_odd_square =
6019
0
                            GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6020
0
                        ymm_sumsquare =
6021
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6022
6023
                        // Now compute the sums
6024
0
                        ymm_sum = GDALmm256_add_epi32(
6025
0
                            ymm_sum,
6026
0
                            GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6027
0
                    }
6028
0
                }
6029
6030
                if constexpr (COMPUTE_OTHER_STATS)
6031
0
                {
6032
0
                    GUInt32 *panCoutNoDataMul255 = panSum;
6033
0
                    GDALmm256_store_si256(
6034
0
                        reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6035
0
                        ymm_count_nodata_mul_255);
6036
6037
0
                    nSampleCount += (i - iInit);
6038
6039
0
                    nValidCount +=
6040
0
                        (i - iInit) -
6041
0
                        (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6042
0
                         panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6043
0
                            255;
6044
6045
0
                    GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6046
0
                                          ymm_sum);
6047
0
                    GDALmm256_store_si256(
6048
0
                        reinterpret_cast<GDALm256i *>(panSumSquare),
6049
0
                        ymm_sumsquare);
6050
0
                    nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6051
0
                    nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6052
0
                                  panSumSquare[1] + panSumSquare[2] +
6053
0
                                  panSumSquare[3] + panSumSquare[4] +
6054
0
                                  panSumSquare[5] + panSumSquare[6] +
6055
0
                                  panSumSquare[7];
6056
0
                }
6057
0
            }
6058
6059
0
            if (bComputeMinMax)
6060
0
            {
6061
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6062
0
                                      ymm_min);
6063
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6064
0
                                      ymm_max);
6065
0
                for (int j = 0; j < 32; j++)
6066
0
                {
6067
0
                    if (pabyMin[j] < nMin)
6068
0
                        nMin = pabyMin[j];
6069
0
                    if (pabyMax[j] > nMax)
6070
0
                        nMax = pabyMax[j];
6071
0
                }
6072
0
            }
6073
6074
            if constexpr (COMPUTE_OTHER_STATS)
6075
0
            {
6076
0
                nSampleCount += nBlockPixels - i;
6077
0
            }
6078
0
            for (; i < nBlockPixels; i++)
6079
0
            {
6080
0
                const GUInt32 nValue = pData[i];
6081
0
                if (nValue == nNoDataValue)
6082
0
                    continue;
6083
0
                if (nValue < nMin)
6084
0
                    nMin = nValue;
6085
0
                if (nValue > nMax)
6086
0
                    nMax = nValue;
6087
                if constexpr (COMPUTE_OTHER_STATS)
6088
0
                {
6089
0
                    nValidCount++;
6090
0
                    nSum += nValue;
6091
0
                    nSumSquare +=
6092
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6093
0
                        nValue;
6094
0
                }
6095
0
            }
6096
0
        }
6097
0
        else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6098
0
        {
6099
0
            if (nMin > 0)
6100
0
            {
6101
0
                if (nMax < 255)
6102
0
                {
6103
0
                    ComputeStatisticsByteNoNodata<true, true,
6104
0
                                                  COMPUTE_OTHER_STATS>(
6105
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6106
0
                        nSampleCount, nValidCount);
6107
0
                }
6108
0
                else
6109
0
                {
6110
0
                    ComputeStatisticsByteNoNodata<true, false,
6111
0
                                                  COMPUTE_OTHER_STATS>(
6112
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6113
0
                        nSampleCount, nValidCount);
6114
0
                }
6115
0
            }
6116
0
            else
6117
0
            {
6118
0
                if (nMax < 255)
6119
0
                {
6120
0
                    ComputeStatisticsByteNoNodata<false, true,
6121
0
                                                  COMPUTE_OTHER_STATS>(
6122
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6123
0
                        nSampleCount, nValidCount);
6124
0
                }
6125
0
                else
6126
0
                {
6127
0
                    ComputeStatisticsByteNoNodata<false, false,
6128
0
                                                  COMPUTE_OTHER_STATS>(
6129
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6130
0
                        nSampleCount, nValidCount);
6131
0
                }
6132
0
            }
6133
0
        }
6134
0
        else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6135
0
                 (nBlockXSize % 32) == 0)
6136
0
        {
6137
0
            for (int iY = 0; iY < nYCheck; iY++)
6138
0
            {
6139
0
                ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6140
0
                    nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6141
0
                    nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6142
0
            }
6143
0
        }
6144
0
        else
6145
0
        {
6146
0
            ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6147
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6148
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6149
0
        }
6150
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&)
6151
};
6152
6153
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6154
static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6155
                             GUIntBig i)
6156
0
{
6157
0
    nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6158
0
}
6159
6160
// AVX2/SSE2 optimization for GUInt16 case
6161
template <bool COMPUTE_OTHER_STATS>
6162
struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6163
{
6164
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
6165
                  // assumed to be aligned on 128 bits
6166
                  const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6167
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6168
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6169
                  GUIntBig &nValidCount)
6170
0
    {
6171
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6172
0
        if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6173
0
        {
6174
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6175
6176
0
            GPtrDiff_t i = 0;
6177
            // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6178
            // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6179
            // Furthermore the shift is also needed to use madd_epi16
6180
0
            const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6181
0
            GDALm256i ymm_min = GDALmm256_load_si256(
6182
0
                reinterpret_cast<const GDALm256i *>(pData + i));
6183
0
            ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6184
0
            GDALm256i ymm_max = ymm_min;
6185
0
            [[maybe_unused]] GDALm256i ymm_sumsquare =
6186
0
                ZERO256;  // holds 4 uint64 sums
6187
6188
            // Make sure that sum can fit on uint32
6189
            // * 8 since we can hold 8 sums per vector register
6190
0
            const int nMaxIterationsPerInnerLoop =
6191
0
                8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6192
0
            GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6193
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6194
0
                nOuterLoops++;
6195
6196
0
            const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6197
0
            [[maybe_unused]] const auto ymm_mask_16bits =
6198
0
                GDALmm256_set1_epi32(0xFFFF);
6199
0
            [[maybe_unused]] const auto ymm_mask_32bits =
6200
0
                GDALmm256_set1_epi64x(0xFFFFFFFF);
6201
6202
0
            GUIntBig nSumThis = 0;
6203
0
            for (int k = 0; k < nOuterLoops; k++)
6204
0
            {
6205
0
                const auto iMax =
6206
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6207
6208
0
                [[maybe_unused]] GDALm256i ymm_sum =
6209
0
                    ZERO256;  // holds 8 uint32 sums
6210
0
                for (; i + 15 < iMax; i += 16)
6211
0
                {
6212
0
                    const GDALm256i ymm = GDALmm256_load_si256(
6213
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
6214
0
                    const GDALm256i ymm_shifted =
6215
0
                        GDALmm256_add_epi16(ymm, ymm_m32768);
6216
0
                    if (bComputeMinMax)
6217
0
                    {
6218
0
                        ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6219
0
                        ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6220
0
                    }
6221
6222
                    if constexpr (COMPUTE_OTHER_STATS)
6223
0
                    {
6224
                        // Note: the int32 range can overflow for (0-32768)^2 +
6225
                        // (0-32768)^2 = 0x80000000, but as we know the result
6226
                        // is positive, this is OK as we interpret is a uint32.
6227
0
                        const GDALm256i ymm_square =
6228
0
                            GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6229
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6230
0
                            ymm_sumsquare,
6231
0
                            GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6232
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6233
0
                            ymm_sumsquare,
6234
0
                            GDALmm256_srli_epi64(ymm_square, 32));
6235
6236
                        // Now compute the sums
6237
0
                        ymm_sum = GDALmm256_add_epi32(
6238
0
                            ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6239
0
                        ymm_sum = GDALmm256_add_epi32(
6240
0
                            ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6241
0
                    }
6242
0
                }
6243
6244
                if constexpr (COMPUTE_OTHER_STATS)
6245
0
                {
6246
0
                    GUInt32 anSum[8];
6247
0
                    GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6248
0
                                           ymm_sum);
6249
0
                    nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6250
0
                                anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6251
0
                                anSum[6] + anSum[7];
6252
0
                }
6253
0
            }
6254
6255
0
            if (bComputeMinMax)
6256
0
            {
6257
0
                GUInt16 anMin[16];
6258
0
                GUInt16 anMax[16];
6259
6260
                // Unshift the result
6261
0
                ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6262
0
                ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6263
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6264
0
                                       ymm_min);
6265
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6266
0
                                       ymm_max);
6267
0
                for (int j = 0; j < 16; j++)
6268
0
                {
6269
0
                    if (anMin[j] < nMin)
6270
0
                        nMin = anMin[j];
6271
0
                    if (anMax[j] > nMax)
6272
0
                        nMax = anMax[j];
6273
0
                }
6274
0
            }
6275
6276
            if constexpr (COMPUTE_OTHER_STATS)
6277
0
            {
6278
0
                GUIntBig anSumSquare[4];
6279
0
                GDALmm256_storeu_si256(
6280
0
                    reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6281
0
                nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6282
0
                              anSumSquare[3];
6283
6284
                // Unshift the sum of squares
6285
0
                UnshiftSumSquare(nSumSquare, nSumThis,
6286
0
                                 static_cast<GUIntBig>(i));
6287
6288
0
                nSum += nSumThis;
6289
6290
0
                for (; i < nBlockPixels; i++)
6291
0
                {
6292
0
                    const GUInt32 nValue = pData[i];
6293
0
                    if (nValue < nMin)
6294
0
                        nMin = nValue;
6295
0
                    if (nValue > nMax)
6296
0
                        nMax = nValue;
6297
0
                    nSum += nValue;
6298
0
                    nSumSquare +=
6299
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6300
0
                        nValue;
6301
0
                }
6302
6303
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6304
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6305
0
            }
6306
0
        }
6307
0
        else
6308
0
        {
6309
0
            ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6310
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6311
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6312
0
        }
6313
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&)
6314
};
6315
6316
#endif
6317
// (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6318
// defined(_MSC_VER))
6319
6320
/************************************************************************/
6321
/*                          GetPixelValue()                             */
6322
/************************************************************************/
6323
6324
static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6325
                                   const void *pData, GPtrDiff_t iOffset,
6326
                                   const GDALNoDataValues &sNoDataValues,
6327
                                   bool &bValid)
6328
0
{
6329
0
    bValid = true;
6330
0
    double dfValue = 0;
6331
0
    switch (eDataType)
6332
0
    {
6333
0
        case GDT_Byte:
6334
0
        {
6335
0
            if (bSignedByte)
6336
0
                dfValue = static_cast<const signed char *>(pData)[iOffset];
6337
0
            else
6338
0
                dfValue = static_cast<const GByte *>(pData)[iOffset];
6339
0
            break;
6340
0
        }
6341
0
        case GDT_Int8:
6342
0
            dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6343
0
            break;
6344
0
        case GDT_UInt16:
6345
0
            dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6346
0
            break;
6347
0
        case GDT_Int16:
6348
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6349
0
            break;
6350
0
        case GDT_UInt32:
6351
0
            dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6352
0
            break;
6353
0
        case GDT_Int32:
6354
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6355
0
            break;
6356
0
        case GDT_UInt64:
6357
0
            dfValue = static_cast<double>(
6358
0
                static_cast<const std::uint64_t *>(pData)[iOffset]);
6359
0
            break;
6360
0
        case GDT_Int64:
6361
0
            dfValue = static_cast<double>(
6362
0
                static_cast<const std::int64_t *>(pData)[iOffset]);
6363
0
            break;
6364
0
        case GDT_Float16:
6365
0
        {
6366
0
            using namespace std;
6367
0
            const GFloat16 hfValue =
6368
0
                static_cast<const GFloat16 *>(pData)[iOffset];
6369
0
            if (isnan(hfValue) ||
6370
0
                (sNoDataValues.bGotFloat16NoDataValue &&
6371
0
                 ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6372
0
            {
6373
0
                bValid = false;
6374
0
                return 0.0;
6375
0
            }
6376
0
            dfValue = hfValue;
6377
0
            return dfValue;
6378
0
        }
6379
0
        case GDT_Float32:
6380
0
        {
6381
0
            const float fValue = static_cast<const float *>(pData)[iOffset];
6382
0
            if (std::isnan(fValue) ||
6383
0
                (sNoDataValues.bGotFloatNoDataValue &&
6384
0
                 ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6385
0
            {
6386
0
                bValid = false;
6387
0
                return 0.0;
6388
0
            }
6389
0
            dfValue = fValue;
6390
0
            return dfValue;
6391
0
        }
6392
0
        case GDT_Float64:
6393
0
            dfValue = static_cast<const double *>(pData)[iOffset];
6394
0
            if (std::isnan(dfValue))
6395
0
            {
6396
0
                bValid = false;
6397
0
                return 0.0;
6398
0
            }
6399
0
            break;
6400
0
        case GDT_CInt16:
6401
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6402
0
            break;
6403
0
        case GDT_CInt32:
6404
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6405
0
            break;
6406
0
        case GDT_CFloat16:
6407
0
            dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6408
0
            if (std::isnan(dfValue))
6409
0
            {
6410
0
                bValid = false;
6411
0
                return 0.0;
6412
0
            }
6413
0
            break;
6414
0
        case GDT_CFloat32:
6415
0
            dfValue = static_cast<const float *>(pData)[iOffset * 2];
6416
0
            if (std::isnan(dfValue))
6417
0
            {
6418
0
                bValid = false;
6419
0
                return 0.0;
6420
0
            }
6421
0
            break;
6422
0
        case GDT_CFloat64:
6423
0
            dfValue = static_cast<const double *>(pData)[iOffset * 2];
6424
0
            if (std::isnan(dfValue))
6425
0
            {
6426
0
                bValid = false;
6427
0
                return 0.0;
6428
0
            }
6429
0
            break;
6430
0
        case GDT_Unknown:
6431
0
        case GDT_TypeCount:
6432
0
            CPLAssert(false);
6433
0
            break;
6434
0
    }
6435
6436
0
    if (sNoDataValues.bGotNoDataValue &&
6437
0
        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6438
0
    {
6439
0
        bValid = false;
6440
0
        return 0.0;
6441
0
    }
6442
0
    return dfValue;
6443
0
}
6444
6445
/************************************************************************/
6446
/*                         SetValidPercent()                            */
6447
/************************************************************************/
6448
6449
//! @cond Doxygen_Suppress
6450
/**
6451
 * \brief Set percentage of valid (not nodata) pixels.
6452
 *
6453
 * Stores the percentage of valid pixels in the metadata item
6454
 * STATISTICS_VALID_PERCENT
6455
 *
6456
 * @param nSampleCount Number of sampled pixels.
6457
 *
6458
 * @param nValidCount Number of valid pixels.
6459
 */
6460
6461
void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6462
                                     GUIntBig nValidCount)
6463
0
{
6464
0
    if (nValidCount == 0)
6465
0
    {
6466
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6467
0
    }
6468
0
    else if (nValidCount == nSampleCount)
6469
0
    {
6470
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6471
0
    }
6472
0
    else /* nValidCount < nSampleCount */
6473
0
    {
6474
0
        char szValue[128] = {0};
6475
6476
        /* percentage is only an indicator: limit precision */
6477
0
        CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6478
0
                    100. * static_cast<double>(nValidCount) / nSampleCount);
6479
6480
0
        if (EQUAL(szValue, "100"))
6481
0
        {
6482
            /* don't set 100 percent valid
6483
             * because some of the sampled pixels were nodata */
6484
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6485
0
        }
6486
0
        else
6487
0
        {
6488
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6489
0
        }
6490
0
    }
6491
0
}
6492
6493
//! @endcond
6494
6495
/************************************************************************/
6496
/*                         ComputeStatistics()                          */
6497
/************************************************************************/
6498
6499
/**
6500
 * \brief Compute image statistics.
6501
 *
6502
 * Returns the minimum, maximum, mean and standard deviation of all
6503
 * pixel values in this band.  If approximate statistics are sufficient,
6504
 * the bApproxOK flag can be set to true in which case overviews, or a
6505
 * subset of image tiles may be used in computing the statistics.
6506
 *
6507
 * Once computed, the statistics will generally be "set" back on the
6508
 * raster band using SetStatistics().
6509
 *
6510
 * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6511
 *
6512
 * This method is the same as the C function GDALComputeRasterStatistics().
6513
 *
6514
 * @param bApproxOK If TRUE statistics may be computed based on overviews
6515
 * or a subset of all tiles.
6516
 *
6517
 * @param pdfMin Location into which to load image minimum (may be NULL).
6518
 *
6519
 * @param pdfMax Location into which to load image maximum (may be NULL).-
6520
 *
6521
 * @param pdfMean Location into which to load image mean (may be NULL).
6522
 *
6523
 * @param pdfStdDev Location into which to load image standard deviation
6524
 * (may be NULL).
6525
 *
6526
 * @param pfnProgress a function to call to report progress, or NULL.
6527
 *
6528
 * @param pProgressData application data to pass to the progress function.
6529
 *
6530
 * @return CE_None on success, or CE_Failure if an error occurs or processing
6531
 * is terminated by the user.
6532
 */
6533
6534
CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6535
                                         double *pdfMax, double *pdfMean,
6536
                                         double *pdfStdDev,
6537
                                         GDALProgressFunc pfnProgress,
6538
                                         void *pProgressData)
6539
6540
0
{
6541
0
    if (pfnProgress == nullptr)
6542
0
        pfnProgress = GDALDummyProgress;
6543
6544
    /* -------------------------------------------------------------------- */
6545
    /*      If we have overview bands, use them for statistics.             */
6546
    /* -------------------------------------------------------------------- */
6547
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6548
0
    {
6549
0
        GDALRasterBand *poBand =
6550
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6551
6552
0
        if (poBand != this)
6553
0
        {
6554
0
            CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6555
0
                                                    pdfMean, pdfStdDev,
6556
0
                                                    pfnProgress, pProgressData);
6557
0
            if (eErr == CE_None)
6558
0
            {
6559
0
                if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6560
0
                {
6561
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6562
0
                    SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6563
0
                }
6564
6565
                /* transfer metadata from overview band to this */
6566
0
                const char *pszPercentValid =
6567
0
                    poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6568
6569
0
                if (pszPercentValid != nullptr)
6570
0
                {
6571
0
                    SetMetadataItem("STATISTICS_VALID_PERCENT",
6572
0
                                    pszPercentValid);
6573
0
                }
6574
0
            }
6575
0
            return eErr;
6576
0
        }
6577
0
    }
6578
6579
0
    if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6580
0
    {
6581
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6582
0
        return CE_Failure;
6583
0
    }
6584
6585
    /* -------------------------------------------------------------------- */
6586
    /*      Read actual data and compute statistics.                        */
6587
    /* -------------------------------------------------------------------- */
6588
    // Using Welford algorithm:
6589
    // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6590
    // to compute standard deviation in a more numerically robust way than
6591
    // the difference of the sum of square values with the square of the sum.
6592
    // dfMean and dfM2 are updated at each sample.
6593
    // dfM2 is the sum of square of differences to the current mean.
6594
0
    double dfMin = std::numeric_limits<double>::infinity();
6595
0
    double dfMax = -std::numeric_limits<double>::infinity();
6596
0
    double dfMean = 0.0;
6597
0
    double dfM2 = 0.0;
6598
6599
0
    GDALRasterIOExtraArg sExtraArg;
6600
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6601
6602
0
    GDALNoDataValues sNoDataValues(this, eDataType);
6603
0
    GDALRasterBand *poMaskBand = nullptr;
6604
0
    if (!sNoDataValues.bGotNoDataValue)
6605
0
    {
6606
0
        const int l_nMaskFlags = GetMaskFlags();
6607
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
6608
0
            GetColorInterpretation() != GCI_AlphaBand)
6609
0
        {
6610
0
            poMaskBand = GetMaskBand();
6611
0
        }
6612
0
    }
6613
6614
0
    bool bSignedByte = false;
6615
0
    if (eDataType == GDT_Byte)
6616
0
    {
6617
0
        EnablePixelTypeSignedByteWarning(false);
6618
0
        const char *pszPixelType =
6619
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6620
0
        EnablePixelTypeSignedByteWarning(true);
6621
0
        bSignedByte =
6622
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6623
0
    }
6624
6625
0
    GUIntBig nSampleCount = 0;
6626
0
    GUIntBig nValidCount = 0;
6627
6628
0
    if (bApproxOK && HasArbitraryOverviews())
6629
0
    {
6630
        /* --------------------------------------------------------------------
6631
         */
6632
        /*      Figure out how much the image should be reduced to get an */
6633
        /*      approximate value. */
6634
        /* --------------------------------------------------------------------
6635
         */
6636
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6637
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6638
6639
0
        int nXReduced = nRasterXSize;
6640
0
        int nYReduced = nRasterYSize;
6641
0
        if (dfReduction > 1.0)
6642
0
        {
6643
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6644
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6645
6646
            // Catch the case of huge resizing ratios here
6647
0
            if (nXReduced == 0)
6648
0
                nXReduced = 1;
6649
0
            if (nYReduced == 0)
6650
0
                nYReduced = 1;
6651
0
        }
6652
6653
0
        void *pData = CPLMalloc(cpl::fits_on<int>(
6654
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6655
6656
0
        const CPLErr eErr =
6657
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6658
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6659
0
        if (eErr != CE_None)
6660
0
        {
6661
0
            CPLFree(pData);
6662
0
            return eErr;
6663
0
        }
6664
6665
0
        GByte *pabyMaskData = nullptr;
6666
0
        if (poMaskBand)
6667
0
        {
6668
0
            pabyMaskData =
6669
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6670
0
            if (!pabyMaskData)
6671
0
            {
6672
0
                CPLFree(pData);
6673
0
                return CE_Failure;
6674
0
            }
6675
6676
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6677
0
                                     pabyMaskData, nXReduced, nYReduced,
6678
0
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
6679
0
            {
6680
0
                CPLFree(pData);
6681
0
                CPLFree(pabyMaskData);
6682
0
                return CE_Failure;
6683
0
            }
6684
0
        }
6685
6686
        /* this isn't the fastest way to do this, but is easier for now */
6687
0
        for (int iY = 0; iY < nYReduced; iY++)
6688
0
        {
6689
0
            for (int iX = 0; iX < nXReduced; iX++)
6690
0
            {
6691
0
                const int iOffset = iX + iY * nXReduced;
6692
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
6693
0
                    continue;
6694
6695
0
                bool bValid = true;
6696
0
                double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
6697
0
                                               iOffset, sNoDataValues, bValid);
6698
0
                if (!bValid)
6699
0
                    continue;
6700
6701
0
                dfMin = std::min(dfMin, dfValue);
6702
0
                dfMax = std::max(dfMax, dfValue);
6703
6704
0
                nValidCount++;
6705
0
                if (dfMin == dfMax)
6706
0
                {
6707
0
                    if (nValidCount == 1)
6708
0
                        dfMean = dfMin;
6709
0
                }
6710
0
                else
6711
0
                {
6712
0
                    const double dfDelta = dfValue - dfMean;
6713
0
                    dfMean += dfDelta / nValidCount;
6714
0
                    dfM2 += dfDelta * (dfValue - dfMean);
6715
0
                }
6716
0
            }
6717
0
        }
6718
6719
0
        nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6720
6721
0
        CPLFree(pData);
6722
0
        CPLFree(pabyMaskData);
6723
0
    }
6724
6725
0
    else  // No arbitrary overviews.
6726
0
    {
6727
0
        if (!InitBlockInfo())
6728
0
            return CE_Failure;
6729
6730
        /* --------------------------------------------------------------------
6731
         */
6732
        /*      Figure out the ratio of blocks we will read to get an */
6733
        /*      approximate value. */
6734
        /* --------------------------------------------------------------------
6735
         */
6736
0
        int nSampleRate = 1;
6737
0
        if (bApproxOK)
6738
0
        {
6739
0
            nSampleRate = static_cast<int>(std::max(
6740
0
                1.0,
6741
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6742
            // We want to avoid probing only the first column of blocks for
6743
            // a square shaped raster, because it is not unlikely that it may
6744
            // be padding only (#6378)
6745
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6746
0
                nSampleRate += 1;
6747
0
        }
6748
0
        if (nSampleRate == 1)
6749
0
            bApproxOK = false;
6750
6751
        // Particular case for GDT_Byte that only use integral types for all
6752
        // intermediate computations. Only possible if the number of pixels
6753
        // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6754
        // can fit on a uint64. Should be 99.99999% of cases.
6755
        // For GUInt16, this limits to raster of 4 giga pixels
6756
0
        if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6757
0
             static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6758
0
                     nSampleRate <
6759
0
                 GUINTBIG_MAX / (255U * 255U) /
6760
0
                     (static_cast<GUInt64>(nBlockXSize) *
6761
0
                      static_cast<GUInt64>(nBlockYSize))) ||
6762
0
            (eDataType == GDT_UInt16 &&
6763
0
             static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6764
0
                     nSampleRate <
6765
0
                 GUINTBIG_MAX / (65535U * 65535U) /
6766
0
                     (static_cast<GUInt64>(nBlockXSize) *
6767
0
                      static_cast<GUInt64>(nBlockYSize))))
6768
0
        {
6769
0
            const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6770
0
            GUInt32 nMin = nMaxValueType;
6771
0
            GUInt32 nMax = 0;
6772
0
            GUIntBig nSum = 0;
6773
0
            GUIntBig nSumSquare = 0;
6774
            // If no valid nodata, map to invalid value (256 for Byte)
6775
0
            const GUInt32 nNoDataValue =
6776
0
                (sNoDataValues.bGotNoDataValue &&
6777
0
                 sNoDataValues.dfNoDataValue >= 0 &&
6778
0
                 sNoDataValues.dfNoDataValue <= nMaxValueType &&
6779
0
                 fabs(sNoDataValues.dfNoDataValue -
6780
0
                      static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
6781
0
                                           1e-10)) < 1e-10)
6782
0
                    ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
6783
0
                    : nMaxValueType + 1;
6784
6785
0
            for (GIntBig iSampleBlock = 0;
6786
0
                 iSampleBlock <
6787
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6788
0
                 iSampleBlock += nSampleRate)
6789
0
            {
6790
0
                const int iYBlock =
6791
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
6792
0
                const int iXBlock =
6793
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
6794
6795
0
                GDALRasterBlock *const poBlock =
6796
0
                    GetLockedBlockRef(iXBlock, iYBlock);
6797
0
                if (poBlock == nullptr)
6798
0
                    return CE_Failure;
6799
6800
0
                void *const pData = poBlock->GetDataRef();
6801
6802
0
                int nXCheck = 0, nYCheck = 0;
6803
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6804
6805
0
                if (eDataType == GDT_Byte)
6806
0
                {
6807
0
                    ComputeStatisticsInternal<
6808
0
                        GByte, /* COMPUTE_OTHER_STATS = */ true>::
6809
0
                        f(nXCheck, nBlockXSize, nYCheck,
6810
0
                          static_cast<const GByte *>(pData),
6811
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6812
0
                          nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6813
0
                }
6814
0
                else
6815
0
                {
6816
0
                    ComputeStatisticsInternal<
6817
0
                        GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6818
0
                        f(nXCheck, nBlockXSize, nYCheck,
6819
0
                          static_cast<const GUInt16 *>(pData),
6820
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6821
0
                          nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6822
0
                }
6823
6824
0
                poBlock->DropLock();
6825
6826
0
                if (!pfnProgress(static_cast<double>(iSampleBlock) /
6827
0
                                     (static_cast<double>(nBlocksPerRow) *
6828
0
                                      nBlocksPerColumn),
6829
0
                                 "Compute Statistics", pProgressData))
6830
0
                {
6831
0
                    ReportError(CE_Failure, CPLE_UserInterrupt,
6832
0
                                "User terminated");
6833
0
                    return CE_Failure;
6834
0
                }
6835
0
            }
6836
6837
0
            if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6838
0
            {
6839
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6840
0
                return CE_Failure;
6841
0
            }
6842
6843
            /* --------------------------------------------------------------------
6844
             */
6845
            /*      Save computed information. */
6846
            /* --------------------------------------------------------------------
6847
             */
6848
0
            if (nValidCount)
6849
0
                dfMean = static_cast<double>(nSum) / nValidCount;
6850
6851
            // To avoid potential precision issues when doing the difference,
6852
            // we need to do that computation on 128 bit rather than casting
6853
            // to double
6854
0
            const GDALUInt128 nTmpForStdDev(
6855
0
                GDALUInt128::Mul(nSumSquare, nValidCount) -
6856
0
                GDALUInt128::Mul(nSum, nSum));
6857
0
            const double dfStdDev =
6858
0
                nValidCount > 0
6859
0
                    ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6860
0
                    : 0.0;
6861
6862
0
            if (nValidCount > 0)
6863
0
            {
6864
0
                if (bApproxOK)
6865
0
                {
6866
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6867
0
                }
6868
0
                else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6869
0
                {
6870
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6871
0
                }
6872
0
                SetStatistics(nMin, nMax, dfMean, dfStdDev);
6873
0
            }
6874
6875
0
            SetValidPercent(nSampleCount, nValidCount);
6876
6877
            /* --------------------------------------------------------------------
6878
             */
6879
            /*      Record results. */
6880
            /* --------------------------------------------------------------------
6881
             */
6882
0
            if (pdfMin != nullptr)
6883
0
                *pdfMin = nValidCount ? nMin : 0;
6884
0
            if (pdfMax != nullptr)
6885
0
                *pdfMax = nValidCount ? nMax : 0;
6886
6887
0
            if (pdfMean != nullptr)
6888
0
                *pdfMean = dfMean;
6889
6890
0
            if (pdfStdDev != nullptr)
6891
0
                *pdfStdDev = dfStdDev;
6892
6893
0
            if (nValidCount > 0)
6894
0
                return CE_None;
6895
6896
0
            ReportError(CE_Failure, CPLE_AppDefined,
6897
0
                        "Failed to compute statistics, no valid pixels found "
6898
0
                        "in sampling.");
6899
0
            return CE_Failure;
6900
0
        }
6901
6902
0
        GByte *pabyMaskData = nullptr;
6903
0
        if (poMaskBand)
6904
0
        {
6905
0
            pabyMaskData = static_cast<GByte *>(
6906
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6907
0
            if (!pabyMaskData)
6908
0
            {
6909
0
                return CE_Failure;
6910
0
            }
6911
0
        }
6912
6913
0
        for (GIntBig iSampleBlock = 0;
6914
0
             iSampleBlock <
6915
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6916
0
             iSampleBlock += nSampleRate)
6917
0
        {
6918
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6919
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6920
6921
0
            int nXCheck = 0, nYCheck = 0;
6922
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6923
6924
0
            if (poMaskBand &&
6925
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6926
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
6927
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6928
0
                                     0, nBlockXSize, nullptr) != CE_None)
6929
0
            {
6930
0
                CPLFree(pabyMaskData);
6931
0
                return CE_Failure;
6932
0
            }
6933
6934
0
            GDALRasterBlock *const poBlock =
6935
0
                GetLockedBlockRef(iXBlock, iYBlock);
6936
0
            if (poBlock == nullptr)
6937
0
            {
6938
0
                CPLFree(pabyMaskData);
6939
0
                return CE_Failure;
6940
0
            }
6941
6942
0
            void *const pData = poBlock->GetDataRef();
6943
6944
            // This isn't the fastest way to do this, but is easier for now.
6945
0
            for (int iY = 0; iY < nYCheck; iY++)
6946
0
            {
6947
0
                for (int iX = 0; iX < nXCheck; iX++)
6948
0
                {
6949
0
                    const GPtrDiff_t iOffset =
6950
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6951
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
6952
0
                        continue;
6953
6954
0
                    bool bValid = true;
6955
0
                    double dfValue =
6956
0
                        GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6957
0
                                      sNoDataValues, bValid);
6958
6959
0
                    if (!bValid)
6960
0
                        continue;
6961
6962
0
                    dfMin = std::min(dfMin, dfValue);
6963
0
                    dfMax = std::max(dfMax, dfValue);
6964
6965
0
                    nValidCount++;
6966
0
                    if (dfMin == dfMax)
6967
0
                    {
6968
0
                        if (nValidCount == 1)
6969
0
                            dfMean = dfMin;
6970
0
                    }
6971
0
                    else
6972
0
                    {
6973
0
                        const double dfDelta = dfValue - dfMean;
6974
0
                        dfMean += dfDelta / nValidCount;
6975
0
                        dfM2 += dfDelta * (dfValue - dfMean);
6976
0
                    }
6977
0
                }
6978
0
            }
6979
6980
0
            nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6981
6982
0
            poBlock->DropLock();
6983
6984
0
            if (!pfnProgress(
6985
0
                    static_cast<double>(iSampleBlock) /
6986
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6987
0
                    "Compute Statistics", pProgressData))
6988
0
            {
6989
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6990
0
                CPLFree(pabyMaskData);
6991
0
                return CE_Failure;
6992
0
            }
6993
0
        }
6994
6995
0
        CPLFree(pabyMaskData);
6996
0
    }
6997
6998
0
    if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6999
0
    {
7000
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7001
0
        return CE_Failure;
7002
0
    }
7003
7004
    /* -------------------------------------------------------------------- */
7005
    /*      Save computed information.                                      */
7006
    /* -------------------------------------------------------------------- */
7007
0
    const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
7008
7009
0
    if (nValidCount > 0)
7010
0
    {
7011
0
        if (bApproxOK)
7012
0
        {
7013
0
            SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7014
0
        }
7015
0
        else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7016
0
        {
7017
0
            SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7018
0
        }
7019
0
        SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7020
0
    }
7021
0
    else
7022
0
    {
7023
0
        dfMin = 0.0;
7024
0
        dfMax = 0.0;
7025
0
    }
7026
7027
0
    SetValidPercent(nSampleCount, nValidCount);
7028
7029
    /* -------------------------------------------------------------------- */
7030
    /*      Record results.                                                 */
7031
    /* -------------------------------------------------------------------- */
7032
0
    if (pdfMin != nullptr)
7033
0
        *pdfMin = dfMin;
7034
0
    if (pdfMax != nullptr)
7035
0
        *pdfMax = dfMax;
7036
7037
0
    if (pdfMean != nullptr)
7038
0
        *pdfMean = dfMean;
7039
7040
0
    if (pdfStdDev != nullptr)
7041
0
        *pdfStdDev = dfStdDev;
7042
7043
0
    if (nValidCount > 0)
7044
0
        return CE_None;
7045
7046
0
    ReportError(
7047
0
        CE_Failure, CPLE_AppDefined,
7048
0
        "Failed to compute statistics, no valid pixels found in sampling.");
7049
0
    return CE_Failure;
7050
0
}
7051
7052
/************************************************************************/
7053
/*                    GDALComputeRasterStatistics()                     */
7054
/************************************************************************/
7055
7056
/**
7057
 * \brief Compute image statistics.
7058
 *
7059
 * @see GDALRasterBand::ComputeStatistics()
7060
 */
7061
7062
CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7063
                                               int bApproxOK, double *pdfMin,
7064
                                               double *pdfMax, double *pdfMean,
7065
                                               double *pdfStdDev,
7066
                                               GDALProgressFunc pfnProgress,
7067
                                               void *pProgressData)
7068
7069
0
{
7070
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7071
7072
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7073
7074
0
    return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7075
0
                                     pdfStdDev, pfnProgress, pProgressData);
7076
0
}
7077
7078
/************************************************************************/
7079
/*                           SetStatistics()                            */
7080
/************************************************************************/
7081
7082
/**
7083
 * \brief Set statistics on band.
7084
 *
7085
 * This method can be used to store min/max/mean/standard deviation
7086
 * statistics on a raster band.
7087
 *
7088
 * The default implementation stores them as metadata, and will only work
7089
 * on formats that can save arbitrary metadata.  This method cannot detect
7090
 * whether metadata will be properly saved and so may return CE_None even
7091
 * if the statistics will never be saved.
7092
 *
7093
 * This method is the same as the C function GDALSetRasterStatistics().
7094
 *
7095
 * @param dfMin minimum pixel value.
7096
 *
7097
 * @param dfMax maximum pixel value.
7098
 *
7099
 * @param dfMean mean (average) of all pixel values.
7100
 *
7101
 * @param dfStdDev Standard deviation of all pixel values.
7102
 *
7103
 * @return CE_None on success or CE_Failure on failure.
7104
 */
7105
7106
CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7107
                                     double dfStdDev)
7108
7109
0
{
7110
0
    char szValue[128] = {0};
7111
7112
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7113
0
    SetMetadataItem("STATISTICS_MINIMUM", szValue);
7114
7115
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7116
0
    SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7117
7118
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7119
0
    SetMetadataItem("STATISTICS_MEAN", szValue);
7120
7121
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7122
0
    SetMetadataItem("STATISTICS_STDDEV", szValue);
7123
7124
0
    return CE_None;
7125
0
}
7126
7127
/************************************************************************/
7128
/*                      GDALSetRasterStatistics()                       */
7129
/************************************************************************/
7130
7131
/**
7132
 * \brief Set statistics on band.
7133
 *
7134
 * @see GDALRasterBand::SetStatistics()
7135
 */
7136
7137
CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7138
                                           double dfMax, double dfMean,
7139
                                           double dfStdDev)
7140
7141
0
{
7142
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7143
7144
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7145
0
    return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7146
0
}
7147
7148
/************************************************************************/
7149
/*                        ComputeRasterMinMax()                         */
7150
/************************************************************************/
7151
7152
template <class T, bool HAS_NODATA>
7153
static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7154
                          T *pMax)
7155
0
{
7156
0
    T min0 = *pMin;
7157
0
    T max0 = *pMax;
7158
0
    T min1 = *pMin;
7159
0
    T max1 = *pMax;
7160
0
    size_t i;
7161
0
    for (i = 0; i + 1 < nElts; i += 2)
7162
0
    {
7163
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
7164
0
        {
7165
0
            min0 = std::min(min0, buffer[i]);
7166
0
            max0 = std::max(max0, buffer[i]);
7167
0
        }
7168
0
        if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7169
0
        {
7170
0
            min1 = std::min(min1, buffer[i + 1]);
7171
0
            max1 = std::max(max1, buffer[i + 1]);
7172
0
        }
7173
0
    }
7174
0
    T min = std::min(min0, min1);
7175
0
    T max = std::max(max0, max1);
7176
0
    if (i < nElts)
7177
0
    {
7178
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
7179
0
        {
7180
0
            min = std::min(min, buffer[i]);
7181
0
            max = std::max(max, buffer[i]);
7182
0
        }
7183
0
    }
7184
0
    *pMin = min;
7185
0
    *pMax = max;
7186
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*)
7187
7188
template <GDALDataType eDataType, bool bSignedByte>
7189
static void
7190
ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7191
                     int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7192
                     const GByte *pabyMaskData, double &dfMin, double &dfMax)
7193
0
{
7194
0
    double dfLocalMin = dfMin;
7195
0
    double dfLocalMax = dfMax;
7196
7197
0
    for (int iY = 0; iY < nYCheck; iY++)
7198
0
    {
7199
0
        for (int iX = 0; iX < nXCheck; iX++)
7200
0
        {
7201
0
            const GPtrDiff_t iOffset =
7202
0
                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7203
0
            if (pabyMaskData && pabyMaskData[iOffset] == 0)
7204
0
                continue;
7205
0
            bool bValid = true;
7206
0
            double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7207
0
                                           iOffset, sNoDataValues, bValid);
7208
0
            if (!bValid)
7209
0
                continue;
7210
7211
0
            dfLocalMin = std::min(dfLocalMin, dfValue);
7212
0
            dfLocalMax = std::max(dfLocalMax, dfValue);
7213
0
        }
7214
0
    }
7215
7216
0
    dfMin = dfLocalMin;
7217
0
    dfMax = dfLocalMax;
7218
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&)
7219
7220
static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
7221
                                 bool bSignedByte, int nXCheck, int nYCheck,
7222
                                 int nBlockXSize,
7223
                                 const GDALNoDataValues &sNoDataValues,
7224
                                 const GByte *pabyMaskData, double &dfMin,
7225
                                 double &dfMax)
7226
0
{
7227
0
    switch (eDataType)
7228
0
    {
7229
0
        case GDT_Unknown:
7230
0
            CPLAssert(false);
7231
0
            break;
7232
0
        case GDT_Byte:
7233
0
            if (bSignedByte)
7234
0
            {
7235
0
                ComputeMinMaxGeneric<GDT_Byte, true>(
7236
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7237
0
                    pabyMaskData, dfMin, dfMax);
7238
0
            }
7239
0
            else
7240
0
            {
7241
0
                ComputeMinMaxGeneric<GDT_Byte, false>(
7242
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7243
0
                    pabyMaskData, dfMin, dfMax);
7244
0
            }
7245
0
            break;
7246
0
        case GDT_Int8:
7247
0
            ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
7248
0
                                                  nBlockXSize, sNoDataValues,
7249
0
                                                  pabyMaskData, dfMin, dfMax);
7250
0
            break;
7251
0
        case GDT_UInt16:
7252
0
            ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
7253
0
                                                    nBlockXSize, sNoDataValues,
7254
0
                                                    pabyMaskData, dfMin, dfMax);
7255
0
            break;
7256
0
        case GDT_Int16:
7257
0
            ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
7258
0
                                                   nBlockXSize, sNoDataValues,
7259
0
                                                   pabyMaskData, dfMin, dfMax);
7260
0
            break;
7261
0
        case GDT_UInt32:
7262
0
            ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
7263
0
                                                    nBlockXSize, sNoDataValues,
7264
0
                                                    pabyMaskData, dfMin, dfMax);
7265
0
            break;
7266
0
        case GDT_Int32:
7267
0
            ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
7268
0
                                                   nBlockXSize, sNoDataValues,
7269
0
                                                   pabyMaskData, dfMin, dfMax);
7270
0
            break;
7271
0
        case GDT_UInt64:
7272
0
            ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
7273
0
                                                    nBlockXSize, sNoDataValues,
7274
0
                                                    pabyMaskData, dfMin, dfMax);
7275
0
            break;
7276
0
        case GDT_Int64:
7277
0
            ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
7278
0
                                                   nBlockXSize, sNoDataValues,
7279
0
                                                   pabyMaskData, dfMin, dfMax);
7280
0
            break;
7281
0
        case GDT_Float16:
7282
0
            ComputeMinMaxGeneric<GDT_Float16, false>(
7283
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7284
0
                pabyMaskData, dfMin, dfMax);
7285
0
            break;
7286
0
        case GDT_Float32:
7287
0
            ComputeMinMaxGeneric<GDT_Float32, false>(
7288
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7289
0
                pabyMaskData, dfMin, dfMax);
7290
0
            break;
7291
0
        case GDT_Float64:
7292
0
            ComputeMinMaxGeneric<GDT_Float64, false>(
7293
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7294
0
                pabyMaskData, dfMin, dfMax);
7295
0
            break;
7296
0
        case GDT_CInt16:
7297
0
            ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
7298
0
                                                    nBlockXSize, sNoDataValues,
7299
0
                                                    pabyMaskData, dfMin, dfMax);
7300
0
            break;
7301
0
        case GDT_CInt32:
7302
0
            ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
7303
0
                                                    nBlockXSize, sNoDataValues,
7304
0
                                                    pabyMaskData, dfMin, dfMax);
7305
0
            break;
7306
0
        case GDT_CFloat16:
7307
0
            ComputeMinMaxGeneric<GDT_CFloat16, false>(
7308
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7309
0
                pabyMaskData, dfMin, dfMax);
7310
0
            break;
7311
0
        case GDT_CFloat32:
7312
0
            ComputeMinMaxGeneric<GDT_CFloat32, false>(
7313
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7314
0
                pabyMaskData, dfMin, dfMax);
7315
0
            break;
7316
0
        case GDT_CFloat64:
7317
0
            ComputeMinMaxGeneric<GDT_CFloat64, false>(
7318
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7319
0
                pabyMaskData, dfMin, dfMax);
7320
0
            break;
7321
0
        case GDT_TypeCount:
7322
0
            CPLAssert(false);
7323
0
            break;
7324
0
    }
7325
0
}
7326
7327
static bool ComputeMinMaxGenericIterBlocks(
7328
    GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
7329
    GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
7330
    const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
7331
    double &dfMin, double &dfMax)
7332
7333
0
{
7334
0
    GByte *pabyMaskData = nullptr;
7335
0
    int nBlockXSize, nBlockYSize;
7336
0
    poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7337
7338
0
    if (poMaskBand)
7339
0
    {
7340
0
        pabyMaskData =
7341
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7342
0
        if (!pabyMaskData)
7343
0
        {
7344
0
            return false;
7345
0
        }
7346
0
    }
7347
7348
0
    for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7349
0
         iSampleBlock += nSampleRate)
7350
0
    {
7351
0
        const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7352
0
        const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7353
7354
0
        int nXCheck = 0, nYCheck = 0;
7355
0
        poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7356
7357
0
        if (poMaskBand &&
7358
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7359
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
7360
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7361
0
                                 nBlockXSize, nullptr) != CE_None)
7362
0
        {
7363
0
            CPLFree(pabyMaskData);
7364
0
            return false;
7365
0
        }
7366
7367
0
        GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7368
0
        if (poBlock == nullptr)
7369
0
        {
7370
0
            CPLFree(pabyMaskData);
7371
0
            return false;
7372
0
        }
7373
7374
0
        void *const pData = poBlock->GetDataRef();
7375
7376
0
        ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7377
0
                             nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
7378
0
                             dfMax);
7379
7380
0
        poBlock->DropLock();
7381
0
    }
7382
7383
0
    CPLFree(pabyMaskData);
7384
0
    return true;
7385
0
}
7386
7387
/**
7388
 * \brief Compute the min/max values for a band.
7389
 *
7390
 * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7391
 * be trusted.  If it doesn't work, a subsample of blocks will be read to
7392
 * get an approximate min/max.  If the band has a nodata value it will
7393
 * be excluded from the minimum and maximum.
7394
 *
7395
 * If bApprox is FALSE, then all pixels will be read and used to compute
7396
 * an exact range.
7397
 *
7398
 * This method is the same as the C function GDALComputeRasterMinMax().
7399
 *
7400
 * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7401
 * FALSE.
7402
 * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7403
 * maximum (adfMinMax[1]) are returned.
7404
 *
7405
 * @return CE_None on success or CE_Failure on failure.
7406
 */
7407
7408
CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7409
0
{
7410
    /* -------------------------------------------------------------------- */
7411
    /*      Does the driver already know the min/max?                       */
7412
    /* -------------------------------------------------------------------- */
7413
0
    if (bApproxOK)
7414
0
    {
7415
0
        int bSuccessMin = FALSE;
7416
0
        int bSuccessMax = FALSE;
7417
7418
0
        double dfMin = GetMinimum(&bSuccessMin);
7419
0
        double dfMax = GetMaximum(&bSuccessMax);
7420
7421
0
        if (bSuccessMin && bSuccessMax)
7422
0
        {
7423
0
            adfMinMax[0] = dfMin;
7424
0
            adfMinMax[1] = dfMax;
7425
0
            return CE_None;
7426
0
        }
7427
0
    }
7428
7429
    /* -------------------------------------------------------------------- */
7430
    /*      If we have overview bands, use them for min/max.                */
7431
    /* -------------------------------------------------------------------- */
7432
    // cppcheck-suppress knownConditionTrueFalse
7433
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7434
0
    {
7435
0
        GDALRasterBand *poBand =
7436
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7437
7438
0
        if (poBand != this)
7439
0
            return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7440
0
    }
7441
7442
    /* -------------------------------------------------------------------- */
7443
    /*      Read actual data and compute minimum and maximum.               */
7444
    /* -------------------------------------------------------------------- */
7445
0
    GDALNoDataValues sNoDataValues(this, eDataType);
7446
0
    GDALRasterBand *poMaskBand = nullptr;
7447
0
    if (!sNoDataValues.bGotNoDataValue)
7448
0
    {
7449
0
        const int l_nMaskFlags = GetMaskFlags();
7450
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
7451
0
            GetColorInterpretation() != GCI_AlphaBand)
7452
0
        {
7453
0
            poMaskBand = GetMaskBand();
7454
0
        }
7455
0
    }
7456
7457
0
    bool bSignedByte = false;
7458
0
    if (eDataType == GDT_Byte)
7459
0
    {
7460
0
        EnablePixelTypeSignedByteWarning(false);
7461
0
        const char *pszPixelType =
7462
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7463
0
        EnablePixelTypeSignedByteWarning(true);
7464
0
        bSignedByte =
7465
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7466
0
    }
7467
7468
0
    GDALRasterIOExtraArg sExtraArg;
7469
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7470
7471
0
    GUInt32 nMin = (eDataType == GDT_Byte)
7472
0
                       ? 255
7473
0
                       : 65535;  // used for GByte & GUInt16 cases
7474
0
    GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
7475
0
    GInt16 nMinInt16 =
7476
0
        std::numeric_limits<GInt16>::max();  // used for GInt16 case
7477
0
    GInt16 nMaxInt16 =
7478
0
        std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
7479
0
    double dfMin =
7480
0
        std::numeric_limits<double>::infinity();  // used for generic code path
7481
0
    double dfMax =
7482
0
        -std::numeric_limits<double>::infinity();  // used for generic code path
7483
0
    const bool bUseOptimizedPath =
7484
0
        !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7485
0
                        eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7486
7487
0
    const auto ComputeMinMaxForBlock =
7488
0
        [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
7489
0
         &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
7490
0
                     int nYCheck)
7491
0
    {
7492
0
        if (eDataType == GDT_Byte && !bSignedByte)
7493
0
        {
7494
0
            const bool bHasNoData =
7495
0
                sNoDataValues.bGotNoDataValue &&
7496
0
                GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
7497
0
                static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
7498
0
                    sNoDataValues.dfNoDataValue;
7499
0
            const GUInt32 nNoDataValue =
7500
0
                bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
7501
0
                           : 0;
7502
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
7503
0
            ComputeStatisticsInternal<GByte,
7504
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
7505
0
                f(nXCheck, nBufferWidth, nYCheck,
7506
0
                  static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7507
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7508
0
        }
7509
0
        else if (eDataType == GDT_UInt16)
7510
0
        {
7511
0
            const bool bHasNoData =
7512
0
                sNoDataValues.bGotNoDataValue &&
7513
0
                GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
7514
0
                static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
7515
0
                    sNoDataValues.dfNoDataValue;
7516
0
            const GUInt32 nNoDataValue =
7517
0
                bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
7518
0
                           : 0;
7519
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
7520
0
            ComputeStatisticsInternal<GUInt16,
7521
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
7522
0
                f(nXCheck, nBufferWidth, nYCheck,
7523
0
                  static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7524
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7525
0
        }
7526
0
        else if (eDataType == GDT_Int16)
7527
0
        {
7528
0
            const bool bHasNoData =
7529
0
                sNoDataValues.bGotNoDataValue &&
7530
0
                GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
7531
0
                static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
7532
0
                    sNoDataValues.dfNoDataValue;
7533
0
            if (bHasNoData)
7534
0
            {
7535
0
                const int16_t nNoDataValue =
7536
0
                    static_cast<int16_t>(sNoDataValues.dfNoDataValue);
7537
0
                for (int iY = 0; iY < nYCheck; iY++)
7538
0
                {
7539
0
                    ComputeMinMax<int16_t, true>(
7540
0
                        static_cast<const int16_t *>(pData) +
7541
0
                            static_cast<size_t>(iY) * nBufferWidth,
7542
0
                        nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7543
0
                }
7544
0
            }
7545
0
            else
7546
0
            {
7547
0
                for (int iY = 0; iY < nYCheck; iY++)
7548
0
                {
7549
0
                    ComputeMinMax<int16_t, false>(
7550
0
                        static_cast<const int16_t *>(pData) +
7551
0
                            static_cast<size_t>(iY) * nBufferWidth,
7552
0
                        nXCheck, 0, &nMinInt16, &nMaxInt16);
7553
0
                }
7554
0
            }
7555
0
        }
7556
0
    };
7557
7558
0
    if (bApproxOK && HasArbitraryOverviews())
7559
0
    {
7560
        /* --------------------------------------------------------------------
7561
         */
7562
        /*      Figure out how much the image should be reduced to get an */
7563
        /*      approximate value. */
7564
        /* --------------------------------------------------------------------
7565
         */
7566
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7567
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7568
7569
0
        int nXReduced = nRasterXSize;
7570
0
        int nYReduced = nRasterYSize;
7571
0
        if (dfReduction > 1.0)
7572
0
        {
7573
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7574
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7575
7576
            // Catch the case of huge resizing ratios here
7577
0
            if (nXReduced == 0)
7578
0
                nXReduced = 1;
7579
0
            if (nYReduced == 0)
7580
0
                nYReduced = 1;
7581
0
        }
7582
7583
0
        void *const pData = CPLMalloc(cpl::fits_on<int>(
7584
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7585
7586
0
        const CPLErr eErr =
7587
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7588
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7589
0
        if (eErr != CE_None)
7590
0
        {
7591
0
            CPLFree(pData);
7592
0
            return eErr;
7593
0
        }
7594
7595
0
        GByte *pabyMaskData = nullptr;
7596
0
        if (poMaskBand)
7597
0
        {
7598
0
            pabyMaskData =
7599
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7600
0
            if (!pabyMaskData)
7601
0
            {
7602
0
                CPLFree(pData);
7603
0
                return CE_Failure;
7604
0
            }
7605
7606
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7607
0
                                     pabyMaskData, nXReduced, nYReduced,
7608
0
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
7609
0
            {
7610
0
                CPLFree(pData);
7611
0
                CPLFree(pabyMaskData);
7612
0
                return CE_Failure;
7613
0
            }
7614
0
        }
7615
7616
0
        if (bUseOptimizedPath)
7617
0
        {
7618
0
            ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7619
0
        }
7620
0
        else
7621
0
        {
7622
0
            ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
7623
0
                                 nYReduced, nXReduced, sNoDataValues,
7624
0
                                 pabyMaskData, dfMin, dfMax);
7625
0
        }
7626
7627
0
        CPLFree(pData);
7628
0
        CPLFree(pabyMaskData);
7629
0
    }
7630
7631
0
    else  // No arbitrary overviews
7632
0
    {
7633
0
        if (!InitBlockInfo())
7634
0
            return CE_Failure;
7635
7636
        /* --------------------------------------------------------------------
7637
         */
7638
        /*      Figure out the ratio of blocks we will read to get an */
7639
        /*      approximate value. */
7640
        /* --------------------------------------------------------------------
7641
         */
7642
0
        int nSampleRate = 1;
7643
7644
0
        if (bApproxOK)
7645
0
        {
7646
0
            nSampleRate = static_cast<int>(std::max(
7647
0
                1.0,
7648
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7649
            // We want to avoid probing only the first column of blocks for
7650
            // a square shaped raster, because it is not unlikely that it may
7651
            // be padding only (#6378).
7652
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7653
0
                nSampleRate += 1;
7654
0
        }
7655
7656
0
        if (bUseOptimizedPath)
7657
0
        {
7658
0
            for (GIntBig iSampleBlock = 0;
7659
0
                 iSampleBlock <
7660
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7661
0
                 iSampleBlock += nSampleRate)
7662
0
            {
7663
0
                const int iYBlock =
7664
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
7665
0
                const int iXBlock =
7666
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
7667
7668
0
                GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7669
0
                if (poBlock == nullptr)
7670
0
                    return CE_Failure;
7671
7672
0
                void *const pData = poBlock->GetDataRef();
7673
7674
0
                int nXCheck = 0, nYCheck = 0;
7675
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7676
7677
0
                ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7678
7679
0
                poBlock->DropLock();
7680
7681
0
                if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7682
0
                    nMax == 255)
7683
0
                    break;
7684
0
            }
7685
0
        }
7686
0
        else
7687
0
        {
7688
0
            const GIntBig nTotalBlocks =
7689
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7690
0
            if (!ComputeMinMaxGenericIterBlocks(
7691
0
                    this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7692
0
                    nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
7693
0
            {
7694
0
                return CE_Failure;
7695
0
            }
7696
0
        }
7697
0
    }
7698
7699
0
    if (bUseOptimizedPath)
7700
0
    {
7701
0
        if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7702
0
        {
7703
0
            dfMin = nMin;
7704
0
            dfMax = nMax;
7705
0
        }
7706
0
        else if (eDataType == GDT_Int16)
7707
0
        {
7708
0
            dfMin = nMinInt16;
7709
0
            dfMax = nMaxInt16;
7710
0
        }
7711
0
    }
7712
7713
0
    if (dfMin > dfMax)
7714
0
    {
7715
0
        adfMinMax[0] = 0;
7716
0
        adfMinMax[1] = 0;
7717
0
        ReportError(
7718
0
            CE_Failure, CPLE_AppDefined,
7719
0
            "Failed to compute min/max, no valid pixels found in sampling.");
7720
0
        return CE_Failure;
7721
0
    }
7722
7723
0
    adfMinMax[0] = dfMin;
7724
0
    adfMinMax[1] = dfMax;
7725
7726
0
    return CE_None;
7727
0
}
7728
7729
/************************************************************************/
7730
/*                      GDALComputeRasterMinMax()                       */
7731
/************************************************************************/
7732
7733
/**
7734
 * \brief Compute the min/max values for a band.
7735
 *
7736
 * @see GDALRasterBand::ComputeRasterMinMax()
7737
 *
7738
 * @note Prior to GDAL 3.6, this function returned void
7739
 */
7740
7741
CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7742
                                           double adfMinMax[2])
7743
7744
0
{
7745
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7746
7747
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7748
0
    return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7749
0
}
7750
7751
/************************************************************************/
7752
/*                    ComputeRasterMinMaxLocation()                     */
7753
/************************************************************************/
7754
7755
/**
7756
 * \brief Compute the min/max values for a band, and their location.
7757
 *
7758
 * Pixels whose value matches the nodata value or are masked by the mask
7759
 * band are ignored.
7760
 *
7761
 * If the minimum or maximum value is hit in several locations, it is not
7762
 * specified which one will be returned.
7763
 *
7764
 * @param[out] pdfMin Pointer to the minimum value.
7765
 * @param[out] pdfMax Pointer to the maximum value.
7766
 * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7767
 * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7768
 * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7769
 * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7770
 *
7771
 * @return CE_None in case of success, CE_Warning if there are no valid values,
7772
 *         CE_Failure in case of error.
7773
 *
7774
 * @since GDAL 3.11
7775
 */
7776
7777
CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7778
                                                   double *pdfMax, int *pnMinX,
7779
                                                   int *pnMinY, int *pnMaxX,
7780
                                                   int *pnMaxY)
7781
0
{
7782
0
    int nMinX = -1;
7783
0
    int nMinY = -1;
7784
0
    int nMaxX = -1;
7785
0
    int nMaxY = -1;
7786
0
    double dfMin = std::numeric_limits<double>::infinity();
7787
0
    double dfMax = -std::numeric_limits<double>::infinity();
7788
0
    if (pdfMin)
7789
0
        *pdfMin = dfMin;
7790
0
    if (pdfMax)
7791
0
        *pdfMax = dfMax;
7792
0
    if (pnMinX)
7793
0
        *pnMinX = nMinX;
7794
0
    if (pnMinY)
7795
0
        *pnMinY = nMinY;
7796
0
    if (pnMaxX)
7797
0
        *pnMaxX = nMaxX;
7798
0
    if (pnMaxY)
7799
0
        *pnMaxY = nMaxY;
7800
7801
0
    if (GDALDataTypeIsComplex(eDataType))
7802
0
    {
7803
0
        CPLError(CE_Failure, CPLE_NotSupported,
7804
0
                 "Complex data type not supported");
7805
0
        return CE_Failure;
7806
0
    }
7807
7808
0
    if (!InitBlockInfo())
7809
0
        return CE_Failure;
7810
7811
0
    GDALNoDataValues sNoDataValues(this, eDataType);
7812
0
    GDALRasterBand *poMaskBand = nullptr;
7813
0
    if (!sNoDataValues.bGotNoDataValue)
7814
0
    {
7815
0
        const int l_nMaskFlags = GetMaskFlags();
7816
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
7817
0
            GetColorInterpretation() != GCI_AlphaBand)
7818
0
        {
7819
0
            poMaskBand = GetMaskBand();
7820
0
        }
7821
0
    }
7822
7823
0
    bool bSignedByte = false;
7824
0
    if (eDataType == GDT_Byte)
7825
0
    {
7826
0
        EnablePixelTypeSignedByteWarning(false);
7827
0
        const char *pszPixelType =
7828
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7829
0
        EnablePixelTypeSignedByteWarning(true);
7830
0
        bSignedByte =
7831
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7832
0
    }
7833
7834
0
    GByte *pabyMaskData = nullptr;
7835
0
    if (poMaskBand)
7836
0
    {
7837
0
        pabyMaskData =
7838
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7839
0
        if (!pabyMaskData)
7840
0
        {
7841
0
            return CE_Failure;
7842
0
        }
7843
0
    }
7844
7845
0
    const GIntBig nTotalBlocks =
7846
0
        static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7847
0
    bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7848
0
    bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7849
0
    for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7850
0
    {
7851
0
        const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7852
0
        const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7853
7854
0
        int nXCheck = 0, nYCheck = 0;
7855
0
        GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7856
7857
0
        if (poMaskBand &&
7858
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7859
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
7860
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7861
0
                                 nBlockXSize, nullptr) != CE_None)
7862
0
        {
7863
0
            CPLFree(pabyMaskData);
7864
0
            return CE_Failure;
7865
0
        }
7866
7867
0
        GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7868
0
        if (poBlock == nullptr)
7869
0
        {
7870
0
            CPLFree(pabyMaskData);
7871
0
            return CE_Failure;
7872
0
        }
7873
7874
0
        void *const pData = poBlock->GetDataRef();
7875
7876
0
        if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7877
0
        {
7878
0
            for (int iY = 0; iY < nYCheck; ++iY)
7879
0
            {
7880
0
                for (int iX = 0; iX < nXCheck; ++iX)
7881
0
                {
7882
0
                    const GPtrDiff_t iOffset =
7883
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7884
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
7885
0
                        continue;
7886
0
                    bool bValid = true;
7887
0
                    double dfValue =
7888
0
                        GetPixelValue(eDataType, bSignedByte, pData, iOffset,
7889
0
                                      sNoDataValues, bValid);
7890
0
                    if (!bValid)
7891
0
                        continue;
7892
0
                    if (dfValue < dfMin)
7893
0
                    {
7894
0
                        dfMin = dfValue;
7895
0
                        nMinX = iXBlock * nBlockXSize + iX;
7896
0
                        nMinY = iYBlock * nBlockYSize + iY;
7897
0
                    }
7898
0
                    if (dfValue > dfMax)
7899
0
                    {
7900
0
                        dfMax = dfValue;
7901
0
                        nMaxX = iXBlock * nBlockXSize + iX;
7902
0
                        nMaxY = iYBlock * nBlockYSize + iY;
7903
0
                    }
7904
0
                }
7905
0
            }
7906
0
        }
7907
0
        else
7908
0
        {
7909
0
            size_t pos_min = 0;
7910
0
            size_t pos_max = 0;
7911
0
            const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7912
0
            if (bNeedsMin && bNeedsMax)
7913
0
            {
7914
0
                std::tie(pos_min, pos_max) = gdal::minmax_element(
7915
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7916
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
7917
0
                    sNoDataValues.dfNoDataValue);
7918
0
            }
7919
0
            else if (bNeedsMin)
7920
0
            {
7921
0
                pos_min = gdal::min_element(
7922
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7923
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
7924
0
                    sNoDataValues.dfNoDataValue);
7925
0
            }
7926
0
            else if (bNeedsMax)
7927
0
            {
7928
0
                pos_max = gdal::max_element(
7929
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7930
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
7931
0
                    sNoDataValues.dfNoDataValue);
7932
0
            }
7933
7934
0
            if (bNeedsMin)
7935
0
            {
7936
0
                const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7937
0
                const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7938
0
                bool bValid = true;
7939
0
                const double dfMinValueBlock =
7940
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_min,
7941
0
                                  sNoDataValues, bValid);
7942
0
                if (bValid && dfMinValueBlock < dfMin)
7943
0
                {
7944
0
                    dfMin = dfMinValueBlock;
7945
0
                    nMinX = iXBlock * nBlockXSize + nMinXBlock;
7946
0
                    nMinY = iYBlock * nBlockYSize + nMinYBlock;
7947
0
                }
7948
0
            }
7949
7950
0
            if (bNeedsMax)
7951
0
            {
7952
0
                const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7953
0
                const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7954
0
                bool bValid = true;
7955
0
                const double dfMaxValueBlock =
7956
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_max,
7957
0
                                  sNoDataValues, bValid);
7958
0
                if (bValid && dfMaxValueBlock > dfMax)
7959
0
                {
7960
0
                    dfMax = dfMaxValueBlock;
7961
0
                    nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7962
0
                    nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7963
0
                }
7964
0
            }
7965
0
        }
7966
7967
0
        poBlock->DropLock();
7968
7969
0
        if (eDataType == GDT_Byte)
7970
0
        {
7971
0
            if (bNeedsMin && dfMin == 0)
7972
0
            {
7973
0
                bNeedsMin = false;
7974
0
            }
7975
0
            if (bNeedsMax && dfMax == 255)
7976
0
            {
7977
0
                bNeedsMax = false;
7978
0
            }
7979
0
            if (!bNeedsMin && !bNeedsMax)
7980
0
            {
7981
0
                break;
7982
0
            }
7983
0
        }
7984
0
    }
7985
7986
0
    CPLFree(pabyMaskData);
7987
7988
0
    if (pdfMin)
7989
0
        *pdfMin = dfMin;
7990
0
    if (pdfMax)
7991
0
        *pdfMax = dfMax;
7992
0
    if (pnMinX)
7993
0
        *pnMinX = nMinX;
7994
0
    if (pnMinY)
7995
0
        *pnMinY = nMinY;
7996
0
    if (pnMaxX)
7997
0
        *pnMaxX = nMaxX;
7998
0
    if (pnMaxY)
7999
0
        *pnMaxY = nMaxY;
8000
0
    return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
8001
0
                                                                  : CE_None;
8002
0
}
8003
8004
/************************************************************************/
8005
/*                    GDALComputeRasterMinMaxLocation()                 */
8006
/************************************************************************/
8007
8008
/**
8009
 * \brief Compute the min/max values for a band, and their location.
8010
 *
8011
 * @see GDALRasterBand::ComputeRasterMinMax()
8012
 * @since GDAL 3.11
8013
 */
8014
8015
CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
8016
                                       double *pdfMax, int *pnMinX, int *pnMinY,
8017
                                       int *pnMaxX, int *pnMaxY)
8018
8019
0
{
8020
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
8021
8022
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8023
0
    return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
8024
0
                                               pnMaxX, pnMaxY);
8025
0
}
8026
8027
/************************************************************************/
8028
/*                        SetDefaultHistogram()                         */
8029
/************************************************************************/
8030
8031
/* FIXME : add proper documentation */
8032
/**
8033
 * \brief Set default histogram.
8034
 *
8035
 * This method is the same as the C function GDALSetDefaultHistogram() and
8036
 * GDALSetDefaultHistogramEx()
8037
 */
8038
CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
8039
                                           double /* dfMax */,
8040
                                           int /* nBuckets */,
8041
                                           GUIntBig * /* panHistogram */)
8042
8043
0
{
8044
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8045
0
        ReportError(CE_Failure, CPLE_NotSupported,
8046
0
                    "SetDefaultHistogram() not implemented for this format.");
8047
8048
0
    return CE_Failure;
8049
0
}
8050
8051
/************************************************************************/
8052
/*                      GDALSetDefaultHistogram()                       */
8053
/************************************************************************/
8054
8055
/**
8056
 * \brief Set default histogram.
8057
 *
8058
 * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8059
 * 2 billion.
8060
 *
8061
 * @see GDALRasterBand::SetDefaultHistogram()
8062
 * @see GDALSetRasterHistogramEx()
8063
 */
8064
8065
CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8066
                                           double dfMax, int nBuckets,
8067
                                           int *panHistogram)
8068
8069
0
{
8070
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8071
8072
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8073
8074
0
    GUIntBig *panHistogramTemp =
8075
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8076
0
    if (panHistogramTemp == nullptr)
8077
0
    {
8078
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8079
0
                            "Out of memory in GDALSetDefaultHistogram().");
8080
0
        return CE_Failure;
8081
0
    }
8082
8083
0
    for (int i = 0; i < nBuckets; ++i)
8084
0
    {
8085
0
        panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8086
0
    }
8087
8088
0
    const CPLErr eErr =
8089
0
        poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8090
8091
0
    CPLFree(panHistogramTemp);
8092
8093
0
    return eErr;
8094
0
}
8095
8096
/************************************************************************/
8097
/*                     GDALSetDefaultHistogramEx()                      */
8098
/************************************************************************/
8099
8100
/**
8101
 * \brief Set default histogram.
8102
 *
8103
 * @see GDALRasterBand::SetDefaultHistogram()
8104
 *
8105
 * @since GDAL 2.0
8106
 */
8107
8108
CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8109
                                             double dfMin, double dfMax,
8110
                                             int nBuckets,
8111
                                             GUIntBig *panHistogram)
8112
8113
0
{
8114
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8115
8116
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8117
0
    return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8118
0
}
8119
8120
/************************************************************************/
8121
/*                           GetDefaultRAT()                            */
8122
/************************************************************************/
8123
8124
/**
8125
 * \brief Fetch default Raster Attribute Table.
8126
 *
8127
 * A RAT will be returned if there is a default one associated with the
8128
 * band, otherwise NULL is returned.  The returned RAT is owned by the
8129
 * band and should not be deleted by the application.
8130
 *
8131
 * This method is the same as the C function GDALGetDefaultRAT().
8132
 *
8133
 * @return NULL, or a pointer to an internal RAT owned by the band.
8134
 */
8135
8136
GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8137
8138
0
{
8139
0
    return nullptr;
8140
0
}
8141
8142
/************************************************************************/
8143
/*                         GDALGetDefaultRAT()                          */
8144
/************************************************************************/
8145
8146
/**
8147
 * \brief Fetch default Raster Attribute Table.
8148
 *
8149
 * @see GDALRasterBand::GetDefaultRAT()
8150
 */
8151
8152
GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8153
8154
0
{
8155
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8156
8157
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8158
0
    return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8159
0
}
8160
8161
/************************************************************************/
8162
/*                           SetDefaultRAT()                            */
8163
/************************************************************************/
8164
8165
/**
8166
 * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8167
 * \brief Set default Raster Attribute Table.
8168
 *
8169
 * Associates a default RAT with the band.  If not implemented for the
8170
 * format a CPLE_NotSupported error will be issued.  If successful a copy
8171
 * of the RAT is made, the original remains owned by the caller.
8172
 *
8173
 * This method is the same as the C function GDALSetDefaultRAT().
8174
 *
8175
 * @param poRAT the RAT to assign to the band.
8176
 *
8177
 * @return CE_None on success or CE_Failure if unsupported or otherwise
8178
 * failing.
8179
 */
8180
8181
/**/
8182
/**/
8183
8184
CPLErr
8185
GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8186
0
{
8187
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8188
0
    {
8189
0
        CPLPushErrorHandler(CPLQuietErrorHandler);
8190
0
        ReportError(CE_Failure, CPLE_NotSupported,
8191
0
                    "SetDefaultRAT() not implemented for this format.");
8192
0
        CPLPopErrorHandler();
8193
0
    }
8194
0
    return CE_Failure;
8195
0
}
8196
8197
/************************************************************************/
8198
/*                         GDALSetDefaultRAT()                          */
8199
/************************************************************************/
8200
8201
/**
8202
 * \brief Set default Raster Attribute Table.
8203
 *
8204
 * @see GDALRasterBand::GDALSetDefaultRAT()
8205
 */
8206
8207
CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
8208
                                     GDALRasterAttributeTableH hRAT)
8209
8210
0
{
8211
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
8212
8213
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8214
8215
0
    return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
8216
0
}
8217
8218
/************************************************************************/
8219
/*                            GetMaskBand()                             */
8220
/************************************************************************/
8221
8222
/**
8223
 * \brief Return the mask band associated with the band.
8224
 *
8225
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
8226
 * that returns one of four default implementations :
8227
 * <ul>
8228
 * <li>If a corresponding .msk file exists it will be used for the mask band.
8229
 * </li>
8230
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8231
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8232
 * GMF_NODATA | GMF_PER_DATASET.
8233
 * </li>
8234
 * <li>If the band has a nodata value set, an instance of the new
8235
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8236
 * GMF_NODATA.
8237
 * </li>
8238
 * <li>If there is no nodata value, but the dataset has an alpha band that seems
8239
 * to apply to this band (specific rules yet to be determined) and that is of
8240
 * type GDT_Byte then that alpha band will be returned, and the flags
8241
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8242
 * </li>
8243
 * <li>If neither of the above apply, an instance of the new
8244
 * GDALAllValidRasterBand class will be returned that has 255 values for all
8245
 * pixels. The null flags will return GMF_ALL_VALID.
8246
 * </li>
8247
 * </ul>
8248
 *
8249
 * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
8250
 * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
8251
 *
8252
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8253
 * dataset, with the same name as the main dataset and suffixed with .msk,
8254
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8255
 * main dataset.
8256
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8257
 * level, where xx matches the band number of a band of the main dataset. The
8258
 * value of those items is a combination of the flags GMF_ALL_VALID,
8259
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8260
 * a band, then the other rules explained above will be used to generate a
8261
 * on-the-fly mask band.
8262
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8263
 *
8264
 * This method is the same as the C function GDALGetMaskBand().
8265
 *
8266
 * @return a valid mask band.
8267
 *
8268
 * @since GDAL 1.5.0
8269
 *
8270
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8271
 *
8272
 */
8273
GDALRasterBand *GDALRasterBand::GetMaskBand()
8274
8275
0
{
8276
0
    const auto HasNoData = [this]()
8277
0
    {
8278
0
        int bHaveNoDataRaw = FALSE;
8279
0
        bool bHaveNoData = false;
8280
0
        if (eDataType == GDT_Int64)
8281
0
        {
8282
0
            CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
8283
0
            bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8284
0
        }
8285
0
        else if (eDataType == GDT_UInt64)
8286
0
        {
8287
0
            CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
8288
0
            bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8289
0
        }
8290
0
        else
8291
0
        {
8292
0
            const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
8293
0
            if (bHaveNoDataRaw &&
8294
0
                GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
8295
0
            {
8296
0
                bHaveNoData = true;
8297
0
            }
8298
0
        }
8299
0
        return bHaveNoData;
8300
0
    };
8301
8302
0
    if (poMask != nullptr)
8303
0
    {
8304
0
        if (poMask.IsOwned())
8305
0
        {
8306
0
            if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
8307
0
            {
8308
0
                if (HasNoData())
8309
0
                {
8310
0
                    InvalidateMaskBand();
8311
0
                }
8312
0
            }
8313
0
            else if (auto poNoDataMaskBand =
8314
0
                         dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
8315
0
            {
8316
0
                int bHaveNoDataRaw = FALSE;
8317
0
                bool bIsSame = false;
8318
0
                if (eDataType == GDT_Int64)
8319
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
8320
0
                                  GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
8321
0
                              bHaveNoDataRaw;
8322
0
                else if (eDataType == GDT_UInt64)
8323
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8324
0
                                  GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8325
0
                              bHaveNoDataRaw;
8326
0
                else
8327
0
                {
8328
0
                    const double dfNoDataValue =
8329
0
                        GetNoDataValue(&bHaveNoDataRaw);
8330
0
                    if (bHaveNoDataRaw)
8331
0
                    {
8332
0
                        bIsSame =
8333
0
                            std::isnan(dfNoDataValue)
8334
0
                                ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8335
0
                                : poNoDataMaskBand->m_dfNoDataValue ==
8336
0
                                      dfNoDataValue;
8337
0
                    }
8338
0
                }
8339
0
                if (!bIsSame)
8340
0
                    InvalidateMaskBand();
8341
0
            }
8342
0
        }
8343
8344
0
        if (poMask)
8345
0
            return poMask.get();
8346
0
    }
8347
8348
    /* -------------------------------------------------------------------- */
8349
    /*      Check for a mask in a .msk file.                                */
8350
    /* -------------------------------------------------------------------- */
8351
0
    if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8352
0
    {
8353
0
        poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
8354
0
        if (poMask != nullptr)
8355
0
        {
8356
0
            nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8357
0
            return poMask.get();
8358
0
        }
8359
0
    }
8360
8361
    /* -------------------------------------------------------------------- */
8362
    /*      Check for NODATA_VALUES metadata.                               */
8363
    /* -------------------------------------------------------------------- */
8364
0
    if (poDS != nullptr)
8365
0
    {
8366
0
        const char *pszGDALNoDataValues =
8367
0
            poDS->GetMetadataItem("NODATA_VALUES");
8368
0
        if (pszGDALNoDataValues != nullptr)
8369
0
        {
8370
0
            char **papszGDALNoDataValues = CSLTokenizeStringComplex(
8371
0
                pszGDALNoDataValues, " ", FALSE, FALSE);
8372
8373
            // Make sure we have as many values as bands.
8374
0
            if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
8375
0
                poDS->GetRasterCount() != 0)
8376
0
            {
8377
                // Make sure that all bands have the same data type
8378
                // This is clearly not a fundamental condition, just a
8379
                // condition to make implementation easier.
8380
0
                GDALDataType eDT = GDT_Unknown;
8381
0
                int i = 0;  // Used after for.
8382
0
                for (; i < poDS->GetRasterCount(); ++i)
8383
0
                {
8384
0
                    if (i == 0)
8385
0
                        eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8386
0
                    else if (eDT !=
8387
0
                             poDS->GetRasterBand(i + 1)->GetRasterDataType())
8388
0
                    {
8389
0
                        break;
8390
0
                    }
8391
0
                }
8392
0
                if (i == poDS->GetRasterCount())
8393
0
                {
8394
0
                    nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8395
0
                    try
8396
0
                    {
8397
0
                        poMask.reset(
8398
0
                            std::make_unique<GDALNoDataValuesMaskBand>(poDS));
8399
0
                    }
8400
0
                    catch (const std::bad_alloc &)
8401
0
                    {
8402
0
                        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8403
0
                        poMask.reset();
8404
0
                    }
8405
0
                    CSLDestroy(papszGDALNoDataValues);
8406
0
                    return poMask.get();
8407
0
                }
8408
0
                else
8409
0
                {
8410
0
                    ReportError(CE_Warning, CPLE_AppDefined,
8411
0
                                "All bands should have the same type in "
8412
0
                                "order the NODATA_VALUES metadata item "
8413
0
                                "to be used as a mask.");
8414
0
                }
8415
0
            }
8416
0
            else
8417
0
            {
8418
0
                ReportError(
8419
0
                    CE_Warning, CPLE_AppDefined,
8420
0
                    "NODATA_VALUES metadata item doesn't have the same number "
8421
0
                    "of values as the number of bands.  "
8422
0
                    "Ignoring it for mask.");
8423
0
            }
8424
8425
0
            CSLDestroy(papszGDALNoDataValues);
8426
0
        }
8427
0
    }
8428
8429
    /* -------------------------------------------------------------------- */
8430
    /*      Check for nodata case.                                          */
8431
    /* -------------------------------------------------------------------- */
8432
0
    if (HasNoData())
8433
0
    {
8434
0
        nMaskFlags = GMF_NODATA;
8435
0
        try
8436
0
        {
8437
0
            poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
8438
0
        }
8439
0
        catch (const std::bad_alloc &)
8440
0
        {
8441
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8442
0
            poMask.reset();
8443
0
        }
8444
0
        return poMask.get();
8445
0
    }
8446
8447
    /* -------------------------------------------------------------------- */
8448
    /*      Check for alpha case.                                           */
8449
    /* -------------------------------------------------------------------- */
8450
0
    if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8451
0
        this == poDS->GetRasterBand(1) &&
8452
0
        poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8453
0
    {
8454
0
        if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8455
0
        {
8456
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8457
0
            poMask.resetNotOwned(poDS->GetRasterBand(2));
8458
0
            return poMask.get();
8459
0
        }
8460
0
        else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8461
0
        {
8462
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8463
0
            try
8464
0
            {
8465
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
8466
0
                    poDS->GetRasterBand(2)));
8467
0
            }
8468
0
            catch (const std::bad_alloc &)
8469
0
            {
8470
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8471
0
                poMask.reset();
8472
0
            }
8473
0
            return poMask.get();
8474
0
        }
8475
0
    }
8476
8477
0
    if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8478
0
        (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8479
0
         this == poDS->GetRasterBand(3)) &&
8480
0
        poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8481
0
    {
8482
0
        if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8483
0
        {
8484
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8485
0
            poMask.resetNotOwned(poDS->GetRasterBand(4));
8486
0
            return poMask.get();
8487
0
        }
8488
0
        else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8489
0
        {
8490
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8491
0
            try
8492
0
            {
8493
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
8494
0
                    poDS->GetRasterBand(4)));
8495
0
            }
8496
0
            catch (const std::bad_alloc &)
8497
0
            {
8498
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8499
0
                poMask.reset();
8500
0
            }
8501
0
            return poMask.get();
8502
0
        }
8503
0
    }
8504
8505
    /* -------------------------------------------------------------------- */
8506
    /*      Fallback to all valid case.                                     */
8507
    /* -------------------------------------------------------------------- */
8508
0
    nMaskFlags = GMF_ALL_VALID;
8509
0
    try
8510
0
    {
8511
0
        poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
8512
0
    }
8513
0
    catch (const std::bad_alloc &)
8514
0
    {
8515
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8516
0
        poMask.reset();
8517
0
    }
8518
8519
0
    return poMask.get();
8520
0
}
8521
8522
/************************************************************************/
8523
/*                          GDALGetMaskBand()                           */
8524
/************************************************************************/
8525
8526
/**
8527
 * \brief Return the mask band associated with the band.
8528
 *
8529
 * @see GDALRasterBand::GetMaskBand()
8530
 */
8531
8532
GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8533
8534
0
{
8535
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8536
8537
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8538
0
    return poBand->GetMaskBand();
8539
0
}
8540
8541
/************************************************************************/
8542
/*                            GetMaskFlags()                            */
8543
/************************************************************************/
8544
8545
/**
8546
 * \brief Return the status flags of the mask band associated with the band.
8547
 *
8548
 * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8549
 * the following available definitions that may be extended in the future:
8550
 * <ul>
8551
 * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8552
 * 255. When used this will normally be the only flag set.
8553
 * </li>
8554
 * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8555
 * dataset.
8556
 * </li>
8557
 * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8558
 * and may have values other than 0 and 255.
8559
 * </li>
8560
 * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8561
 * nodata values. (mutually exclusive of GMF_ALPHA)
8562
 * </li>
8563
 * </ul>
8564
 *
8565
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
8566
 * that returns one of four default implementations:
8567
 * <ul>
8568
 * <li>If a corresponding .msk file exists it will be used for the mask band.
8569
 * </li>
8570
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8571
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8572
 * GMF_NODATA | GMF_PER_DATASET.
8573
 * </li>
8574
 * <li>If the band has a nodata value set, an instance of the new
8575
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8576
 * GMF_NODATA.
8577
 * </li>
8578
 * <li>If there is no nodata value, but the dataset has an alpha band that
8579
 * seems to apply to this band (specific rules yet to be determined) and that is
8580
 * of type GDT_Byte then that alpha band will be returned, and the flags
8581
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8582
 * </li>
8583
 * <li>If neither of the above apply, an instance of the new
8584
 * GDALAllValidRasterBand class will be returned that has 255 values for all
8585
 * pixels. The null flags will return GMF_ALL_VALID.
8586
 * </li>
8587
 * </ul>
8588
 *
8589
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8590
 * dataset, with the same name as the main dataset and suffixed with .msk,
8591
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8592
 * main dataset.
8593
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8594
 * level, where xx matches the band number of a band of the main dataset. The
8595
 * value of those items is a combination of the flags GMF_ALL_VALID,
8596
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8597
 * a band, then the other rules explained above will be used to generate a
8598
 * on-the-fly mask band.
8599
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8600
 *
8601
 * This method is the same as the C function GDALGetMaskFlags().
8602
 *
8603
 * @since GDAL 1.5.0
8604
 *
8605
 * @return a valid mask band.
8606
 *
8607
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8608
 *
8609
 */
8610
int GDALRasterBand::GetMaskFlags()
8611
8612
0
{
8613
    // If we don't have a band yet, force this now so that the masks value
8614
    // will be initialized.
8615
8616
0
    if (poMask == nullptr)
8617
0
        GetMaskBand();
8618
8619
0
    return nMaskFlags;
8620
0
}
8621
8622
/************************************************************************/
8623
/*                          GDALGetMaskFlags()                          */
8624
/************************************************************************/
8625
8626
/**
8627
 * \brief Return the status flags of the mask band associated with the band.
8628
 *
8629
 * @see GDALRasterBand::GetMaskFlags()
8630
 */
8631
8632
int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8633
8634
0
{
8635
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8636
8637
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8638
0
    return poBand->GetMaskFlags();
8639
0
}
8640
8641
/************************************************************************/
8642
/*                         InvalidateMaskBand()                         */
8643
/************************************************************************/
8644
8645
//! @cond Doxygen_Suppress
8646
void GDALRasterBand::InvalidateMaskBand()
8647
0
{
8648
0
    poMask.reset();
8649
0
    nMaskFlags = 0;
8650
0
}
8651
8652
//! @endcond
8653
8654
/************************************************************************/
8655
/*                           CreateMaskBand()                           */
8656
/************************************************************************/
8657
8658
/**
8659
 * \brief Adds a mask band to the current band
8660
 *
8661
 * The default implementation of the CreateMaskBand() method is implemented
8662
 * based on similar rules to the .ovr handling implemented using the
8663
 * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8664
 * be created with the same basename as the original file, and it will have
8665
 * as many bands as the original image (or just one for GMF_PER_DATASET).
8666
 * The mask images will be deflate compressed tiled images with the same
8667
 * block size as the original image if possible.
8668
 * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8669
 * level, where xx matches the band number of a band of the main dataset. The
8670
 * value of those items will be the one of the nFlagsIn parameter.
8671
 *
8672
 * Note that if you got a mask band with a previous call to GetMaskBand(),
8673
 * it might be invalidated by CreateMaskBand(). So you have to call
8674
 * GetMaskBand() again.
8675
 *
8676
 * This method is the same as the C function GDALCreateMaskBand().
8677
 *
8678
 * @since GDAL 1.5.0
8679
 *
8680
 * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8681
 *
8682
 * @return CE_None on success or CE_Failure on an error.
8683
 *
8684
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8685
 * @see GDALDataset::CreateMaskBand()
8686
 *
8687
 */
8688
8689
CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8690
8691
0
{
8692
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8693
0
    {
8694
0
        const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8695
0
        if (eErr != CE_None)
8696
0
            return eErr;
8697
8698
0
        InvalidateMaskBand();
8699
8700
0
        return CE_None;
8701
0
    }
8702
8703
0
    ReportError(CE_Failure, CPLE_NotSupported,
8704
0
                "CreateMaskBand() not supported for this band.");
8705
8706
0
    return CE_Failure;
8707
0
}
8708
8709
/************************************************************************/
8710
/*                         GDALCreateMaskBand()                         */
8711
/************************************************************************/
8712
8713
/**
8714
 * \brief Adds a mask band to the current band
8715
 *
8716
 * @see GDALRasterBand::CreateMaskBand()
8717
 */
8718
8719
CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8720
8721
0
{
8722
0
    VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8723
8724
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8725
0
    return poBand->CreateMaskBand(nFlags);
8726
0
}
8727
8728
/************************************************************************/
8729
/*                            IsMaskBand()                              */
8730
/************************************************************************/
8731
8732
/**
8733
 * \brief Returns whether a band is a mask band.
8734
 *
8735
 * Mask band must be understood in the broad term: it can be a per-dataset
8736
 * mask band, an alpha band, or an implicit mask band.
8737
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8738
 *
8739
 * This method is the same as the C function GDALIsMaskBand().
8740
 *
8741
 * @return true if the band is a mask band.
8742
 *
8743
 * @see GDALDataset::CreateMaskBand()
8744
 *
8745
 * @since GDAL 3.5.0
8746
 *
8747
 */
8748
8749
bool GDALRasterBand::IsMaskBand() const
8750
0
{
8751
    // The GeoTIFF driver, among others, override this method to
8752
    // also handle external .msk bands.
8753
0
    return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8754
0
           GCI_AlphaBand;
8755
0
}
8756
8757
/************************************************************************/
8758
/*                            GDALIsMaskBand()                          */
8759
/************************************************************************/
8760
8761
/**
8762
 * \brief Returns whether a band is a mask band.
8763
 *
8764
 * Mask band must be understood in the broad term: it can be a per-dataset
8765
 * mask band, an alpha band, or an implicit mask band.
8766
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8767
 *
8768
 * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8769
 *
8770
 * @return true if the band is a mask band.
8771
 *
8772
 * @see GDALRasterBand::IsMaskBand()
8773
 *
8774
 * @since GDAL 3.5.0
8775
 *
8776
 */
8777
8778
bool GDALIsMaskBand(GDALRasterBandH hBand)
8779
8780
0
{
8781
0
    VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8782
8783
0
    const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8784
0
    return poBand->IsMaskBand();
8785
0
}
8786
8787
/************************************************************************/
8788
/*                         GetMaskValueRange()                          */
8789
/************************************************************************/
8790
8791
/**
8792
 * \brief Returns the range of values that a mask band can take.
8793
 *
8794
 * @return the range of values that a mask band can take.
8795
 *
8796
 * @since GDAL 3.5.0
8797
 *
8798
 */
8799
8800
GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8801
0
{
8802
0
    return GMVR_UNKNOWN;
8803
0
}
8804
8805
/************************************************************************/
8806
/*                    GetIndexColorTranslationTo()                      */
8807
/************************************************************************/
8808
8809
/**
8810
 * \brief Compute translation table for color tables.
8811
 *
8812
 * When the raster band has a palette index, it may be useful to compute
8813
 * the "translation" of this palette to the palette of another band.
8814
 * The translation tries to do exact matching first, and then approximate
8815
 * matching if no exact matching is possible.
8816
 * This method returns a table such that table[i] = j where i is an index
8817
 * of the 'this' rasterband and j the corresponding index for the reference
8818
 * rasterband.
8819
 *
8820
 * This method is thought as internal to GDAL and is used for drivers
8821
 * like RPFTOC.
8822
 *
8823
 * The implementation only supports 1-byte palette rasterbands.
8824
 *
8825
 * @param poReferenceBand the raster band
8826
 * @param pTranslationTable an already allocated translation table (at least 256
8827
 * bytes), or NULL to let the method allocate it
8828
 * @param pApproximateMatching a pointer to a flag that is set if the matching
8829
 *                              is approximate. May be NULL.
8830
 *
8831
 * @return a translation table if the two bands are palette index and that they
8832
 * do not match or NULL in other cases. The table must be freed with CPLFree if
8833
 * NULL was passed for pTranslationTable.
8834
 */
8835
8836
unsigned char *
8837
GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8838
                                           unsigned char *pTranslationTable,
8839
                                           int *pApproximateMatching)
8840
0
{
8841
0
    if (poReferenceBand == nullptr)
8842
0
        return nullptr;
8843
8844
    // cppcheck-suppress knownConditionTrueFalse
8845
0
    if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8846
        // cppcheck-suppress knownConditionTrueFalse
8847
0
        GetColorInterpretation() == GCI_PaletteIndex &&
8848
0
        poReferenceBand->GetRasterDataType() == GDT_Byte &&
8849
0
        GetRasterDataType() == GDT_Byte)
8850
0
    {
8851
0
        const GDALColorTable *srcColorTable = GetColorTable();
8852
0
        GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8853
0
        if (srcColorTable != nullptr && destColorTable != nullptr)
8854
0
        {
8855
0
            const int nEntries = srcColorTable->GetColorEntryCount();
8856
0
            const int nRefEntries = destColorTable->GetColorEntryCount();
8857
8858
0
            int bHasNoDataValueSrc = FALSE;
8859
0
            double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8860
0
            if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8861
0
                  dfNoDataValueSrc <= 255 &&
8862
0
                  dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8863
0
                bHasNoDataValueSrc = FALSE;
8864
0
            const int noDataValueSrc =
8865
0
                bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8866
8867
0
            int bHasNoDataValueRef = FALSE;
8868
0
            const double dfNoDataValueRef =
8869
0
                poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8870
0
            if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8871
0
                  dfNoDataValueRef <= 255 &&
8872
0
                  dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8873
0
                bHasNoDataValueRef = FALSE;
8874
0
            const int noDataValueRef =
8875
0
                bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8876
8877
0
            bool samePalette = false;
8878
8879
0
            if (pApproximateMatching)
8880
0
                *pApproximateMatching = FALSE;
8881
8882
0
            if (nEntries == nRefEntries &&
8883
0
                bHasNoDataValueSrc == bHasNoDataValueRef &&
8884
0
                (bHasNoDataValueSrc == FALSE ||
8885
0
                 noDataValueSrc == noDataValueRef))
8886
0
            {
8887
0
                samePalette = true;
8888
0
                for (int i = 0; i < nEntries; ++i)
8889
0
                {
8890
0
                    if (noDataValueSrc == i)
8891
0
                        continue;
8892
0
                    const GDALColorEntry *entry =
8893
0
                        srcColorTable->GetColorEntry(i);
8894
0
                    const GDALColorEntry *entryRef =
8895
0
                        destColorTable->GetColorEntry(i);
8896
0
                    if (entry->c1 != entryRef->c1 ||
8897
0
                        entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8898
0
                    {
8899
0
                        samePalette = false;
8900
0
                    }
8901
0
                }
8902
0
            }
8903
8904
0
            if (!samePalette)
8905
0
            {
8906
0
                if (pTranslationTable == nullptr)
8907
0
                {
8908
0
                    pTranslationTable = static_cast<unsigned char *>(
8909
0
                        VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8910
0
                    if (pTranslationTable == nullptr)
8911
0
                        return nullptr;
8912
0
                }
8913
8914
                // Trying to remap the product palette on the subdataset
8915
                // palette.
8916
0
                for (int i = 0; i < nEntries; ++i)
8917
0
                {
8918
0
                    if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8919
0
                        noDataValueSrc == i)
8920
0
                        continue;
8921
0
                    const GDALColorEntry *entry =
8922
0
                        srcColorTable->GetColorEntry(i);
8923
0
                    bool bMatchFound = false;
8924
0
                    for (int j = 0; j < nRefEntries; ++j)
8925
0
                    {
8926
0
                        if (bHasNoDataValueRef && noDataValueRef == j)
8927
0
                            continue;
8928
0
                        const GDALColorEntry *entryRef =
8929
0
                            destColorTable->GetColorEntry(j);
8930
0
                        if (entry->c1 == entryRef->c1 &&
8931
0
                            entry->c2 == entryRef->c2 &&
8932
0
                            entry->c3 == entryRef->c3)
8933
0
                        {
8934
0
                            pTranslationTable[i] =
8935
0
                                static_cast<unsigned char>(j);
8936
0
                            bMatchFound = true;
8937
0
                            break;
8938
0
                        }
8939
0
                    }
8940
0
                    if (!bMatchFound)
8941
0
                    {
8942
                        // No exact match. Looking for closest color now.
8943
0
                        int best_j = 0;
8944
0
                        int best_distance = 0;
8945
0
                        if (pApproximateMatching)
8946
0
                            *pApproximateMatching = TRUE;
8947
0
                        for (int j = 0; j < nRefEntries; ++j)
8948
0
                        {
8949
0
                            const GDALColorEntry *entryRef =
8950
0
                                destColorTable->GetColorEntry(j);
8951
0
                            int distance = (entry->c1 - entryRef->c1) *
8952
0
                                               (entry->c1 - entryRef->c1) +
8953
0
                                           (entry->c2 - entryRef->c2) *
8954
0
                                               (entry->c2 - entryRef->c2) +
8955
0
                                           (entry->c3 - entryRef->c3) *
8956
0
                                               (entry->c3 - entryRef->c3);
8957
0
                            if (j == 0 || distance < best_distance)
8958
0
                            {
8959
0
                                best_j = j;
8960
0
                                best_distance = distance;
8961
0
                            }
8962
0
                        }
8963
0
                        pTranslationTable[i] =
8964
0
                            static_cast<unsigned char>(best_j);
8965
0
                    }
8966
0
                }
8967
0
                if (bHasNoDataValueRef && bHasNoDataValueSrc)
8968
0
                    pTranslationTable[noDataValueSrc] =
8969
0
                        static_cast<unsigned char>(noDataValueRef);
8970
8971
0
                return pTranslationTable;
8972
0
            }
8973
0
        }
8974
0
    }
8975
0
    return nullptr;
8976
0
}
8977
8978
/************************************************************************/
8979
/*                         SetFlushBlockErr()                           */
8980
/************************************************************************/
8981
8982
/**
8983
 * \brief Store that an error occurred while writing a dirty block.
8984
 *
8985
 * This function stores the fact that an error occurred while writing a dirty
8986
 * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8987
 * flushed when the block cache get full, it is not convenient/possible to
8988
 * report that a dirty block could not be written correctly. This function
8989
 * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8990
 * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8991
 * places where the user can easily match the error with the relevant dataset.
8992
 */
8993
8994
void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8995
0
{
8996
0
    eFlushBlockErr = eErr;
8997
0
}
8998
8999
/************************************************************************/
9000
/*                         IncDirtyBlocks()                             */
9001
/************************************************************************/
9002
9003
/**
9004
 * \brief Increment/decrement the number of dirty blocks
9005
 */
9006
9007
void GDALRasterBand::IncDirtyBlocks(int nInc)
9008
0
{
9009
0
    if (poBandBlockCache)
9010
0
        poBandBlockCache->IncDirtyBlocks(nInc);
9011
0
}
9012
9013
/************************************************************************/
9014
/*                            ReportError()                             */
9015
/************************************************************************/
9016
9017
#ifndef DOXYGEN_XML
9018
/**
9019
 * \brief Emits an error related to a raster band.
9020
 *
9021
 * This function is a wrapper for regular CPLError(). The only difference
9022
 * with CPLError() is that it prepends the error message with the dataset
9023
 * name and the band number.
9024
 *
9025
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
9026
 * @param err_no the error number (CPLE_*) from cpl_error.h.
9027
 * @param fmt a printf() style format string.  Any additional arguments
9028
 * will be treated as arguments to fill in this format in a manner
9029
 * similar to printf().
9030
 *
9031
 * @since GDAL 1.9.0
9032
 */
9033
9034
void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
9035
                                 const char *fmt, ...) const
9036
0
{
9037
0
    va_list args;
9038
9039
0
    va_start(args, fmt);
9040
9041
0
    const char *pszDSName = poDS ? poDS->GetDescription() : "";
9042
0
    pszDSName = CPLGetFilename(pszDSName);
9043
0
    if (pszDSName[0] != '\0')
9044
0
    {
9045
0
        CPLError(eErrClass, err_no, "%s",
9046
0
                 CPLString()
9047
0
                     .Printf("%s, band %d: ", pszDSName, GetBand())
9048
0
                     .append(CPLString().vPrintf(fmt, args))
9049
0
                     .c_str());
9050
0
    }
9051
0
    else
9052
0
    {
9053
0
        CPLErrorV(eErrClass, err_no, fmt, args);
9054
0
    }
9055
9056
0
    va_end(args);
9057
0
}
9058
#endif
9059
9060
/************************************************************************/
9061
/*                           GetVirtualMemAuto()                        */
9062
/************************************************************************/
9063
9064
/** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9065
 *
9066
 * Only supported on Linux and Unix systems with mmap() for now.
9067
 *
9068
 * This method allows creating a virtual memory object for a GDALRasterBand,
9069
 * that exposes the whole image data as a virtual array.
9070
 *
9071
 * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9072
 * specialized implementation, such as for raw files, may also directly use
9073
 * mechanisms of the operating system to create a view of the underlying file
9074
 * into virtual memory ( CPLVirtualMemFileMapNew() )
9075
 *
9076
 * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9077
 * offer a specialized implementation with direct file mapping, provided that
9078
 * some requirements are met :
9079
 *   - for all drivers, the dataset must be backed by a "real" file in the file
9080
 *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9081
 *     must match the native ordering of the CPU.
9082
 *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9083
 * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9084
 * the file in sequential order, and be equally spaced (which is generally the
9085
 * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9086
 * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9087
 *
9088
 * The pointer returned remains valid until CPLVirtualMemFree() is called.
9089
 * CPLVirtualMemFree() must be called before the raster band object is
9090
 * destroyed.
9091
 *
9092
 * If p is such a pointer and base_type the type matching
9093
 * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9094
 * accessed with
9095
 * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9096
 *
9097
 * This method is the same as the C GDALGetVirtualMemAuto() function.
9098
 *
9099
 * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9100
 * read/write the band.
9101
 *
9102
 * @param pnPixelSpace Output parameter giving the byte offset from the start of
9103
 * one pixel value in the buffer to the start of the next pixel value within a
9104
 * scanline.
9105
 *
9106
 * @param pnLineSpace Output parameter giving the byte offset from the start of
9107
 * one scanline in the buffer to the start of the next.
9108
 *
9109
 * @param papszOptions NULL terminated list of options.
9110
 *                     If a specialized implementation exists, defining
9111
 * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9112
 * used. On the contrary, starting with GDAL 2.2, defining
9113
 * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9114
 * being used (thus only allowing efficient implementations to be used). When
9115
 * requiring or falling back to the default implementation, the following
9116
 *                     options are available : CACHE_SIZE (in bytes, defaults to
9117
 * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9118
 * to FALSE)
9119
 *
9120
 * @return a virtual memory object that must be unreferenced by
9121
 * CPLVirtualMemFree(), or NULL in case of failure.
9122
 *
9123
 * @since GDAL 1.11
9124
 */
9125
9126
CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9127
                                                 int *pnPixelSpace,
9128
                                                 GIntBig *pnLineSpace,
9129
                                                 char **papszOptions)
9130
0
{
9131
0
    const char *pszImpl = CSLFetchNameValueDef(
9132
0
        papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9133
0
    if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9134
0
        EQUAL(pszImpl, "FALSE"))
9135
0
    {
9136
0
        return nullptr;
9137
0
    }
9138
9139
0
    const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9140
0
    const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9141
0
    if (pnPixelSpace)
9142
0
        *pnPixelSpace = nPixelSpace;
9143
0
    if (pnLineSpace)
9144
0
        *pnLineSpace = nLineSpace;
9145
0
    const size_t nCacheSize =
9146
0
        atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9147
0
    const size_t nPageSizeHint =
9148
0
        atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9149
0
    const bool bSingleThreadUsage = CPLTestBool(
9150
0
        CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9151
0
    return GDALRasterBandGetVirtualMem(
9152
0
        GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9153
0
        nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9154
0
        nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9155
0
        papszOptions);
9156
0
}
9157
9158
/************************************************************************/
9159
/*                         GDALGetVirtualMemAuto()                      */
9160
/************************************************************************/
9161
9162
/**
9163
 * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9164
 *
9165
 * @see GDALRasterBand::GetVirtualMemAuto()
9166
 */
9167
9168
CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9169
                                     int *pnPixelSpace, GIntBig *pnLineSpace,
9170
                                     CSLConstList papszOptions)
9171
0
{
9172
0
    VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9173
9174
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9175
9176
0
    return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9177
0
                                     const_cast<char **>(papszOptions));
9178
0
}
9179
9180
/************************************************************************/
9181
/*                        GDALGetDataCoverageStatus()                   */
9182
/************************************************************************/
9183
9184
/**
9185
 * \brief Get the coverage status of a sub-window of the raster.
9186
 *
9187
 * Returns whether a sub-window of the raster contains only data, only empty
9188
 * blocks or a mix of both. This function can be used to determine quickly
9189
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9190
 * be sparse.
9191
 *
9192
 * Empty blocks are blocks that are generally not physically present in the
9193
 * file, and when read through GDAL, contain only pixels whose value is the
9194
 * nodata value when it is set, or whose value is 0 when the nodata value is
9195
 * not set.
9196
 *
9197
 * The query is done in an efficient way without reading the actual pixel
9198
 * values. If not possible, or not implemented at all by the driver,
9199
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9200
 * be returned.
9201
 *
9202
 * The values that can be returned by the function are the following,
9203
 * potentially combined with the binary or operator :
9204
 * <ul>
9205
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9206
 * GetDataCoverageStatus(). This flag should be returned together with
9207
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9208
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9209
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9210
 * the queried window. This is typically identified by the concept of missing
9211
 * block in formats that supports it.
9212
 * </li>
9213
 * </ul>
9214
 *
9215
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9216
 * should be interpreted more as hint of potential presence of data. For example
9217
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9218
 * nodata value), instead of using the missing block mechanism,
9219
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9220
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9221
 *
9222
 * The nMaskFlagStop should be generally set to 0. It can be set to a
9223
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9224
 * the function as soon as the computed mask matches the nMaskFlagStop. For
9225
 * example, you can issue a request on the whole raster with nMaskFlagStop =
9226
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9227
 * the function will exit, so that you can potentially refine the requested area
9228
 * to find which particular region(s) have missing blocks.
9229
 *
9230
 * @see GDALRasterBand::GetDataCoverageStatus()
9231
 *
9232
 * @param hBand raster band
9233
 *
9234
 * @param nXOff The pixel offset to the top left corner of the region
9235
 * of the band to be queried. This would be zero to start from the left side.
9236
 *
9237
 * @param nYOff The line offset to the top left corner of the region
9238
 * of the band to be queried. This would be zero to start from the top.
9239
 *
9240
 * @param nXSize The width of the region of the band to be queried in pixels.
9241
 *
9242
 * @param nYSize The height of the region of the band to be queried in lines.
9243
 *
9244
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9245
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9246
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9247
 * as the computation of the coverage matches the mask, the computation will be
9248
 * stopped. *pdfDataPct will not be valid in that case.
9249
 *
9250
 * @param pdfDataPct Optional output parameter whose pointed value will be set
9251
 * to the (approximate) percentage in [0,100] of pixels in the queried
9252
 * sub-window that have valid values. The implementation might not always be
9253
 * able to compute it, in which case it will be set to a negative value.
9254
 *
9255
 * @return a binary-or'ed combination of possible values
9256
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9257
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9258
 *
9259
 * @note Added in GDAL 2.2
9260
 */
9261
9262
int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
9263
                                          int nYOff, int nXSize, int nYSize,
9264
                                          int nMaskFlagStop, double *pdfDataPct)
9265
0
{
9266
0
    VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
9267
0
                      GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
9268
9269
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9270
9271
0
    return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
9272
0
                                         nMaskFlagStop, pdfDataPct);
9273
0
}
9274
9275
/************************************************************************/
9276
/*                          GetDataCoverageStatus()                     */
9277
/************************************************************************/
9278
9279
/**
9280
 * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
9281
 *                                           int nYOff,
9282
 *                                           int nXSize,
9283
 *                                           int nYSize,
9284
 *                                           int nMaskFlagStop,
9285
 *                                           double* pdfDataPct)
9286
 * \brief Get the coverage status of a sub-window of the raster.
9287
 *
9288
 * Returns whether a sub-window of the raster contains only data, only empty
9289
 * blocks or a mix of both. This function can be used to determine quickly
9290
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9291
 * be sparse.
9292
 *
9293
 * Empty blocks are blocks that contain only pixels whose value is the nodata
9294
 * value when it is set, or whose value is 0 when the nodata value is not set.
9295
 *
9296
 * The query is done in an efficient way without reading the actual pixel
9297
 * values. If not possible, or not implemented at all by the driver,
9298
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9299
 * be returned.
9300
 *
9301
 * The values that can be returned by the function are the following,
9302
 * potentially combined with the binary or operator :
9303
 * <ul>
9304
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9305
 * GetDataCoverageStatus(). This flag should be returned together with
9306
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9307
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9308
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9309
 * the queried window. This is typically identified by the concept of missing
9310
 * block in formats that supports it.
9311
 * </li>
9312
 * </ul>
9313
 *
9314
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9315
 * should be interpreted more as hint of potential presence of data. For example
9316
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9317
 * nodata value), instead of using the missing block mechanism,
9318
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9319
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9320
 *
9321
 * The nMaskFlagStop should be generally set to 0. It can be set to a
9322
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9323
 * the function as soon as the computed mask matches the nMaskFlagStop. For
9324
 * example, you can issue a request on the whole raster with nMaskFlagStop =
9325
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9326
 * the function will exit, so that you can potentially refine the requested area
9327
 * to find which particular region(s) have missing blocks.
9328
 *
9329
 * @see GDALGetDataCoverageStatus()
9330
 *
9331
 * @param nXOff The pixel offset to the top left corner of the region
9332
 * of the band to be queried. This would be zero to start from the left side.
9333
 *
9334
 * @param nYOff The line offset to the top left corner of the region
9335
 * of the band to be queried. This would be zero to start from the top.
9336
 *
9337
 * @param nXSize The width of the region of the band to be queried in pixels.
9338
 *
9339
 * @param nYSize The height of the region of the band to be queried in lines.
9340
 *
9341
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9342
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9343
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9344
 * as the computation of the coverage matches the mask, the computation will be
9345
 * stopped. *pdfDataPct will not be valid in that case.
9346
 *
9347
 * @param pdfDataPct Optional output parameter whose pointed value will be set
9348
 * to the (approximate) percentage in [0,100] of pixels in the queried
9349
 * sub-window that have valid values. The implementation might not always be
9350
 * able to compute it, in which case it will be set to a negative value.
9351
 *
9352
 * @return a binary-or'ed combination of possible values
9353
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9354
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9355
 *
9356
 * @note Added in GDAL 2.2
9357
 */
9358
9359
/**
9360
 * \brief Get the coverage status of a sub-window of the raster.
9361
 *
9362
 * Returns whether a sub-window of the raster contains only data, only empty
9363
 * blocks or a mix of both. This function can be used to determine quickly
9364
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9365
 * be sparse.
9366
 *
9367
 * Empty blocks are blocks that contain only pixels whose value is the nodata
9368
 * value when it is set, or whose value is 0 when the nodata value is not set.
9369
 *
9370
 * The query is done in an efficient way without reading the actual pixel
9371
 * values. If not possible, or not implemented at all by the driver,
9372
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9373
 * be returned.
9374
 *
9375
 * The values that can be returned by the function are the following,
9376
 * potentially combined with the binary or operator :
9377
 * <ul>
9378
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9379
 * GetDataCoverageStatus(). This flag should be returned together with
9380
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9381
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9382
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9383
 * the queried window. This is typically identified by the concept of missing
9384
 * block in formats that supports it.
9385
 * </li>
9386
 * </ul>
9387
 *
9388
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9389
 * should be interpreted more as hint of potential presence of data. For example
9390
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9391
 * nodata value), instead of using the missing block mechanism,
9392
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9393
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9394
 *
9395
 * The nMaskFlagStop should be generally set to 0. It can be set to a
9396
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9397
 * the function as soon as the computed mask matches the nMaskFlagStop. For
9398
 * example, you can issue a request on the whole raster with nMaskFlagStop =
9399
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9400
 * the function will exit, so that you can potentially refine the requested area
9401
 * to find which particular region(s) have missing blocks.
9402
 *
9403
 * @see GDALGetDataCoverageStatus()
9404
 *
9405
 * @param nXOff The pixel offset to the top left corner of the region
9406
 * of the band to be queried. This would be zero to start from the left side.
9407
 *
9408
 * @param nYOff The line offset to the top left corner of the region
9409
 * of the band to be queried. This would be zero to start from the top.
9410
 *
9411
 * @param nXSize The width of the region of the band to be queried in pixels.
9412
 *
9413
 * @param nYSize The height of the region of the band to be queried in lines.
9414
 *
9415
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9416
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9417
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9418
 * as the computation of the coverage matches the mask, the computation will be
9419
 * stopped. *pdfDataPct will not be valid in that case.
9420
 *
9421
 * @param pdfDataPct Optional output parameter whose pointed value will be set
9422
 * to the (approximate) percentage in [0,100] of pixels in the queried
9423
 * sub-window that have valid values. The implementation might not always be
9424
 * able to compute it, in which case it will be set to a negative value.
9425
 *
9426
 * @return a binary-or'ed combination of possible values
9427
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9428
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9429
 *
9430
 * @note Added in GDAL 2.2
9431
 */
9432
9433
int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9434
                                          int nYSize, int nMaskFlagStop,
9435
                                          double *pdfDataPct)
9436
0
{
9437
0
    if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9438
0
        nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9439
0
        nYOff + nYSize > nRasterYSize)
9440
0
    {
9441
0
        CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9442
0
        if (pdfDataPct)
9443
0
            *pdfDataPct = 0.0;
9444
0
        return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9445
0
               GDAL_DATA_COVERAGE_STATUS_EMPTY;
9446
0
    }
9447
0
    return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9448
0
                                  pdfDataPct);
9449
0
}
9450
9451
/************************************************************************/
9452
/*                         IGetDataCoverageStatus()                     */
9453
/************************************************************************/
9454
9455
int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9456
                                           int /*nXSize*/, int /*nYSize*/,
9457
                                           int /*nMaskFlagStop*/,
9458
                                           double *pdfDataPct)
9459
0
{
9460
0
    if (pdfDataPct != nullptr)
9461
0
        *pdfDataPct = 100.0;
9462
0
    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9463
0
           GDAL_DATA_COVERAGE_STATUS_DATA;
9464
0
}
9465
9466
//! @cond Doxygen_Suppress
9467
/************************************************************************/
9468
/*                          EnterReadWrite()                            */
9469
/************************************************************************/
9470
9471
int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9472
0
{
9473
0
    if (poDS != nullptr)
9474
0
        return poDS->EnterReadWrite(eRWFlag);
9475
0
    return FALSE;
9476
0
}
9477
9478
/************************************************************************/
9479
/*                         LeaveReadWrite()                             */
9480
/************************************************************************/
9481
9482
void GDALRasterBand::LeaveReadWrite()
9483
0
{
9484
0
    if (poDS != nullptr)
9485
0
        poDS->LeaveReadWrite();
9486
0
}
9487
9488
/************************************************************************/
9489
/*                           InitRWLock()                               */
9490
/************************************************************************/
9491
9492
void GDALRasterBand::InitRWLock()
9493
0
{
9494
0
    if (poDS != nullptr)
9495
0
        poDS->InitRWLock();
9496
0
}
9497
9498
//! @endcond
9499
9500
// clang-format off
9501
9502
/**
9503
 * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9504
 * \brief Set metadata.
9505
 *
9506
 * CAUTION: depending on the format, older values of the updated information
9507
 * might still be found in the file in a "ghost" state, even if no longer
9508
 * accessible through the GDAL API. This is for example the case of the GTiff
9509
 * format (this is not a exhaustive list)
9510
 *
9511
 * The C function GDALSetMetadata() does the same thing as this method.
9512
 *
9513
 * @param papszMetadata the metadata in name=value string list format to
9514
 * apply.
9515
 * @param pszDomain the domain of interest.  Use "" or NULL for the default
9516
 * domain.
9517
 * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9518
 * metadata has been accepted, but is likely not maintained persistently
9519
 * by the underlying object between sessions.
9520
 */
9521
9522
/**
9523
 * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9524
 * \brief Set single metadata item.
9525
 *
9526
 * CAUTION: depending on the format, older values of the updated information
9527
 * might still be found in the file in a "ghost" state, even if no longer
9528
 * accessible through the GDAL API. This is for example the case of the GTiff
9529
 * format (this is not a exhaustive list)
9530
 *
9531
 * The C function GDALSetMetadataItem() does the same thing as this method.
9532
 *
9533
 * @param pszName the key for the metadata item to fetch.
9534
 * @param pszValue the value to assign to the key.
9535
 * @param pszDomain the domain to set within, use NULL for the default domain.
9536
 *
9537
 * @return CE_None on success, or an error code on failure.
9538
 */
9539
9540
// clang-format on
9541
9542
//! @cond Doxygen_Suppress
9543
/************************************************************************/
9544
/*                    EnablePixelTypeSignedByteWarning()                */
9545
/************************************************************************/
9546
9547
void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9548
0
{
9549
0
    m_bEnablePixelTypeSignedByteWarning = b;
9550
0
}
9551
9552
void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9553
0
{
9554
0
    GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9555
0
}
9556
9557
//! @endcond
9558
9559
/************************************************************************/
9560
/*                           GetMetadataItem()                          */
9561
/************************************************************************/
9562
9563
const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9564
                                            const char *pszDomain)
9565
0
{
9566
    // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9567
0
    if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9568
0
        pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9569
0
        EQUAL(pszName, "PIXELTYPE"))
9570
0
    {
9571
0
        CPLError(CE_Warning, CPLE_AppDefined,
9572
0
                 "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9573
0
                 "used to signal signed 8-bit raster. Change your code to "
9574
0
                 "test for the new GDT_Int8 data type instead.");
9575
0
    }
9576
0
    return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9577
0
}
9578
9579
/************************************************************************/
9580
/*                            WindowIterator                            */
9581
/************************************************************************/
9582
9583
//! @cond Doxygen_Suppress
9584
9585
GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
9586
                                               int nRasterYSize,
9587
                                               int nBlockXSize, int nBlockYSize,
9588
                                               int nRow, int nCol)
9589
0
    : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
9590
0
      m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
9591
0
      m_col(nCol)
9592
0
{
9593
0
}
9594
9595
bool GDALRasterBand::WindowIterator::operator==(
9596
    const WindowIterator &other) const
9597
0
{
9598
0
    return m_row == other.m_row && m_col == other.m_col &&
9599
0
           m_nRasterXSize == other.m_nRasterXSize &&
9600
0
           m_nRasterYSize == other.m_nRasterYSize &&
9601
0
           m_nBlockXSize == other.m_nBlockXSize &&
9602
0
           m_nBlockYSize == other.m_nBlockYSize;
9603
0
}
9604
9605
bool GDALRasterBand::WindowIterator::operator!=(
9606
    const WindowIterator &other) const
9607
0
{
9608
0
    return !(*this == other);
9609
0
}
9610
9611
GDALRasterBand::WindowIterator::value_type
9612
GDALRasterBand::WindowIterator::operator*() const
9613
0
{
9614
0
    GDALRasterWindow ret;
9615
0
    ret.nXOff = m_col * m_nBlockXSize;
9616
0
    ret.nYOff = m_row * m_nBlockYSize;
9617
0
    ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
9618
0
    ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
9619
9620
0
    return ret;
9621
0
}
9622
9623
GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
9624
0
{
9625
0
    m_col++;
9626
0
    if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
9627
0
    {
9628
0
        m_col = 0;
9629
0
        m_row++;
9630
0
    }
9631
0
    return *this;
9632
0
}
9633
9634
GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
9635
    const GDALRasterBand &band)
9636
0
    : m_nRasterXSize(band.GetXSize()), m_nRasterYSize(band.GetYSize()),
9637
0
      m_nBlockXSize(-1), m_nBlockYSize(-1)
9638
0
{
9639
0
    band.GetBlockSize(&m_nBlockXSize, &m_nBlockYSize);
9640
0
}
9641
9642
GDALRasterBand::WindowIterator
9643
GDALRasterBand::WindowIteratorWrapper::begin() const
9644
0
{
9645
0
    return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
9646
0
                          m_nBlockYSize, 0, 0);
9647
0
}
9648
9649
GDALRasterBand::WindowIterator
9650
GDALRasterBand::WindowIteratorWrapper::end() const
9651
0
{
9652
0
    return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
9653
0
                          m_nBlockYSize,
9654
0
                          DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
9655
0
}
9656
9657
//! @endcond
9658
9659
/** Return an object whose begin() and end() methods can be used to iterate
9660
 *  over a GDALRasterWindow for each block in this raster band. The iteration
9661
 *  order is from left to right, then from top to bottom.
9662
 *
9663
\code{.cpp}
9664
    std::vector<double> pixelValues;
9665
    for (const auto& window : poBand->IterateWindows()) {
9666
        CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
9667
                                         window.nXSize, window.nYSize);
9668
        // check eErr
9669
    }
9670
\endcode
9671
 *
9672
 *
9673
 *  @since GDAL 3.12
9674
 */
9675
GDALRasterBand::WindowIteratorWrapper GDALRasterBand::IterateWindows() const
9676
0
{
9677
0
    return WindowIteratorWrapper(*this);
9678
0
}
9679
9680
/************************************************************************/
9681
/*                     GDALMDArrayFromRasterBand                        */
9682
/************************************************************************/
9683
9684
class GDALMDArrayFromRasterBand final : public GDALMDArray
9685
{
9686
    CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9687
9688
    GDALDataset *m_poDS;
9689
    GDALRasterBand *m_poBand;
9690
    GDALExtendedDataType m_dt;
9691
    std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9692
    std::string m_osUnit;
9693
    std::vector<GByte> m_pabyNoData{};
9694
    std::shared_ptr<GDALMDArray> m_varX{};
9695
    std::shared_ptr<GDALMDArray> m_varY{};
9696
    std::string m_osFilename{};
9697
9698
    bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9699
                   const size_t *count, const GInt64 *arrayStep,
9700
                   const GPtrDiff_t *bufferStride,
9701
                   const GDALExtendedDataType &bufferDataType,
9702
                   void *pBuffer) const;
9703
9704
  protected:
9705
    GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9706
0
        : GDALAbstractMDArray(std::string(),
9707
0
                              std::string(poDS->GetDescription()) +
9708
0
                                  CPLSPrintf(" band %d", poBand->GetBand())),
9709
0
          GDALMDArray(std::string(),
9710
0
                      std::string(poDS->GetDescription()) +
9711
0
                          CPLSPrintf(" band %d", poBand->GetBand())),
9712
0
          m_poDS(poDS), m_poBand(poBand),
9713
0
          m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9714
0
          m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9715
0
    {
9716
0
        m_poDS->Reference();
9717
9718
0
        int bHasNoData = false;
9719
0
        if (m_poBand->GetRasterDataType() == GDT_Int64)
9720
0
        {
9721
0
            const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9722
0
            if (bHasNoData)
9723
0
            {
9724
0
                m_pabyNoData.resize(m_dt.GetSize());
9725
0
                GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9726
0
                                m_dt.GetNumericDataType(), 0, 1);
9727
0
            }
9728
0
        }
9729
0
        else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9730
0
        {
9731
0
            const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9732
0
            if (bHasNoData)
9733
0
            {
9734
0
                m_pabyNoData.resize(m_dt.GetSize());
9735
0
                GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9736
0
                                m_dt.GetNumericDataType(), 0, 1);
9737
0
            }
9738
0
        }
9739
0
        else
9740
0
        {
9741
0
            const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9742
0
            if (bHasNoData)
9743
0
            {
9744
0
                m_pabyNoData.resize(m_dt.GetSize());
9745
0
                GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9746
0
                                m_dt.GetNumericDataType(), 0, 1);
9747
0
            }
9748
0
        }
9749
9750
0
        const int nXSize = poBand->GetXSize();
9751
0
        const int nYSize = poBand->GetYSize();
9752
9753
0
        auto poSRS = m_poDS->GetSpatialRef();
9754
0
        std::string osTypeY;
9755
0
        std::string osTypeX;
9756
0
        std::string osDirectionY;
9757
0
        std::string osDirectionX;
9758
0
        if (poSRS && poSRS->GetAxesCount() == 2)
9759
0
        {
9760
0
            const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9761
0
            OGRAxisOrientation eOrientation1 = OAO_Other;
9762
0
            poSRS->GetAxis(nullptr, 0, &eOrientation1);
9763
0
            OGRAxisOrientation eOrientation2 = OAO_Other;
9764
0
            poSRS->GetAxis(nullptr, 1, &eOrientation2);
9765
0
            if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9766
0
            {
9767
0
                if (mapping == std::vector<int>{1, 2})
9768
0
                {
9769
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9770
0
                    osDirectionY = "NORTH";
9771
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9772
0
                    osDirectionX = "EAST";
9773
0
                }
9774
0
            }
9775
0
            else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9776
0
            {
9777
0
                if (mapping == std::vector<int>{2, 1})
9778
0
                {
9779
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9780
0
                    osDirectionY = "NORTH";
9781
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9782
0
                    osDirectionX = "EAST";
9783
0
                }
9784
0
            }
9785
0
        }
9786
9787
0
        m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9788
0
                      "/", "Y", osTypeY, osDirectionY, nYSize),
9789
0
                  std::make_shared<GDALDimensionWeakIndexingVar>(
9790
0
                      "/", "X", osTypeX, osDirectionX, nXSize)};
9791
9792
0
        GDALGeoTransform gt;
9793
0
        if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
9794
0
        {
9795
0
            m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
9796
0
                                                        gt[0], gt[1], 0.5);
9797
0
            m_dims[1]->SetIndexingVariable(m_varX);
9798
9799
0
            m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
9800
0
                                                        gt[3], gt[5], 0.5);
9801
0
            m_dims[0]->SetIndexingVariable(m_varY);
9802
0
        }
9803
0
    }
9804
9805
    bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9806
               const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9807
               const GDALExtendedDataType &bufferDataType,
9808
               void *pDstBuffer) const override;
9809
9810
    bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9811
                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9812
                const GDALExtendedDataType &bufferDataType,
9813
                const void *pSrcBuffer) override
9814
0
    {
9815
0
        return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9816
0
                         bufferStride, bufferDataType,
9817
0
                         const_cast<void *>(pSrcBuffer));
9818
0
    }
9819
9820
  public:
9821
    ~GDALMDArrayFromRasterBand()
9822
0
    {
9823
0
        m_poDS->ReleaseRef();
9824
0
    }
9825
9826
    static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9827
                                               GDALRasterBand *poBand)
9828
0
    {
9829
0
        auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9830
0
            new GDALMDArrayFromRasterBand(poDS, poBand)));
9831
0
        array->SetSelf(array);
9832
0
        return array;
9833
0
    }
9834
9835
    bool IsWritable() const override
9836
0
    {
9837
0
        return m_poDS->GetAccess() == GA_Update;
9838
0
    }
9839
9840
    const std::string &GetFilename() const override
9841
0
    {
9842
0
        return m_osFilename;
9843
0
    }
9844
9845
    const std::vector<std::shared_ptr<GDALDimension>> &
9846
    GetDimensions() const override
9847
0
    {
9848
0
        return m_dims;
9849
0
    }
9850
9851
    const GDALExtendedDataType &GetDataType() const override
9852
0
    {
9853
0
        return m_dt;
9854
0
    }
9855
9856
    const std::string &GetUnit() const override
9857
0
    {
9858
0
        return m_osUnit;
9859
0
    }
9860
9861
    const void *GetRawNoDataValue() const override
9862
0
    {
9863
0
        return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9864
0
    }
9865
9866
    double GetOffset(bool *pbHasOffset,
9867
                     GDALDataType *peStorageType) const override
9868
0
    {
9869
0
        int bHasOffset = false;
9870
0
        double dfRes = m_poBand->GetOffset(&bHasOffset);
9871
0
        if (pbHasOffset)
9872
0
            *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9873
0
        if (peStorageType)
9874
0
            *peStorageType = GDT_Unknown;
9875
0
        return dfRes;
9876
0
    }
9877
9878
    double GetScale(bool *pbHasScale,
9879
                    GDALDataType *peStorageType) const override
9880
0
    {
9881
0
        int bHasScale = false;
9882
0
        double dfRes = m_poBand->GetScale(&bHasScale);
9883
0
        if (pbHasScale)
9884
0
            *pbHasScale = CPL_TO_BOOL(bHasScale);
9885
0
        if (peStorageType)
9886
0
            *peStorageType = GDT_Unknown;
9887
0
        return dfRes;
9888
0
    }
9889
9890
    std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9891
0
    {
9892
0
        auto poSrcSRS = m_poDS->GetSpatialRef();
9893
0
        if (!poSrcSRS)
9894
0
            return nullptr;
9895
0
        auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9896
9897
0
        auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9898
0
        constexpr int iYDim = 0;
9899
0
        constexpr int iXDim = 1;
9900
0
        for (auto &m : axisMapping)
9901
0
        {
9902
0
            if (m == 1)
9903
0
                m = iXDim + 1;
9904
0
            else if (m == 2)
9905
0
                m = iYDim + 1;
9906
0
            else
9907
0
                m = 0;
9908
0
        }
9909
0
        poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9910
0
        return poSRS;
9911
0
    }
9912
9913
    std::vector<GUInt64> GetBlockSize() const override
9914
0
    {
9915
0
        int nBlockXSize = 0;
9916
0
        int nBlockYSize = 0;
9917
0
        m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9918
0
        return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9919
0
                                    static_cast<GUInt64>(nBlockXSize)};
9920
0
    }
9921
9922
    class MDIAsAttribute : public GDALAttribute
9923
    {
9924
        std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9925
        const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
9926
        std::string m_osValue;
9927
9928
      public:
9929
        MDIAsAttribute(const std::string &name, const std::string &value)
9930
0
            : GDALAbstractMDArray(std::string(), name),
9931
0
              GDALAttribute(std::string(), name), m_osValue(value)
9932
0
        {
9933
0
        }
9934
9935
        const std::vector<std::shared_ptr<GDALDimension>> &
9936
        GetDimensions() const override;
9937
9938
        const GDALExtendedDataType &GetDataType() const override
9939
0
        {
9940
0
            return m_dt;
9941
0
        }
9942
9943
        bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
9944
                   const GPtrDiff_t *,
9945
                   const GDALExtendedDataType &bufferDataType,
9946
                   void *pDstBuffer) const override
9947
0
        {
9948
0
            const char *pszStr = m_osValue.c_str();
9949
0
            GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
9950
0
                                            bufferDataType);
9951
0
            return true;
9952
0
        }
9953
    };
9954
9955
    std::vector<std::shared_ptr<GDALAttribute>>
9956
    GetAttributes(CSLConstList) const override
9957
0
    {
9958
0
        std::vector<std::shared_ptr<GDALAttribute>> res;
9959
0
        auto papszMD = m_poBand->GetMetadata();
9960
0
        for (auto iter = papszMD; iter && iter[0]; ++iter)
9961
0
        {
9962
0
            char *pszKey = nullptr;
9963
0
            const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9964
0
            if (pszKey && pszValue)
9965
0
            {
9966
0
                res.emplace_back(
9967
0
                    std::make_shared<MDIAsAttribute>(pszKey, pszValue));
9968
0
            }
9969
0
            CPLFree(pszKey);
9970
0
        }
9971
0
        return res;
9972
0
    }
9973
};
9974
9975
bool GDALMDArrayFromRasterBand::IRead(
9976
    const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
9977
    const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
9978
    void *pDstBuffer) const
9979
0
{
9980
0
    return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9981
0
                     bufferDataType, pDstBuffer);
9982
0
}
9983
9984
const std::vector<std::shared_ptr<GDALDimension>> &
9985
GDALMDArrayFromRasterBand::MDIAsAttribute::GetDimensions() const
9986
0
{
9987
0
    return m_dims;
9988
0
}
9989
9990
/************************************************************************/
9991
/*                            ReadWrite()                               */
9992
/************************************************************************/
9993
9994
bool GDALMDArrayFromRasterBand::ReadWrite(
9995
    GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
9996
    const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9997
    const GDALExtendedDataType &bufferDataType, void *pBuffer) const
9998
0
{
9999
0
    constexpr size_t iDimX = 1;
10000
0
    constexpr size_t iDimY = 0;
10001
0
    return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
10002
0
                                  arrayStartIdx, count, arrayStep, bufferStride,
10003
0
                                  bufferDataType, pBuffer);
10004
0
}
10005
10006
/************************************************************************/
10007
/*                       GDALMDRasterIOFromBand()                       */
10008
/************************************************************************/
10009
10010
bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
10011
                            size_t iDimX, size_t iDimY,
10012
                            const GUInt64 *arrayStartIdx, const size_t *count,
10013
                            const GInt64 *arrayStep,
10014
                            const GPtrDiff_t *bufferStride,
10015
                            const GDALExtendedDataType &bufferDataType,
10016
                            void *pBuffer)
10017
0
{
10018
0
    const auto eDT(bufferDataType.GetNumericDataType());
10019
0
    const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
10020
0
    const int nX =
10021
0
        arrayStep[iDimX] > 0
10022
0
            ? static_cast<int>(arrayStartIdx[iDimX])
10023
0
            : static_cast<int>(arrayStartIdx[iDimX] -
10024
0
                               (count[iDimX] - 1) * -arrayStep[iDimX]);
10025
0
    const int nY =
10026
0
        arrayStep[iDimY] > 0
10027
0
            ? static_cast<int>(arrayStartIdx[iDimY])
10028
0
            : static_cast<int>(arrayStartIdx[iDimY] -
10029
0
                               (count[iDimY] - 1) * -arrayStep[iDimY]);
10030
0
    const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
10031
0
    const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
10032
0
    GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
10033
0
    int nStrideXSign = 1;
10034
0
    if (arrayStep[iDimX] < 0)
10035
0
    {
10036
0
        pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
10037
0
        nStrideXSign = -1;
10038
0
    }
10039
0
    int nStrideYSign = 1;
10040
0
    if (arrayStep[iDimY] < 0)
10041
0
    {
10042
0
        pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
10043
0
        nStrideYSign = -1;
10044
0
    }
10045
10046
0
    return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
10047
0
                            static_cast<int>(count[iDimX]),
10048
0
                            static_cast<int>(count[iDimY]), eDT,
10049
0
                            static_cast<GSpacing>(
10050
0
                                nStrideXSign * bufferStride[iDimX] * nDTSize),
10051
0
                            static_cast<GSpacing>(
10052
0
                                nStrideYSign * bufferStride[iDimY] * nDTSize),
10053
0
                            nullptr) == CE_None;
10054
0
}
10055
10056
/************************************************************************/
10057
/*                            AsMDArray()                               */
10058
/************************************************************************/
10059
10060
/** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10061
 *
10062
 * The band must be linked to a GDALDataset. If this dataset is not already
10063
 * marked as shared, it will be, so that the returned array holds a reference
10064
 * to it.
10065
 *
10066
 * If the dataset has a geotransform attached, the X and Y dimensions of the
10067
 * returned array will have an associated indexing variable.
10068
 *
10069
 * This is the same as the C function GDALRasterBandAsMDArray().
10070
 *
10071
 * The "reverse" method is GDALMDArray::AsClassicDataset().
10072
 *
10073
 * @return a new array, or nullptr.
10074
 *
10075
 * @since GDAL 3.1
10076
 */
10077
std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
10078
0
{
10079
0
    if (!poDS)
10080
0
    {
10081
0
        CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
10082
0
        return nullptr;
10083
0
    }
10084
0
    if (!poDS->GetShared())
10085
0
    {
10086
0
        poDS->MarkAsShared();
10087
0
    }
10088
0
    return GDALMDArrayFromRasterBand::Create(
10089
0
        poDS, const_cast<GDALRasterBand *>(this));
10090
0
}
10091
10092
/************************************************************************/
10093
/*                             InterpolateAtPoint()                     */
10094
/************************************************************************/
10095
10096
/**
10097
 * \brief Interpolates the value between pixels using a resampling algorithm,
10098
 * taking pixel/line coordinates as input.
10099
 *
10100
 * @param dfPixel pixel coordinate as a double, where interpolation should be done.
10101
 * @param dfLine line coordinate as a double, where interpolation should be done.
10102
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10103
 * @param pdfRealValue pointer to real part of interpolated value
10104
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10105
 *
10106
 * @return CE_None on success, or an error code on failure.
10107
 * @since GDAL 3.10
10108
 */
10109
10110
CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
10111
                                          GDALRIOResampleAlg eInterpolation,
10112
                                          double *pdfRealValue,
10113
                                          double *pdfImagValue) const
10114
0
{
10115
0
    if (eInterpolation != GRIORA_NearestNeighbour &&
10116
0
        eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
10117
0
        eInterpolation != GRIORA_CubicSpline)
10118
0
    {
10119
0
        CPLError(CE_Failure, CPLE_AppDefined,
10120
0
                 "Only nearest, bilinear, cubic and cubicspline interpolation "
10121
0
                 "methods "
10122
0
                 "allowed");
10123
10124
0
        return CE_Failure;
10125
0
    }
10126
10127
0
    GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
10128
0
    if (!m_poPointsCache)
10129
0
        m_poPointsCache = new GDALDoublePointsCache();
10130
10131
0
    const bool res =
10132
0
        GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
10133
0
                               dfPixel, dfLine, pdfRealValue, pdfImagValue);
10134
10135
0
    return res ? CE_None : CE_Failure;
10136
0
}
10137
10138
/************************************************************************/
10139
/*                        GDALRasterInterpolateAtPoint()                */
10140
/************************************************************************/
10141
10142
/**
10143
 * \brief Interpolates the value between pixels using
10144
 * a resampling algorithm
10145
 *
10146
 * @see GDALRasterBand::InterpolateAtPoint()
10147
 * @since GDAL 3.10
10148
 */
10149
10150
CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10151
                                    double dfLine,
10152
                                    GDALRIOResampleAlg eInterpolation,
10153
                                    double *pdfRealValue, double *pdfImagValue)
10154
0
{
10155
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10156
10157
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10158
0
    return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10159
0
                                      pdfRealValue, pdfImagValue);
10160
0
}
10161
10162
/************************************************************************/
10163
/*                    InterpolateAtGeolocation()                        */
10164
/************************************************************************/
10165
10166
/**
10167
 * \brief Interpolates the value between pixels using a resampling algorithm,
10168
 * taking georeferenced coordinates as input.
10169
 *
10170
 * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
10171
 * must be in the "natural" SRS of the dataset, that is the one returned by
10172
 * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
10173
 * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
10174
 * array (generally WGS 84) if there is a geolocation array.
10175
 * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10176
 * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10177
 * be a easting, and dfGeolocY a northing.
10178
 *
10179
 * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10180
 * expressed in that CRS, and that tuple must be conformant with the
10181
 * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10182
 * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10183
 * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10184
 * before calling this method, and in that case, dfGeolocX must be a longitude
10185
 * or an easting value, and dfGeolocX a latitude or a northing value.
10186
 *
10187
 * The GDALDataset::GeolocationToPixelLine() will be used to transform from
10188
 * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
10189
 * it for details on how that transformation is done.
10190
 *
10191
 * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
10192
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10193
 * where interpolation should be done.
10194
 * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
10195
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10196
 * where interpolation should be done.
10197
 * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
10198
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10199
 * @param pdfRealValue pointer to real part of interpolated value
10200
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10201
 * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
10202
 *
10203
 * @return CE_None on success, or an error code on failure.
10204
 * @since GDAL 3.11
10205
 */
10206
10207
CPLErr GDALRasterBand::InterpolateAtGeolocation(
10208
    double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
10209
    GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
10210
    double *pdfImagValue, CSLConstList papszTransformerOptions) const
10211
0
{
10212
0
    double dfPixel;
10213
0
    double dfLine;
10214
0
    if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
10215
0
                                     &dfLine,
10216
0
                                     papszTransformerOptions) != CE_None)
10217
0
    {
10218
0
        return CE_Failure;
10219
0
    }
10220
0
    return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
10221
0
                              pdfImagValue);
10222
0
}
10223
10224
/************************************************************************/
10225
/*                  GDALRasterInterpolateAtGeolocation()                */
10226
/************************************************************************/
10227
10228
/**
10229
 * \brief Interpolates the value between pixels using a resampling algorithm,
10230
 * taking georeferenced coordinates as input.
10231
 *
10232
 * @see GDALRasterBand::InterpolateAtGeolocation()
10233
 * @since GDAL 3.11
10234
 */
10235
10236
CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
10237
                                          double dfGeolocX, double dfGeolocY,
10238
                                          OGRSpatialReferenceH hSRS,
10239
                                          GDALRIOResampleAlg eInterpolation,
10240
                                          double *pdfRealValue,
10241
                                          double *pdfImagValue,
10242
                                          CSLConstList papszTransformerOptions)
10243
0
{
10244
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
10245
10246
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10247
0
    return poBand->InterpolateAtGeolocation(
10248
0
        dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
10249
0
        eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
10250
0
}
10251
10252
/************************************************************************/
10253
/*                    GDALRasterBand::SplitRasterIO()                   */
10254
/************************************************************************/
10255
10256
//! @cond Doxygen_Suppress
10257
10258
/** Implements IRasterIO() by dividing the request in 2.
10259
 *
10260
 * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
10261
 *
10262
 * Return CE_Warning if the split could not be done, CE_None in case of
10263
 * success and CE_Failure in case of error.
10264
 *
10265
 * @since 3.12
10266
 */
10267
CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
10268
                                     [[maybe_unused]] int nXSize,
10269
                                     [[maybe_unused]] int nYSize, void *pData,
10270
                                     int nBufXSize, int nBufYSize,
10271
                                     GDALDataType eBufType,
10272
                                     GSpacing nPixelSpace, GSpacing nLineSpace,
10273
                                     GDALRasterIOExtraArg *psExtraArg)
10274
0
{
10275
0
    CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
10276
10277
0
    GByte *pabyData = static_cast<GByte *>(pData);
10278
0
    if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
10279
0
    {
10280
0
        GDALRasterIOExtraArg sArg;
10281
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
10282
0
        const int nHalfHeight = nBufYSize / 2;
10283
10284
0
        sArg.pfnProgress = GDALScaledProgress;
10285
0
        sArg.pProgressData = GDALCreateScaledProgress(
10286
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10287
0
        if (sArg.pProgressData == nullptr)
10288
0
            sArg.pfnProgress = nullptr;
10289
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
10290
0
                                pabyData, nBufXSize, nHalfHeight, eBufType,
10291
0
                                nPixelSpace, nLineSpace, &sArg);
10292
0
        GDALDestroyScaledProgress(sArg.pProgressData);
10293
10294
0
        if (eErr == CE_None)
10295
0
        {
10296
0
            sArg.pfnProgress = GDALScaledProgress;
10297
0
            sArg.pProgressData = GDALCreateScaledProgress(
10298
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10299
0
            if (sArg.pProgressData == nullptr)
10300
0
                sArg.pfnProgress = nullptr;
10301
0
            eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
10302
0
                             nBufYSize - nHalfHeight,
10303
0
                             pabyData + nHalfHeight * nLineSpace, nBufXSize,
10304
0
                             nBufYSize - nHalfHeight, eBufType, nPixelSpace,
10305
0
                             nLineSpace, &sArg);
10306
0
            GDALDestroyScaledProgress(sArg.pProgressData);
10307
0
        }
10308
0
        return eErr;
10309
0
    }
10310
0
    else if (nBufXSize >= 2)
10311
0
    {
10312
0
        GDALRasterIOExtraArg sArg;
10313
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
10314
0
        const int nHalfWidth = nBufXSize / 2;
10315
10316
0
        sArg.pfnProgress = GDALScaledProgress;
10317
0
        sArg.pProgressData = GDALCreateScaledProgress(
10318
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10319
0
        if (sArg.pProgressData == nullptr)
10320
0
            sArg.pfnProgress = nullptr;
10321
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
10322
0
                                pabyData, nHalfWidth, nBufYSize, eBufType,
10323
0
                                nPixelSpace, nLineSpace, &sArg);
10324
0
        GDALDestroyScaledProgress(sArg.pProgressData);
10325
10326
0
        if (eErr == CE_None)
10327
0
        {
10328
0
            sArg.pfnProgress = GDALScaledProgress;
10329
0
            sArg.pProgressData = GDALCreateScaledProgress(
10330
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10331
0
            if (sArg.pProgressData == nullptr)
10332
0
                sArg.pfnProgress = nullptr;
10333
0
            eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
10334
0
                             nBufXSize - nHalfWidth, nBufYSize,
10335
0
                             pabyData + nHalfWidth * nPixelSpace,
10336
0
                             nBufXSize - nHalfWidth, nBufYSize, eBufType,
10337
0
                             nPixelSpace, nLineSpace, &sArg);
10338
0
            GDALDestroyScaledProgress(sArg.pProgressData);
10339
0
        }
10340
0
        return eErr;
10341
0
    }
10342
10343
0
    return CE_Warning;
10344
0
}
10345
10346
//! @endcond
10347
10348
/************************************************************************/
10349
/*                         ThrowIfNotSameDimensions()                   */
10350
/************************************************************************/
10351
10352
//! @cond Doxygen_Suppress
10353
/* static */
10354
void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
10355
                                              const GDALRasterBand &second)
10356
0
{
10357
0
    if (first.GetXSize() != second.GetXSize() ||
10358
0
        first.GetYSize() != second.GetYSize())
10359
0
    {
10360
0
        throw std::runtime_error("Bands do not have the same dimensions");
10361
0
    }
10362
0
}
10363
10364
//! @endcond
10365
10366
/************************************************************************/
10367
/*                          GDALRasterBandUnaryOp()                     */
10368
/************************************************************************/
10369
10370
/** Apply a unary operation on this band.
10371
 *
10372
 * The resulting band is lazy evaluated. A reference is taken on the input
10373
 * dataset.
10374
 *
10375
 * @since 3.12
10376
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10377
 */
10378
GDALComputedRasterBandH
10379
GDALRasterBandUnaryOp(GDALRasterBandH hBand,
10380
                      GDALRasterAlgebraUnaryOperation eOp)
10381
0
{
10382
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
10383
0
    GDALComputedRasterBand::Operation cppOp{};
10384
0
    switch (eOp)
10385
0
    {
10386
0
        case GRAUO_LOGICAL_NOT:
10387
0
            return new GDALComputedRasterBand(
10388
0
                GDALComputedRasterBand::Operation::OP_NE,
10389
0
                *(GDALRasterBand::FromHandle(hBand)), true);
10390
0
        case GRAUO_ABS:
10391
0
            cppOp = GDALComputedRasterBand::Operation::OP_ABS;
10392
0
            break;
10393
0
        case GRAUO_SQRT:
10394
0
            cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
10395
0
            break;
10396
0
        case GRAUO_LOG:
10397
0
#ifndef HAVE_MUPARSER
10398
0
            CPLError(
10399
0
                CE_Failure, CPLE_NotSupported,
10400
0
                "log(band) not available on a GDAL build without muparser");
10401
0
            return nullptr;
10402
#else
10403
            cppOp = GDALComputedRasterBand::Operation::OP_LOG;
10404
            break;
10405
#endif
10406
0
        case GRAUO_LOG10:
10407
0
            cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
10408
0
            break;
10409
0
    }
10410
0
    return new GDALComputedRasterBand(cppOp,
10411
0
                                      *(GDALRasterBand::FromHandle(hBand)));
10412
0
}
10413
10414
/************************************************************************/
10415
/*            ConvertGDALRasterAlgebraBinaryOperationToCpp()            */
10416
/************************************************************************/
10417
10418
static GDALComputedRasterBand::Operation
10419
ConvertGDALRasterAlgebraBinaryOperationToCpp(
10420
    GDALRasterAlgebraBinaryOperation eOp)
10421
0
{
10422
0
    switch (eOp)
10423
0
    {
10424
0
        case GRABO_ADD:
10425
0
            return GDALComputedRasterBand::Operation::OP_ADD;
10426
0
        case GRABO_SUB:
10427
0
            return GDALComputedRasterBand::Operation::OP_SUBTRACT;
10428
0
        case GRABO_MUL:
10429
0
            return GDALComputedRasterBand::Operation::OP_MULTIPLY;
10430
0
        case GRABO_DIV:
10431
0
            return GDALComputedRasterBand::Operation::OP_DIVIDE;
10432
0
        case GRABO_GT:
10433
0
            return GDALComputedRasterBand::Operation::OP_GT;
10434
0
        case GRABO_GE:
10435
0
            return GDALComputedRasterBand::Operation::OP_GE;
10436
0
        case GRABO_LT:
10437
0
            return GDALComputedRasterBand::Operation::OP_LT;
10438
0
        case GRABO_LE:
10439
0
            return GDALComputedRasterBand::Operation::OP_LE;
10440
0
        case GRABO_EQ:
10441
0
            return GDALComputedRasterBand::Operation::OP_EQ;
10442
0
        case GRABO_NE:
10443
0
            break;
10444
0
        case GRABO_LOGICAL_AND:
10445
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
10446
0
        case GRABO_LOGICAL_OR:
10447
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
10448
0
        case GRABO_POW:
10449
0
            return GDALComputedRasterBand::Operation::OP_POW;
10450
0
    }
10451
0
    return GDALComputedRasterBand::Operation::OP_NE;
10452
0
}
10453
10454
/************************************************************************/
10455
/*                     GDALRasterBandBinaryOpBand()                     */
10456
/************************************************************************/
10457
10458
/** Apply a binary operation on this band with another one.
10459
 *
10460
 * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
10461
 * "hBand1 - hBand2".
10462
 *
10463
 * The resulting band is lazy evaluated. A reference is taken on both input
10464
 * datasets.
10465
 *
10466
 * @since 3.12
10467
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10468
 */
10469
GDALComputedRasterBandH
10470
GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
10471
                           GDALRasterAlgebraBinaryOperation eOp,
10472
                           GDALRasterBandH hOtherBand)
10473
0
{
10474
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
10475
0
    VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
10476
0
#ifndef HAVE_MUPARSER
10477
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10478
0
    {
10479
0
        CPLError(
10480
0
            CE_Failure, CPLE_NotSupported,
10481
0
            "Band comparison operators not available on a GDAL build without "
10482
0
            "muparser");
10483
0
        return nullptr;
10484
0
    }
10485
0
    else if (eOp == GRABO_POW)
10486
0
    {
10487
0
        CPLError(
10488
0
            CE_Failure, CPLE_NotSupported,
10489
0
            "pow(band, band) not available on a GDAL build without muparser");
10490
0
        return nullptr;
10491
0
    }
10492
0
#endif
10493
0
    auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
10494
0
    auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
10495
0
    try
10496
0
    {
10497
0
        GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
10498
0
    }
10499
0
    catch (const std::exception &e)
10500
0
    {
10501
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
10502
0
        return nullptr;
10503
0
    }
10504
0
    return new GDALComputedRasterBand(
10505
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
10506
0
        secondBand);
10507
0
}
10508
10509
/************************************************************************/
10510
/*                     GDALRasterBandBinaryOpDouble()                   */
10511
/************************************************************************/
10512
10513
/** Apply a binary operation on this band with a constant
10514
 *
10515
 * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
10516
 * "hBand - constant".
10517
 *
10518
 * The resulting band is lazy evaluated. A reference is taken on the input
10519
 * dataset.
10520
 *
10521
 * @since 3.12
10522
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10523
 */
10524
GDALComputedRasterBandH
10525
GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
10526
                             GDALRasterAlgebraBinaryOperation eOp,
10527
                             double constant)
10528
0
{
10529
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
10530
0
#ifndef HAVE_MUPARSER
10531
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10532
0
    {
10533
0
        CPLError(
10534
0
            CE_Failure, CPLE_NotSupported,
10535
0
            "Band comparison operators not available on a GDAL build without "
10536
0
            "muparser");
10537
0
        return nullptr;
10538
0
    }
10539
0
#endif
10540
0
    return new GDALComputedRasterBand(
10541
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
10542
0
        *(GDALRasterBand::FromHandle(hBand)), constant);
10543
0
}
10544
10545
/************************************************************************/
10546
/*                   GDALRasterBandBinaryOpDoubleToBand()               */
10547
/************************************************************************/
10548
10549
/** Apply a binary operation on the constant with this band
10550
 *
10551
 * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
10552
 * "constant - hBand".
10553
 *
10554
 * The resulting band is lazy evaluated. A reference is taken on the input
10555
 * dataset.
10556
 *
10557
 * @since 3.12
10558
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10559
 */
10560
GDALComputedRasterBandH
10561
GDALRasterBandBinaryOpDoubleToBand(double constant,
10562
                                   GDALRasterAlgebraBinaryOperation eOp,
10563
                                   GDALRasterBandH hBand)
10564
0
{
10565
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
10566
0
#ifndef HAVE_MUPARSER
10567
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10568
0
    {
10569
0
        CPLError(
10570
0
            CE_Failure, CPLE_NotSupported,
10571
0
            "Band comparison operators not available on a GDAL build without "
10572
0
            "muparser");
10573
0
        return nullptr;
10574
0
    }
10575
0
#endif
10576
0
    switch (eOp)
10577
0
    {
10578
0
        case GRABO_ADD:
10579
0
        case GRABO_MUL:
10580
0
        {
10581
0
            return new GDALComputedRasterBand(
10582
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
10583
0
                *(GDALRasterBand::FromHandle(hBand)), constant);
10584
0
        }
10585
10586
0
        case GRABO_DIV:
10587
0
        case GRABO_GT:
10588
0
        case GRABO_GE:
10589
0
        case GRABO_LT:
10590
0
        case GRABO_LE:
10591
0
        case GRABO_EQ:
10592
0
        case GRABO_NE:
10593
0
        case GRABO_LOGICAL_AND:
10594
0
        case GRABO_LOGICAL_OR:
10595
0
        case GRABO_POW:
10596
0
        {
10597
0
            return new GDALComputedRasterBand(
10598
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
10599
0
                *(GDALRasterBand::FromHandle(hBand)));
10600
0
        }
10601
10602
0
        case GRABO_SUB:
10603
0
        {
10604
0
            break;
10605
0
        }
10606
0
    }
10607
10608
0
    return new GDALComputedRasterBand(
10609
0
        GDALComputedRasterBand::Operation::OP_ADD,
10610
0
        GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
10611
0
                               *(GDALRasterBand::FromHandle(hBand)), -1.0),
10612
0
        constant);
10613
0
}
10614
10615
/************************************************************************/
10616
/*                           operator+()                                */
10617
/************************************************************************/
10618
10619
/** Add this band with another one.
10620
 *
10621
 * The resulting band is lazy evaluated. A reference is taken on both input
10622
 * datasets.
10623
 *
10624
 * @since 3.12
10625
 * @throw std::runtime_error if both bands do not have the same dimensions.
10626
 */
10627
GDALComputedRasterBand
10628
GDALRasterBand::operator+(const GDALRasterBand &other) const
10629
0
{
10630
0
    ThrowIfNotSameDimensions(*this, other);
10631
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
10632
0
                                  *this, other);
10633
0
}
10634
10635
/************************************************************************/
10636
/*                           operator+()                                */
10637
/************************************************************************/
10638
10639
/** Add this band with a constant.
10640
 *
10641
 * The resulting band is lazy evaluated. A reference is taken on the input
10642
 * dataset.
10643
 *
10644
 * @since 3.12
10645
 */
10646
GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
10647
0
{
10648
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
10649
0
                                  *this, constant);
10650
0
}
10651
10652
/************************************************************************/
10653
/*                           operator+()                                */
10654
/************************************************************************/
10655
10656
/** Add a band with a constant.
10657
 *
10658
 * The resulting band is lazy evaluated. A reference is taken on the input
10659
 * dataset.
10660
 *
10661
 * @since 3.12
10662
 */
10663
GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
10664
0
{
10665
0
    return other + constant;
10666
0
}
10667
10668
/************************************************************************/
10669
/*                           operator-()                                */
10670
/************************************************************************/
10671
10672
/** Return a band whose value is the opposite value of the band for each
10673
 * pixel.
10674
 *
10675
 * The resulting band is lazy evaluated. A reference is taken on the input
10676
 * dataset.
10677
 *
10678
 * @since 3.12
10679
 */
10680
GDALComputedRasterBand GDALRasterBand::operator-() const
10681
0
{
10682
0
    return 0 - *this;
10683
0
}
10684
10685
/************************************************************************/
10686
/*                           operator-()                                */
10687
/************************************************************************/
10688
10689
/** Subtract this band with another one.
10690
 *
10691
 * The resulting band is lazy evaluated. A reference is taken on both input
10692
 * datasets.
10693
 *
10694
 * @since 3.12
10695
 * @throw std::runtime_error if both bands do not have the same dimensions.
10696
 */
10697
GDALComputedRasterBand
10698
GDALRasterBand::operator-(const GDALRasterBand &other) const
10699
0
{
10700
0
    ThrowIfNotSameDimensions(*this, other);
10701
0
    return GDALComputedRasterBand(
10702
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
10703
0
}
10704
10705
/************************************************************************/
10706
/*                           operator-()                                */
10707
/************************************************************************/
10708
10709
/** Subtract this band with a constant.
10710
 *
10711
 * The resulting band is lazy evaluated. A reference is taken on the input
10712
 * dataset.
10713
 *
10714
 * @since 3.12
10715
 */
10716
GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
10717
0
{
10718
0
    return GDALComputedRasterBand(
10719
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
10720
0
}
10721
10722
/************************************************************************/
10723
/*                           operator-()                                */
10724
/************************************************************************/
10725
10726
/** Subtract a constant with a band.
10727
 *
10728
 * The resulting band is lazy evaluated. A reference is taken on the input
10729
 * dataset.
10730
 *
10731
 * @since 3.12
10732
 */
10733
GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
10734
0
{
10735
0
    return other * (-1.0) + constant;
10736
0
}
10737
10738
/************************************************************************/
10739
/*                           operator*()                                */
10740
/************************************************************************/
10741
10742
/** Multiply this band with another one.
10743
 *
10744
 * The resulting band is lazy evaluated. A reference is taken on both input
10745
 * datasets.
10746
 *
10747
 * @since 3.12
10748
 * @throw std::runtime_error if both bands do not have the same dimensions.
10749
 */
10750
GDALComputedRasterBand
10751
GDALRasterBand::operator*(const GDALRasterBand &other) const
10752
0
{
10753
0
    ThrowIfNotSameDimensions(*this, other);
10754
0
    return GDALComputedRasterBand(
10755
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
10756
0
}
10757
10758
/************************************************************************/
10759
/*                           operator*()                                */
10760
/************************************************************************/
10761
10762
/** Multiply this band by a constant.
10763
 *
10764
 * The resulting band is lazy evaluated. A reference is taken on the input
10765
 * dataset.
10766
 *
10767
 * @since 3.12
10768
 */
10769
GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
10770
0
{
10771
0
    return GDALComputedRasterBand(
10772
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
10773
0
}
10774
10775
/************************************************************************/
10776
/*                           operator*()                                */
10777
/************************************************************************/
10778
10779
/** Multiply a band with a constant.
10780
 *
10781
 * The resulting band is lazy evaluated. A reference is taken on the input
10782
 * dataset.
10783
 *
10784
 * @since 3.12
10785
 */
10786
GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
10787
0
{
10788
0
    return other * constant;
10789
0
}
10790
10791
/************************************************************************/
10792
/*                           operator/()                                */
10793
/************************************************************************/
10794
10795
/** Divide this band with another one.
10796
 *
10797
 * The resulting band is lazy evaluated. A reference is taken on both input
10798
 * datasets.
10799
 *
10800
 * @since 3.12
10801
 * @throw std::runtime_error if both bands do not have the same dimensions.
10802
 */
10803
GDALComputedRasterBand
10804
GDALRasterBand::operator/(const GDALRasterBand &other) const
10805
0
{
10806
0
    ThrowIfNotSameDimensions(*this, other);
10807
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10808
0
                                  *this, other);
10809
0
}
10810
10811
/************************************************************************/
10812
/*                           operator/()                                */
10813
/************************************************************************/
10814
10815
/** Divide this band by a constant.
10816
 *
10817
 * The resulting band is lazy evaluated. A reference is taken on the input
10818
 * dataset.
10819
 *
10820
 * @since 3.12
10821
 */
10822
GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
10823
0
{
10824
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10825
0
                                  *this, constant);
10826
0
}
10827
10828
/************************************************************************/
10829
/*                           operator/()                                */
10830
/************************************************************************/
10831
10832
/** Divide a constant by a band.
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 operator/(double constant, const GDALRasterBand &other)
10840
0
{
10841
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10842
0
                                  constant, other);
10843
0
}
10844
10845
/************************************************************************/
10846
/*                          ThrowIfNotMuparser()                        */
10847
/************************************************************************/
10848
10849
#ifndef HAVE_MUPARSER
10850
static GDALComputedRasterBand ThrowIfNotMuparser()
10851
0
{
10852
0
    throw std::runtime_error("Operator not available on a "
10853
0
                             "GDAL build without muparser");
10854
0
}
10855
#endif
10856
10857
/************************************************************************/
10858
/*                           operator>()                                */
10859
/************************************************************************/
10860
10861
/** Return a band whose value is 1 if the pixel value of the left operand
10862
 * is greater than the pixel value of the right operand.
10863
 *
10864
 * The resulting band is lazy evaluated. A reference is taken on the input
10865
 * dataset.
10866
 *
10867
 * @since 3.12
10868
 */
10869
GDALComputedRasterBand
10870
GDALRasterBand::operator>(const GDALRasterBand &other) const
10871
0
{
10872
0
#ifndef HAVE_MUPARSER
10873
0
    (void)other;
10874
0
    return ThrowIfNotMuparser();
10875
#else
10876
    ThrowIfNotSameDimensions(*this, other);
10877
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10878
                                  *this, other);
10879
#endif
10880
0
}
10881
10882
/************************************************************************/
10883
/*                           operator>()                                */
10884
/************************************************************************/
10885
10886
/** Return a band whose value is 1 if the pixel value of the left operand
10887
 * is greater than the constant.
10888
 *
10889
 * The resulting band is lazy evaluated. A reference is taken on the input
10890
 * dataset.
10891
 *
10892
 * @since 3.12
10893
 */
10894
GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
10895
0
{
10896
0
#ifndef HAVE_MUPARSER
10897
0
    (void)constant;
10898
0
    return ThrowIfNotMuparser();
10899
#else
10900
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10901
                                  *this, constant);
10902
#endif
10903
0
}
10904
10905
/************************************************************************/
10906
/*                           operator>()                                */
10907
/************************************************************************/
10908
10909
/** Return a band whose value is 1 if the constant is greater than the pixel
10910
 * value of the right operand.
10911
 *
10912
 * The resulting band is lazy evaluated. A reference is taken on the input
10913
 * dataset.
10914
 *
10915
 * @since 3.12
10916
 */
10917
GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
10918
0
{
10919
0
#ifndef HAVE_MUPARSER
10920
0
    (void)constant;
10921
0
    (void)other;
10922
0
    return ThrowIfNotMuparser();
10923
#else
10924
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10925
                                  constant, other);
10926
#endif
10927
0
}
10928
10929
/************************************************************************/
10930
/*                           operator>=()                               */
10931
/************************************************************************/
10932
10933
/** Return a band whose value is 1 if the pixel value of the left operand
10934
 * is greater or equal to the pixel value of the right operand.
10935
 *
10936
 * The resulting band is lazy evaluated. A reference is taken on the input
10937
 * dataset.
10938
 *
10939
 * @since 3.12
10940
 */
10941
GDALComputedRasterBand
10942
GDALRasterBand::operator>=(const GDALRasterBand &other) const
10943
0
{
10944
0
#ifndef HAVE_MUPARSER
10945
0
    (void)other;
10946
0
    return ThrowIfNotMuparser();
10947
#else
10948
    ThrowIfNotSameDimensions(*this, other);
10949
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10950
                                  *this, other);
10951
#endif
10952
0
}
10953
10954
/************************************************************************/
10955
/*                           operator>=()                               */
10956
/************************************************************************/
10957
10958
/** Return a band whose value is 1 if the pixel value of the left operand
10959
 * is greater or equal to the constant.
10960
 *
10961
 * The resulting band is lazy evaluated. A reference is taken on the input
10962
 * dataset.
10963
 *
10964
 * @since 3.12
10965
 */
10966
GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
10967
0
{
10968
0
#ifndef HAVE_MUPARSER
10969
0
    (void)constant;
10970
0
    return ThrowIfNotMuparser();
10971
#else
10972
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10973
                                  *this, constant);
10974
#endif
10975
0
}
10976
10977
/************************************************************************/
10978
/*                           operator>=()                               */
10979
/************************************************************************/
10980
10981
/** Return a band whose value is 1 if the constant is greater or equal to
10982
 * the pixel value of the right operand.
10983
 *
10984
 * The resulting band is lazy evaluated. A reference is taken on the input
10985
 * dataset.
10986
 *
10987
 * @since 3.12
10988
 */
10989
GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
10990
0
{
10991
0
#ifndef HAVE_MUPARSER
10992
0
    (void)constant;
10993
0
    (void)other;
10994
0
    return ThrowIfNotMuparser();
10995
#else
10996
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10997
                                  constant, other);
10998
#endif
10999
0
}
11000
11001
/************************************************************************/
11002
/*                           operator<()                                */
11003
/************************************************************************/
11004
11005
/** Return a band whose value is 1 if the pixel value of the left operand
11006
 * is lesser than the pixel value of the right operand.
11007
 *
11008
 * The resulting band is lazy evaluated. A reference is taken on the input
11009
 * dataset.
11010
 *
11011
 * @since 3.12
11012
 */
11013
GDALComputedRasterBand
11014
GDALRasterBand::operator<(const GDALRasterBand &other) const
11015
0
{
11016
0
#ifndef HAVE_MUPARSER
11017
0
    (void)other;
11018
0
    return ThrowIfNotMuparser();
11019
#else
11020
    ThrowIfNotSameDimensions(*this, other);
11021
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11022
                                  *this, other);
11023
#endif
11024
0
}
11025
11026
/************************************************************************/
11027
/*                           operator<()                                */
11028
/************************************************************************/
11029
11030
/** Return a band whose value is 1 if the pixel value of the left operand
11031
 * is lesser than the constant.
11032
 *
11033
 * The resulting band is lazy evaluated. A reference is taken on the input
11034
 * dataset.
11035
 *
11036
 * @since 3.12
11037
 */
11038
GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
11039
0
{
11040
0
#ifndef HAVE_MUPARSER
11041
0
    (void)constant;
11042
0
    return ThrowIfNotMuparser();
11043
#else
11044
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11045
                                  *this, constant);
11046
#endif
11047
0
}
11048
11049
/************************************************************************/
11050
/*                           operator<()                                */
11051
/************************************************************************/
11052
11053
/** Return a band whose value is 1 if the constant is lesser than the pixel
11054
 * value of the right operand.
11055
 *
11056
 * The resulting band is lazy evaluated. A reference is taken on the input
11057
 * dataset.
11058
 *
11059
 * @since 3.12
11060
 */
11061
GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
11062
0
{
11063
0
#ifndef HAVE_MUPARSER
11064
0
    (void)constant;
11065
0
    (void)other;
11066
0
    return ThrowIfNotMuparser();
11067
#else
11068
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11069
                                  constant, other);
11070
#endif
11071
0
}
11072
11073
/************************************************************************/
11074
/*                           operator<=()                               */
11075
/************************************************************************/
11076
11077
/** Return a band whose value is 1 if the pixel value of the left operand
11078
 * is lesser or equal to the pixel value of the right operand.
11079
 *
11080
 * The resulting band is lazy evaluated. A reference is taken on the input
11081
 * dataset.
11082
 *
11083
 * @since 3.12
11084
 */
11085
GDALComputedRasterBand
11086
GDALRasterBand::operator<=(const GDALRasterBand &other) const
11087
0
{
11088
0
#ifndef HAVE_MUPARSER
11089
0
    (void)other;
11090
0
    return ThrowIfNotMuparser();
11091
#else
11092
    ThrowIfNotSameDimensions(*this, other);
11093
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11094
                                  *this, other);
11095
#endif
11096
0
}
11097
11098
/************************************************************************/
11099
/*                           operator<=()                               */
11100
/************************************************************************/
11101
11102
/** Return a band whose value is 1 if the pixel value of the left operand
11103
 * is lesser or equal to the constant.
11104
 *
11105
 * The resulting band is lazy evaluated. A reference is taken on the input
11106
 * dataset.
11107
 *
11108
 * @since 3.12
11109
 */
11110
GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
11111
0
{
11112
0
#ifndef HAVE_MUPARSER
11113
0
    (void)constant;
11114
0
    return ThrowIfNotMuparser();
11115
#else
11116
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11117
                                  *this, constant);
11118
#endif
11119
0
}
11120
11121
/************************************************************************/
11122
/*                           operator<=()                               */
11123
/************************************************************************/
11124
11125
/** Return a band whose value is 1 if the constant is lesser or equal to
11126
 * the pixel value of the right operand.
11127
 *
11128
 * The resulting band is lazy evaluated. A reference is taken on the input
11129
 * dataset.
11130
 *
11131
 * @since 3.12
11132
 */
11133
GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
11134
0
{
11135
0
#ifndef HAVE_MUPARSER
11136
0
    (void)constant;
11137
0
    (void)other;
11138
0
    return ThrowIfNotMuparser();
11139
#else
11140
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11141
                                  constant, other);
11142
#endif
11143
0
}
11144
11145
/************************************************************************/
11146
/*                           operator==()                               */
11147
/************************************************************************/
11148
11149
/** Return a band whose value is 1 if the pixel value of the left operand
11150
 * is equal to the pixel value of the right operand.
11151
 *
11152
 * The resulting band is lazy evaluated. A reference is taken on the input
11153
 * dataset.
11154
 *
11155
 * @since 3.12
11156
 */
11157
GDALComputedRasterBand
11158
GDALRasterBand::operator==(const GDALRasterBand &other) const
11159
0
{
11160
0
#ifndef HAVE_MUPARSER
11161
0
    (void)other;
11162
0
    return ThrowIfNotMuparser();
11163
#else
11164
    ThrowIfNotSameDimensions(*this, other);
11165
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11166
                                  *this, other);
11167
#endif
11168
0
}
11169
11170
/************************************************************************/
11171
/*                           operator==()                               */
11172
/************************************************************************/
11173
11174
/** Return a band whose value is 1 if the pixel value of the left operand
11175
 * is equal to the constant.
11176
 *
11177
 * The resulting band is lazy evaluated. A reference is taken on the input
11178
 * dataset.
11179
 *
11180
 * @since 3.12
11181
 */
11182
GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
11183
0
{
11184
0
#ifndef HAVE_MUPARSER
11185
0
    (void)constant;
11186
0
    return ThrowIfNotMuparser();
11187
#else
11188
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11189
                                  *this, constant);
11190
#endif
11191
0
}
11192
11193
/************************************************************************/
11194
/*                           operator==()                               */
11195
/************************************************************************/
11196
11197
/** Return a band whose value is 1 if the constant is equal to
11198
 * the pixel value of the right operand.
11199
 *
11200
 * The resulting band is lazy evaluated. A reference is taken on the input
11201
 * dataset.
11202
 *
11203
 * @since 3.12
11204
 */
11205
GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
11206
0
{
11207
0
#ifndef HAVE_MUPARSER
11208
0
    (void)constant;
11209
0
    (void)other;
11210
0
    return ThrowIfNotMuparser();
11211
#else
11212
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11213
                                  constant, other);
11214
#endif
11215
0
}
11216
11217
/************************************************************************/
11218
/*                           operator!=()                               */
11219
/************************************************************************/
11220
11221
/** Return a band whose value is 1 if the pixel value of the left operand
11222
 * is different from the pixel value of the right operand.
11223
 *
11224
 * The resulting band is lazy evaluated. A reference is taken on the input
11225
 * dataset.
11226
 *
11227
 * @since 3.12
11228
 */
11229
GDALComputedRasterBand
11230
GDALRasterBand::operator!=(const GDALRasterBand &other) const
11231
0
{
11232
0
#ifndef HAVE_MUPARSER
11233
0
    (void)other;
11234
0
    return ThrowIfNotMuparser();
11235
#else
11236
    ThrowIfNotSameDimensions(*this, other);
11237
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11238
                                  *this, other);
11239
#endif
11240
0
}
11241
11242
/************************************************************************/
11243
/*                           operator!=()                               */
11244
/************************************************************************/
11245
11246
/** Return a band whose value is 1 if the pixel value of the left operand
11247
 * is different from the constant.
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!=(double constant) const
11255
0
{
11256
0
#ifndef HAVE_MUPARSER
11257
0
    (void)constant;
11258
0
    return ThrowIfNotMuparser();
11259
#else
11260
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11261
                                  *this, constant);
11262
#endif
11263
0
}
11264
11265
/************************************************************************/
11266
/*                           operator!=()                               */
11267
/************************************************************************/
11268
11269
/** Return a band whose value is 1 if the constant is different from
11270
 * the pixel value of the right operand.
11271
 *
11272
 * The resulting band is lazy evaluated. A reference is taken on the input
11273
 * dataset.
11274
 *
11275
 * @since 3.12
11276
 */
11277
GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
11278
0
{
11279
0
#ifndef HAVE_MUPARSER
11280
0
    (void)constant;
11281
0
    (void)other;
11282
0
    return ThrowIfNotMuparser();
11283
#else
11284
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11285
                                  constant, other);
11286
#endif
11287
0
}
11288
11289
#if defined(__GNUC__)
11290
#pragma GCC diagnostic push
11291
#pragma GCC diagnostic ignored "-Weffc++"
11292
#endif
11293
11294
/************************************************************************/
11295
/*                           operator&&()                               */
11296
/************************************************************************/
11297
11298
/** Return a band whose value is 1 if the pixel value of the left and right
11299
 * operands is true.
11300
 *
11301
 * The resulting band is lazy evaluated. A reference is taken on the input
11302
 * dataset.
11303
 *
11304
 * @since 3.12
11305
 */
11306
GDALComputedRasterBand
11307
GDALRasterBand::operator&&(const GDALRasterBand &other) const
11308
0
{
11309
0
#ifndef HAVE_MUPARSER
11310
0
    (void)other;
11311
0
    return ThrowIfNotMuparser();
11312
#else
11313
    ThrowIfNotSameDimensions(*this, other);
11314
    return GDALComputedRasterBand(
11315
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
11316
#endif
11317
0
}
11318
11319
/************************************************************************/
11320
/*                           operator&&()                               */
11321
/************************************************************************/
11322
11323
/** Return a band whose value is 1 if the pixel value of the left operand
11324
 * is true, as well as the constant
11325
 *
11326
 * The resulting band is lazy evaluated. A reference is taken on the input
11327
 * dataset.
11328
 *
11329
 * @since 3.12
11330
 */
11331
GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
11332
0
{
11333
0
#ifndef HAVE_MUPARSER
11334
0
    (void)constant;
11335
0
    return ThrowIfNotMuparser();
11336
#else
11337
    return GDALComputedRasterBand(
11338
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
11339
#endif
11340
0
}
11341
11342
/************************************************************************/
11343
/*                           operator&&()                               */
11344
/************************************************************************/
11345
11346
/** Return a band whose value is 1 if the constant is true, as well as
11347
 * the pixel value of the right operand.
11348
 *
11349
 * The resulting band is lazy evaluated. A reference is taken on the input
11350
 * dataset.
11351
 *
11352
 * @since 3.12
11353
 */
11354
GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
11355
0
{
11356
0
#ifndef HAVE_MUPARSER
11357
0
    (void)constant;
11358
0
    (void)other;
11359
0
    return ThrowIfNotMuparser();
11360
#else
11361
    return GDALComputedRasterBand(
11362
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
11363
#endif
11364
0
}
11365
11366
/************************************************************************/
11367
/*                           operator||()                               */
11368
/************************************************************************/
11369
11370
/** Return a band whose value is 1 if the pixel value of the left or right
11371
 * operands is true.
11372
 *
11373
 * The resulting band is lazy evaluated. A reference is taken on the input
11374
 * dataset.
11375
 *
11376
 * @since 3.12
11377
 */
11378
GDALComputedRasterBand
11379
GDALRasterBand::operator||(const GDALRasterBand &other) const
11380
0
{
11381
0
#ifndef HAVE_MUPARSER
11382
0
    (void)other;
11383
0
    return ThrowIfNotMuparser();
11384
#else
11385
    ThrowIfNotSameDimensions(*this, other);
11386
    return GDALComputedRasterBand(
11387
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
11388
#endif
11389
0
}
11390
11391
/************************************************************************/
11392
/*                           operator||()                               */
11393
/************************************************************************/
11394
11395
/** Return a band whose value is 1 if the pixel value of the left operand
11396
 * is true, or if the constant is true
11397
 *
11398
 * The resulting band is lazy evaluated. A reference is taken on the input
11399
 * dataset.
11400
 *
11401
 * @since 3.12
11402
 */
11403
GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
11404
0
{
11405
0
#ifndef HAVE_MUPARSER
11406
0
    (void)constant;
11407
0
    return ThrowIfNotMuparser();
11408
#else
11409
    return GDALComputedRasterBand(
11410
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
11411
#endif
11412
0
}
11413
11414
/************************************************************************/
11415
/*                           operator||()                               */
11416
/************************************************************************/
11417
11418
/** Return a band whose value is 1 if the constant is true, or
11419
 * the pixel value of the right operand is true
11420
 *
11421
 * The resulting band is lazy evaluated. A reference is taken on the input
11422
 * dataset.
11423
 *
11424
 * @since 3.12
11425
 */
11426
GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
11427
0
{
11428
0
#ifndef HAVE_MUPARSER
11429
0
    (void)constant;
11430
0
    (void)other;
11431
0
    return ThrowIfNotMuparser();
11432
#else
11433
    return GDALComputedRasterBand(
11434
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
11435
#endif
11436
0
}
11437
11438
#if defined(__GNUC__)
11439
#pragma GCC diagnostic pop
11440
#endif
11441
11442
/************************************************************************/
11443
/*                            operator!()                               */
11444
/************************************************************************/
11445
11446
/** Return a band whose value is the logical negation of the pixel value
11447
 *
11448
 * The resulting band is lazy evaluated. A reference is taken on the input
11449
 * dataset.
11450
 *
11451
 * @since 3.12
11452
 */
11453
GDALComputedRasterBand GDALRasterBand::operator!() const
11454
0
{
11455
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11456
0
                                  *this, true);
11457
0
}
11458
11459
namespace gdal
11460
{
11461
11462
/************************************************************************/
11463
/*                           IfThenElse()                               */
11464
/************************************************************************/
11465
11466
/** Return a band whose value is thenBand if the corresponding pixel in condBand
11467
 * is not zero, or the one from elseBand otherwise.
11468
 *
11469
 * Variants of this method exits where thenBand and/or elseBand can be double
11470
 * values.
11471
 *
11472
 * The resulting band is lazy evaluated. A reference is taken on the input
11473
 * datasets.
11474
 *
11475
 * This method is the same as the C function GDALRasterBandIfThenElse()
11476
 *
11477
 * @since 3.12
11478
 */
11479
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11480
                                  const GDALRasterBand &thenBand,
11481
                                  const GDALRasterBand &elseBand)
11482
0
{
11483
0
#ifndef HAVE_MUPARSER
11484
0
    (void)condBand;
11485
0
    (void)thenBand;
11486
0
    (void)elseBand;
11487
0
    return ThrowIfNotMuparser();
11488
#else
11489
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11490
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11491
    return GDALComputedRasterBand(
11492
        GDALComputedRasterBand::Operation::OP_TERNARY,
11493
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11494
#endif
11495
0
}
11496
11497
//! @cond Doxygen_Suppress
11498
11499
/************************************************************************/
11500
/*                           IfThenElse()                               */
11501
/************************************************************************/
11502
11503
/** Return a band whose value is thenValue if the corresponding pixel in condBand
11504
 * is not zero, or the one from elseBand otherwise.
11505
 *
11506
 * The resulting band is lazy evaluated. A reference is taken on the input
11507
 * datasets.
11508
 *
11509
 * This method is the same as the C function GDALRasterBandIfThenElse(),
11510
 * with thenBand = (condBand * 0) + thenValue
11511
 *
11512
 * @since 3.12
11513
 */
11514
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11515
                                  double thenValue,
11516
                                  const GDALRasterBand &elseBand)
11517
0
{
11518
0
#ifndef HAVE_MUPARSER
11519
0
    (void)condBand;
11520
0
    (void)thenValue;
11521
0
    (void)elseBand;
11522
0
    return ThrowIfNotMuparser();
11523
#else
11524
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11525
    auto thenBand =
11526
        (condBand * 0)
11527
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
11528
        thenValue;
11529
    return GDALComputedRasterBand(
11530
        GDALComputedRasterBand::Operation::OP_TERNARY,
11531
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11532
#endif
11533
0
}
11534
11535
/************************************************************************/
11536
/*                           IfThenElse()                               */
11537
/************************************************************************/
11538
11539
/** Return a band whose value is thenBand if the corresponding pixel in condBand
11540
 * is not zero, or the one from elseValue otherwise.
11541
 *
11542
 * The resulting band is lazy evaluated. A reference is taken on the input
11543
 * datasets.
11544
 *
11545
 * This method is the same as the C function GDALRasterBandIfThenElse(),
11546
 * with elseBand = (condBand * 0) + elseValue
11547
11548
 * @since 3.12
11549
 */
11550
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11551
                                  const GDALRasterBand &thenBand,
11552
                                  double elseValue)
11553
0
{
11554
0
#ifndef HAVE_MUPARSER
11555
0
    (void)condBand;
11556
0
    (void)thenBand;
11557
0
    (void)elseValue;
11558
0
    return ThrowIfNotMuparser();
11559
#else
11560
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11561
    auto elseBand =
11562
        (condBand * 0)
11563
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
11564
        elseValue;
11565
    return GDALComputedRasterBand(
11566
        GDALComputedRasterBand::Operation::OP_TERNARY,
11567
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11568
#endif
11569
0
}
11570
11571
/************************************************************************/
11572
/*                           IfThenElse()                               */
11573
/************************************************************************/
11574
11575
/** Return a band whose value is thenValue if the corresponding pixel in condBand
11576
 * is not zero, or the one from elseValue otherwise.
11577
 *
11578
 * The resulting band is lazy evaluated. A reference is taken on the input
11579
 * datasets.
11580
 *
11581
 * This method is the same as the C function GDALRasterBandIfThenElse(),
11582
 * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
11583
 *
11584
 * @since 3.12
11585
 */
11586
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11587
                                  double thenValue, double elseValue)
11588
0
{
11589
0
#ifndef HAVE_MUPARSER
11590
0
    (void)condBand;
11591
0
    (void)thenValue;
11592
0
    (void)elseValue;
11593
0
    return ThrowIfNotMuparser();
11594
#else
11595
    auto thenBand =
11596
        (condBand * 0)
11597
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
11598
        thenValue;
11599
    auto elseBand =
11600
        (condBand * 0)
11601
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
11602
        elseValue;
11603
    return GDALComputedRasterBand(
11604
        GDALComputedRasterBand::Operation::OP_TERNARY,
11605
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11606
#endif
11607
0
}
11608
11609
//! @endcond
11610
11611
}  // namespace gdal
11612
11613
/************************************************************************/
11614
/*                     GDALRasterBandIfThenElse()                       */
11615
/************************************************************************/
11616
11617
/** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
11618
 * is not zero, or the one from hElseBand otherwise.
11619
 *
11620
 * The resulting band is lazy evaluated. A reference is taken on the input
11621
 * datasets.
11622
 *
11623
 * This function is the same as the C++ method gdal::IfThenElse()
11624
 *
11625
 * @since 3.12
11626
 */
11627
GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
11628
                                                 GDALRasterBandH hThenBand,
11629
                                                 GDALRasterBandH hElseBand)
11630
0
{
11631
0
    VALIDATE_POINTER1(hCondBand, __func__, nullptr);
11632
0
    VALIDATE_POINTER1(hThenBand, __func__, nullptr);
11633
0
    VALIDATE_POINTER1(hElseBand, __func__, nullptr);
11634
0
#ifndef HAVE_MUPARSER
11635
0
    CPLError(CE_Failure, CPLE_NotSupported,
11636
0
             "Band comparison operators not available on a GDAL build without "
11637
0
             "muparser");
11638
0
    return nullptr;
11639
#else
11640
11641
    auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
11642
    auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
11643
    auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
11644
    try
11645
    {
11646
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11647
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11648
    }
11649
    catch (const std::exception &e)
11650
    {
11651
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11652
        return nullptr;
11653
    }
11654
    return new GDALComputedRasterBand(
11655
        GDALComputedRasterBand::Operation::OP_TERNARY,
11656
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11657
#endif
11658
0
}
11659
11660
/************************************************************************/
11661
/*                       GDALRasterBand::AsType()                       */
11662
/************************************************************************/
11663
11664
/** Cast this band to another type.
11665
 *
11666
 * The resulting band is lazy evaluated. A reference is taken on the input
11667
 * dataset.
11668
 *
11669
 * This method is the same as the C function GDALRasterBandAsDataType()
11670
 *
11671
 * @since 3.12
11672
 */
11673
GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
11674
0
{
11675
0
    if (dt == GDT_Unknown)
11676
0
    {
11677
0
        throw std::runtime_error("AsType(GDT_Unknown) is not supported");
11678
0
    }
11679
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
11680
0
                                  *this, dt);
11681
0
}
11682
11683
/************************************************************************/
11684
/*                       GDALRasterBandAsDataType()                     */
11685
/************************************************************************/
11686
11687
/** Cast this band to another type.
11688
 *
11689
 * The resulting band is lazy evaluated. A reference is taken on the input
11690
 * dataset.
11691
 *
11692
 * This function is the same as the C++ method GDALRasterBand::AsType()
11693
 *
11694
 * @since 3.12
11695
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11696
 */
11697
GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
11698
                                                 GDALDataType eDT)
11699
0
{
11700
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11701
0
    if (eDT == GDT_Unknown)
11702
0
    {
11703
0
        CPLError(CE_Failure, CPLE_NotSupported,
11704
0
                 "GDALRasterBandAsDataType(GDT_Unknown) not supported");
11705
0
        return nullptr;
11706
0
    }
11707
0
    return new GDALComputedRasterBand(
11708
0
        GDALComputedRasterBand::Operation::OP_CAST,
11709
0
        *(GDALRasterBand::FromHandle(hBand)), eDT);
11710
0
}
11711
11712
/************************************************************************/
11713
/*                         GetBandVector()                              */
11714
/************************************************************************/
11715
11716
static std::vector<const GDALRasterBand *>
11717
GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
11718
0
{
11719
0
    std::vector<const GDALRasterBand *> bands;
11720
0
    for (size_t i = 0; i < nBandCount; ++i)
11721
0
    {
11722
0
        if (i > 0)
11723
0
        {
11724
0
            GDALRasterBand::ThrowIfNotSameDimensions(
11725
0
                *(GDALRasterBand::FromHandle(pahBands[0])),
11726
0
                *(GDALRasterBand::FromHandle(pahBands[i])));
11727
0
        }
11728
0
        bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
11729
0
    }
11730
0
    return bands;
11731
0
}
11732
11733
/************************************************************************/
11734
/*                       GDALOperationOnNBands()                        */
11735
/************************************************************************/
11736
11737
static GDALComputedRasterBandH
11738
GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
11739
                      GDALRasterBandH *pahBands)
11740
0
{
11741
0
    VALIDATE_POINTER1(pahBands, __func__, nullptr);
11742
0
    if (nBandCount == 0)
11743
0
    {
11744
0
        CPLError(CE_Failure, CPLE_AppDefined,
11745
0
                 "At least one band should be passed");
11746
0
        return nullptr;
11747
0
    }
11748
11749
0
    std::vector<const GDALRasterBand *> bands;
11750
0
    try
11751
0
    {
11752
0
        bands = GetBandVector(nBandCount, pahBands);
11753
0
    }
11754
0
    catch (const std::exception &e)
11755
0
    {
11756
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11757
0
        return nullptr;
11758
0
    }
11759
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
11760
0
}
11761
11762
/************************************************************************/
11763
/*                       GDALMaximumOfNBands()                          */
11764
/************************************************************************/
11765
11766
/** Return a band whose each pixel value is the maximum of the corresponding
11767
 * pixel values in the input bands.
11768
 *
11769
 * The resulting band is lazy evaluated. A reference is taken on input
11770
 * datasets.
11771
 *
11772
 * This function is the same as the C ++ method gdal::max()
11773
 *
11774
 * @since 3.12
11775
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11776
 */
11777
GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
11778
                                            GDALRasterBandH *pahBands)
11779
0
{
11780
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
11781
0
                                 nBandCount, pahBands);
11782
0
}
11783
11784
/************************************************************************/
11785
/*                               gdal::max()                            */
11786
/************************************************************************/
11787
11788
namespace gdal
11789
{
11790
/** Return a band whose each pixel value is the maximum of the corresponding
11791
 * pixel values in the inputs (bands or constants)
11792
 *
11793
 * The resulting band is lazy evaluated. A reference is taken on input
11794
 * datasets.
11795
 *
11796
 * Two or more bands can be passed.
11797
 *
11798
 * This method is the same as the C function GDALMaximumOfNBands()
11799
 *
11800
 * @since 3.12
11801
 * @throw std::runtime_error if bands do not have the same dimensions.
11802
 */
11803
GDALComputedRasterBand max(const GDALRasterBand &first,
11804
                           const GDALRasterBand &second)
11805
0
{
11806
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11807
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
11808
0
                                  first, second);
11809
0
}
11810
}  // namespace gdal
11811
11812
/************************************************************************/
11813
/*                     GDALRasterBandMaxConstant()                      */
11814
/************************************************************************/
11815
11816
/** Return a band whose each pixel value is the maximum of the corresponding
11817
 * pixel values in the input band and the constant.
11818
 *
11819
 * The resulting band is lazy evaluated. A reference is taken on the input
11820
 * dataset.
11821
 *
11822
 * This function is the same as the C ++ method gdal::max()
11823
 *
11824
 * @since 3.12
11825
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11826
 */
11827
GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
11828
                                                  double dfConstant)
11829
0
{
11830
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
11831
0
        GDALComputedRasterBand::Operation::OP_MAX,
11832
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
11833
0
        dfConstant));
11834
0
}
11835
11836
/************************************************************************/
11837
/*                       GDALMinimumOfNBands()                          */
11838
/************************************************************************/
11839
11840
/** Return a band whose each pixel value is the minimum of the corresponding
11841
 * pixel values in the input bands.
11842
 *
11843
 * The resulting band is lazy evaluated. A reference is taken on input
11844
 * datasets.
11845
 *
11846
 * This function is the same as the C ++ method gdal::min()
11847
 *
11848
 * @since 3.12
11849
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11850
 */
11851
GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
11852
                                            GDALRasterBandH *pahBands)
11853
0
{
11854
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
11855
0
                                 nBandCount, pahBands);
11856
0
}
11857
11858
/************************************************************************/
11859
/*                               gdal::min()                            */
11860
/************************************************************************/
11861
11862
namespace gdal
11863
{
11864
/** Return a band whose each pixel value is the minimum of the corresponding
11865
 * pixel values in the inputs (bands or constants)
11866
 *
11867
 * The resulting band is lazy evaluated. A reference is taken on input
11868
 * datasets.
11869
 *
11870
 * Two or more bands can be passed.
11871
 *
11872
 * This method is the same as the C function GDALMinimumOfNBands()
11873
 *
11874
 * @since 3.12
11875
 * @throw std::runtime_error if bands do not have the same dimensions.
11876
 */
11877
GDALComputedRasterBand min(const GDALRasterBand &first,
11878
                           const GDALRasterBand &second)
11879
0
{
11880
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11881
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
11882
0
                                  first, second);
11883
0
}
11884
}  // namespace gdal
11885
11886
/************************************************************************/
11887
/*                     GDALRasterBandMinConstant()                      */
11888
/************************************************************************/
11889
11890
/** Return a band whose each pixel value is the minimum of the corresponding
11891
 * pixel values in the input band and the constant.
11892
 *
11893
 * The resulting band is lazy evaluated. A reference is taken on the input
11894
 * dataset.
11895
 *
11896
 * This function is the same as the C ++ method gdal::min()
11897
 *
11898
 * @since 3.12
11899
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11900
 */
11901
GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
11902
                                                  double dfConstant)
11903
0
{
11904
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
11905
0
        GDALComputedRasterBand::Operation::OP_MIN,
11906
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
11907
0
        dfConstant));
11908
0
}
11909
11910
/************************************************************************/
11911
/*                         GDALMeanOfNBands()                           */
11912
/************************************************************************/
11913
11914
/** Return a band whose each pixel value is the arithmetic mean of the
11915
 * corresponding pixel values in the input bands.
11916
 *
11917
 * The resulting band is lazy evaluated. A reference is taken on input
11918
 * datasets.
11919
 *
11920
 * This function is the same as the C ++ method gdal::mean()
11921
 *
11922
 * @since 3.12
11923
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11924
 */
11925
GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
11926
                                         GDALRasterBandH *pahBands)
11927
0
{
11928
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
11929
0
                                 nBandCount, pahBands);
11930
0
}
11931
11932
/************************************************************************/
11933
/*                              gdal::mean()                            */
11934
/************************************************************************/
11935
11936
namespace gdal
11937
{
11938
11939
/** Return a band whose each pixel value is the arithmetic mean of the
11940
 * corresponding pixel values in the input bands.
11941
 *
11942
 * The resulting band is lazy evaluated. A reference is taken on input
11943
 * datasets.
11944
 *
11945
 * Two or more bands can be passed.
11946
 *
11947
 * This method is the same as the C function GDALMeanOfNBands()
11948
 *
11949
 * @since 3.12
11950
 * @throw std::runtime_error if bands do not have the same dimensions.
11951
 */
11952
GDALComputedRasterBand mean(const GDALRasterBand &first,
11953
                            const GDALRasterBand &second)
11954
0
{
11955
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11956
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
11957
0
                                  first, second);
11958
0
}
11959
}  // namespace gdal
11960
11961
/************************************************************************/
11962
/*                              gdal::abs()                             */
11963
/************************************************************************/
11964
11965
namespace gdal
11966
{
11967
11968
/** Return a band whose each pixel value is the absolute value (or module
11969
 * for complex data type) of the corresponding pixel value in the input band.
11970
 *
11971
 * The resulting band is lazy evaluated. A reference is taken on input
11972
 * datasets.
11973
 *
11974
 * @since 3.12
11975
 */
11976
GDALComputedRasterBand abs(const GDALRasterBand &band)
11977
0
{
11978
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
11979
0
                                  band);
11980
0
}
11981
}  // namespace gdal
11982
11983
/************************************************************************/
11984
/*                             gdal::fabs()                             */
11985
/************************************************************************/
11986
11987
namespace gdal
11988
{
11989
11990
/** Return a band whose each pixel value is the absolute value (or module
11991
 * for complex data type) of the corresponding pixel value in the input band.
11992
 *
11993
 * The resulting band is lazy evaluated. A reference is taken on input
11994
 * datasets.
11995
 *
11996
 * @since 3.12
11997
 */
11998
GDALComputedRasterBand fabs(const GDALRasterBand &band)
11999
0
{
12000
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12001
0
                                  band);
12002
0
}
12003
}  // namespace gdal
12004
12005
/************************************************************************/
12006
/*                             gdal::sqrt()                             */
12007
/************************************************************************/
12008
12009
namespace gdal
12010
{
12011
12012
/** Return a band whose each pixel value is the square root of the
12013
 * corresponding pixel value in the input band.
12014
 *
12015
 * The resulting band is lazy evaluated. A reference is taken on input
12016
 * datasets.
12017
 *
12018
 * @since 3.12
12019
 */
12020
GDALComputedRasterBand sqrt(const GDALRasterBand &band)
12021
0
{
12022
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
12023
0
                                  band);
12024
0
}
12025
}  // namespace gdal
12026
12027
/************************************************************************/
12028
/*                             gdal::log()                              */
12029
/************************************************************************/
12030
12031
namespace gdal
12032
{
12033
12034
/** Return a band whose each pixel value is the natural logarithm of the
12035
 * corresponding pixel value in the input band.
12036
 *
12037
 * The resulting band is lazy evaluated. A reference is taken on input
12038
 * datasets.
12039
 *
12040
 * @since 3.12
12041
 */
12042
GDALComputedRasterBand log(const GDALRasterBand &band)
12043
0
{
12044
0
#ifndef HAVE_MUPARSER
12045
0
    (void)band;
12046
0
    return ThrowIfNotMuparser();
12047
#else
12048
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
12049
                                  band);
12050
#endif
12051
0
}
12052
}  // namespace gdal
12053
12054
/************************************************************************/
12055
/*                             gdal::log10()                            */
12056
/************************************************************************/
12057
12058
namespace gdal
12059
{
12060
12061
/** Return a band whose each pixel value is the logarithm base 10 of the
12062
 * corresponding pixel value in the input band.
12063
 *
12064
 * The resulting band is lazy evaluated. A reference is taken on input
12065
 * datasets.
12066
 *
12067
 * @since 3.12
12068
 */
12069
GDALComputedRasterBand log10(const GDALRasterBand &band)
12070
0
{
12071
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
12072
0
                                  band);
12073
0
}
12074
}  // namespace gdal
12075
12076
/************************************************************************/
12077
/*                             gdal::pow()                              */
12078
/************************************************************************/
12079
12080
namespace gdal
12081
{
12082
12083
#ifndef DOXYGEN_SKIP
12084
/** Return a band whose each pixel value is the constant raised to the power of
12085
 * the corresponding pixel value in the input band.
12086
 *
12087
 * The resulting band is lazy evaluated. A reference is taken on input
12088
 * datasets.
12089
 *
12090
 * @since 3.12
12091
 */
12092
GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
12093
0
{
12094
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12095
0
                                  constant, band);
12096
0
}
12097
#endif
12098
12099
}  // namespace gdal
12100
12101
/************************************************************************/
12102
/*                             gdal::pow()                              */
12103
/************************************************************************/
12104
12105
namespace gdal
12106
{
12107
12108
/** Return a band whose each pixel value is the the corresponding pixel value
12109
 * in the input band raised to the power of the constant.
12110
 *
12111
 * The resulting band is lazy evaluated. A reference is taken on input
12112
 * datasets.
12113
 *
12114
 * @since 3.12
12115
 */
12116
GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
12117
0
{
12118
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12119
0
                                  band, constant);
12120
0
}
12121
}  // namespace gdal
12122
12123
/************************************************************************/
12124
/*                             gdal::pow()                              */
12125
/************************************************************************/
12126
12127
namespace gdal
12128
{
12129
12130
#ifndef DOXYGEN_SKIP
12131
/** Return a band whose each pixel value is the the corresponding pixel value
12132
 * in the input band1 raised to the power of the corresponding pixel value
12133
 * in the input band2
12134
 *
12135
 * The resulting band is lazy evaluated. A reference is taken on input
12136
 * datasets.
12137
 *
12138
 * @since 3.12
12139
 * @throw std::runtime_error if bands do not have the same dimensions.
12140
 */
12141
GDALComputedRasterBand pow(const GDALRasterBand &band1,
12142
                           const GDALRasterBand &band2)
12143
0
{
12144
0
#ifndef HAVE_MUPARSER
12145
0
    (void)band1;
12146
0
    (void)band2;
12147
0
    return ThrowIfNotMuparser();
12148
#else
12149
    GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
12150
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12151
                                  band1, band2);
12152
#endif
12153
0
}
12154
#endif
12155
}  // namespace gdal