Coverage Report

Created: 2025-11-16 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/gcore/gdalrasterband.cpp
Line
Count
Source
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
18
#include <cassert>
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_abstractbandblockcache.h"
41
#include "gdalantirecursion.h"
42
#include "gdal_rat.h"
43
#include "gdal_rasterband.h"
44
#include "gdal_priv_templates.hpp"
45
#include "gdal_interpolateatpoint.h"
46
#include "gdal_minmax_element.hpp"
47
#include "gdalmultidim_priv.h"
48
49
#if defined(__AVX2__) || defined(__FMA__)
50
#include <immintrin.h>
51
#endif
52
53
/************************************************************************/
54
/*                           GDALRasterBand()                           */
55
/************************************************************************/
56
57
/*! Constructor. Applications should never create GDALRasterBands directly. */
58
59
GDALRasterBand::GDALRasterBand()
60
0
    : GDALRasterBand(
61
0
          CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
62
0
{
63
0
}
64
65
/** Constructor. Applications should never create GDALRasterBands directly.
66
 * @param bForceCachedIOIn Whether cached IO should be forced.
67
 */
68
GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
69
0
    : bForceCachedIO(bForceCachedIOIn)
70
71
0
{
72
0
}
73
74
/************************************************************************/
75
/*                          ~GDALRasterBand()                           */
76
/************************************************************************/
77
78
/*! Destructor. Applications should never destroy GDALRasterBands directly,
79
    instead destroy the GDALDataset. */
80
81
GDALRasterBand::~GDALRasterBand()
82
83
0
{
84
0
    if (poDS && poDS->IsMarkedSuppressOnClose())
85
0
    {
86
0
        if (poBandBlockCache)
87
0
            poBandBlockCache->DisableDirtyBlockWriting();
88
0
    }
89
0
    GDALRasterBand::FlushCache(true);
90
91
0
    delete poBandBlockCache;
92
93
0
    if (static_cast<GIntBig>(nBlockReads) >
94
0
            static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
95
0
        nBand == 1 && poDS != nullptr)
96
0
    {
97
0
        CPLDebug(
98
0
            "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
99
0
            nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
100
0
            poDS->GetDescription());
101
0
    }
102
103
0
    InvalidateMaskBand();
104
0
    nBand = -nBand;
105
106
0
    delete m_poPointsCache;
107
0
}
108
109
/************************************************************************/
110
/*                              RasterIO()                              */
111
/************************************************************************/
112
113
/**
114
 * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
115
 *                                int nXOff, int nYOff, int nXSize, int nYSize,
116
 *                                void * pData, int nBufXSize, int nBufYSize,
117
 *                                GDALDataType eBufType,
118
 *                                GSpacing nPixelSpace,
119
 *                                GSpacing nLineSpace,
120
 *                                GDALRasterIOExtraArg* psExtraArg )
121
 * \brief Read/write a region of image data for this band.
122
 *
123
 * This method allows reading a region of a GDALRasterBand into a buffer,
124
 * or writing data from a buffer into a region of a GDALRasterBand. It
125
 * automatically takes care of data type translation if the data type
126
 * (eBufType) of the buffer is different than that of the GDALRasterBand.
127
 * The method also takes care of image decimation / replication if the
128
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
129
 * region being accessed (nXSize x nYSize).
130
 *
131
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
132
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
133
 * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
134
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
135
 * Or use nLineSpace and a possibly shifted pData value.
136
 *
137
 * The nPixelSpace and nLineSpace parameters allow reading into or
138
 * writing from unusually organized buffers. This is primarily used
139
 * for buffers containing more than one bands raster data in interleaved
140
 * format.
141
 *
142
 * Some formats may efficiently implement decimation into a buffer by
143
 * reading from lower resolution overview images. The logic of the default
144
 * implementation in the base class GDALRasterBand is the following one. It
145
 * computes a target_downscaling_factor from the window of interest and buffer
146
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
147
 * It then walks through overviews and will select the first one whose
148
 * downscaling factor is greater than target_downscaling_factor / 1.2.
149
 *
150
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
151
 * The relationship between target_downscaling_factor and the select overview
152
 * level is the following one:
153
 *
154
 * target_downscaling_factor  | selected_overview
155
 * -------------------------  | -----------------
156
 * ]0,       2 / 1.2]         | full resolution band
157
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
158
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
159
 * ]8 / 1.2, infinity[        | 8x downsampled band
160
 *
161
 * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
162
 * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
163
 * option. Also note that starting with GDAL 3.9, when the resampling algorithm
164
 * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
165
 * this oversampling threshold defaults to 1. Consequently if there are overviews
166
 * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
167
 * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
168
 *
169
 * For highest performance full resolution data access, read and write
170
 * on "block boundaries" as returned by GetBlockSize(), or use the
171
 * ReadBlock() and WriteBlock() methods.
172
 *
173
 * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
174
 * functions.
175
 *
176
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
177
 * write a region of data.
178
 *
179
 * @param nXOff The pixel offset to the top left corner of the region
180
 * of the band to be accessed. This would be zero to start from the left side.
181
 *
182
 * @param nYOff The line offset to the top left corner of the region
183
 * of the band to be accessed. This would be zero to start from the top.
184
 *
185
 * @param nXSize The width of the region of the band to be accessed in pixels.
186
 *
187
 * @param nYSize The height of the region of the band to be accessed in lines.
188
 *
189
 * @param pData The buffer into which the data should be read, or from which
190
 * it should be written. This buffer must contain at least nBufXSize *
191
 * nBufYSize words of type eBufType. It is organized in left to right,
192
 * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
193
 * and nLineSpace parameters.
194
 * Note that even with eRWFlag==GF_Write, the content of the buffer might be
195
 * temporarily modified during the execution of this method (and eventually
196
 * restored back to its original content), so it is not safe to use a buffer
197
 * stored in a read-only section of the calling program.
198
 *
199
 * @param nBufXSize the width of the buffer image into which the desired region
200
 * is to be read, or from which it is to be written.
201
 *
202
 * @param nBufYSize the height of the buffer image into which the desired region
203
 * is to be read, or from which it is to be written.
204
 *
205
 * @param eBufType the type of the pixel values in the pData data buffer. The
206
 * pixel values will automatically be translated to/from the GDALRasterBand
207
 * data type as needed. Most driver implementations will use GDALCopyWords64()
208
 * to perform data type translation.
209
 *
210
 * @param nPixelSpace The byte offset from the start of one pixel value in
211
 * pData to the start of the next pixel value within a scanline. If defaulted
212
 * (0) the size of the datatype eBufType is used.
213
 *
214
 * @param nLineSpace The byte offset from the start of one scanline in
215
 * pData to the start of the next. If defaulted (0) the size of the datatype
216
 * eBufType * nBufXSize is used.
217
 *
218
 * @param psExtraArg Pointer to a GDALRasterIOExtraArg
219
 * structure with additional arguments to specify resampling and progress
220
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
221
 * configuration option can also be defined to override the default resampling
222
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
223
 *
224
 * @return CE_Failure if the access fails, otherwise CE_None.
225
 */
226
227
/**
228
 * \brief Read/write a region of image data for this band.
229
 *
230
 * This method allows reading a region of a GDALRasterBand into a buffer,
231
 * or writing data from a buffer into a region of a GDALRasterBand. It
232
 * automatically takes care of data type translation if the data type
233
 * (eBufType) of the buffer is different than that of the GDALRasterBand.
234
 * The method also takes care of image decimation / replication if the
235
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
236
 * region being accessed (nXSize x nYSize).
237
 *
238
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
239
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
240
 * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
241
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
242
 * Or use nLineSpace and a possibly shifted pData value.
243
 *
244
 * The nPixelSpace and nLineSpace parameters allow reading into or
245
 * writing from unusually organized buffers. This is primarily used
246
 * for buffers containing more than one bands raster data in interleaved
247
 * format.
248
 *
249
 * Some formats may efficiently implement decimation into a buffer by
250
 * reading from lower resolution overview images. The logic of the default
251
 * implementation in the base class GDALRasterBand is the following one. It
252
 * computes a target_downscaling_factor from the window of interest and buffer
253
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
254
 * It then walks through overviews and will select the first one whose
255
 * downscaling factor is greater than target_downscaling_factor / 1.2.
256
 *
257
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
258
 * The relationship between target_downscaling_factor and the select overview
259
 * level is the following one:
260
 *
261
 * target_downscaling_factor  | selected_overview
262
 * -------------------------  | -----------------
263
 * ]0,       2 / 1.2]         | full resolution band
264
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
265
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
266
 * ]8 / 1.2, infinity[        | 8x downsampled band
267
 *
268
 * For highest performance full resolution data access, read and write
269
 * on "block boundaries" as returned by GetBlockSize(), or use the
270
 * ReadBlock() and WriteBlock() methods.
271
 *
272
 * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
273
 * functions.
274
 *
275
 * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
276
 * more convenient to use for most common use cases.
277
 *
278
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
279
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
280
 * instance of this dataset) concurrently from several threads.
281
 *
282
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
283
 * write a region of data.
284
 *
285
 * @param nXOff The pixel offset to the top left corner of the region
286
 * of the band to be accessed. This would be zero to start from the left side.
287
 *
288
 * @param nYOff The line offset to the top left corner of the region
289
 * of the band to be accessed. This would be zero to start from the top.
290
 *
291
 * @param nXSize The width of the region of the band to be accessed in pixels.
292
 *
293
 * @param nYSize The height of the region of the band to be accessed in lines.
294
 *
295
 * @param[in,out] pData The buffer into which the data should be read, or from
296
 * which it should be written. This buffer must contain at least nBufXSize *
297
 * nBufYSize words of type eBufType. It is organized in left to right,
298
 * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
299
 * and nLineSpace parameters.
300
 *
301
 * @param nBufXSize the width of the buffer image into which the desired region
302
 * is to be read, or from which it is to be written.
303
 *
304
 * @param nBufYSize the height of the buffer image into which the desired region
305
 * is to be read, or from which it is to be written.
306
 *
307
 * @param eBufType the type of the pixel values in the pData data buffer. The
308
 * pixel values will automatically be translated to/from the GDALRasterBand
309
 * data type as needed.
310
 *
311
 * @param nPixelSpace The byte offset from the start of one pixel value in
312
 * pData to the start of the next pixel value within a scanline. If defaulted
313
 * (0) the size of the datatype eBufType is used.
314
 *
315
 * @param nLineSpace The byte offset from the start of one scanline in
316
 * pData to the start of the next. If defaulted (0) the size of the datatype
317
 * eBufType * nBufXSize is used.
318
 *
319
 * @param[in] psExtraArg Pointer to a GDALRasterIOExtraArg
320
 * structure with additional arguments to specify resampling and progress
321
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
322
 * configuration option can also be defined to override the default resampling
323
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
324
 *
325
 * @return CE_Failure if the access fails, otherwise CE_None.
326
 *
327
 * @see GDALRasterBand::ReadRaster()
328
 */
329
330
CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
331
                                int nXSize, int nYSize, void *pData,
332
                                int nBufXSize, int nBufYSize,
333
                                GDALDataType eBufType, GSpacing nPixelSpace,
334
                                GSpacing nLineSpace,
335
                                GDALRasterIOExtraArg *psExtraArg)
336
337
0
{
338
0
    GDALRasterIOExtraArg sExtraArg;
339
0
    if (psExtraArg == nullptr)
340
0
    {
341
0
        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
342
0
        psExtraArg = &sExtraArg;
343
0
    }
344
0
    else if (CPL_UNLIKELY(psExtraArg->nVersion >
345
0
                          RASTERIO_EXTRA_ARG_CURRENT_VERSION))
346
0
    {
347
0
        ReportError(CE_Failure, CPLE_AppDefined,
348
0
                    "Unhandled version of GDALRasterIOExtraArg");
349
0
        return CE_Failure;
350
0
    }
351
352
0
    GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
353
0
                                       nBufYSize);
354
355
0
    if (CPL_UNLIKELY(nullptr == pData))
356
0
    {
357
0
        ReportError(CE_Failure, CPLE_AppDefined,
358
0
                    "The buffer into which the data should be read is null");
359
0
        return CE_Failure;
360
0
    }
361
362
    /* -------------------------------------------------------------------- */
363
    /*      Some size values are "noop".  Lets just return to avoid         */
364
    /*      stressing lower level functions.                                */
365
    /* -------------------------------------------------------------------- */
366
0
    if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
367
0
                     nBufYSize < 1))
368
0
    {
369
0
        CPLDebug("GDAL",
370
0
                 "RasterIO() skipped for odd window or buffer size.\n"
371
0
                 "  Window = (%d,%d)x%dx%d\n"
372
0
                 "  Buffer = %dx%d\n",
373
0
                 nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
374
375
0
        return CE_None;
376
0
    }
377
378
0
    if (eRWFlag == GF_Write)
379
0
    {
380
0
        if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
381
0
        {
382
0
            ReportError(eFlushBlockErr, CPLE_AppDefined,
383
0
                        "An error occurred while writing a dirty block "
384
0
                        "from GDALRasterBand::RasterIO");
385
0
            CPLErr eErr = eFlushBlockErr;
386
0
            eFlushBlockErr = CE_None;
387
0
            return eErr;
388
0
        }
389
0
        if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
390
0
        {
391
0
            return CE_Failure;
392
0
        }
393
0
    }
394
395
    /* -------------------------------------------------------------------- */
396
    /*      If pixel and line spacing are defaulted assign reasonable      */
397
    /*      value assuming a packed buffer.                                 */
398
    /* -------------------------------------------------------------------- */
399
0
    if (nPixelSpace == 0)
400
0
    {
401
0
        nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
402
0
    }
403
404
0
    if (nLineSpace == 0)
405
0
    {
406
0
        nLineSpace = nPixelSpace * nBufXSize;
407
0
    }
408
409
    /* -------------------------------------------------------------------- */
410
    /*      Do some validation of parameters.                               */
411
    /* -------------------------------------------------------------------- */
412
0
    if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
413
0
                     nXOff + nXSize > nRasterXSize || nYOff < 0 ||
414
0
                     nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
415
0
    {
416
0
        ReportError(CE_Failure, CPLE_IllegalArg,
417
0
                    "Access window out of range in RasterIO().  Requested\n"
418
0
                    "(%d,%d) of size %dx%d on raster of %dx%d.",
419
0
                    nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
420
0
        return CE_Failure;
421
0
    }
422
423
0
    if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
424
0
    {
425
0
        ReportError(
426
0
            CE_Failure, CPLE_IllegalArg,
427
0
            "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
428
0
            eRWFlag);
429
0
        return CE_Failure;
430
0
    }
431
0
    if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
432
0
    {
433
0
        ReportError(CE_Failure, CPLE_IllegalArg,
434
0
                    "Illegal GDT_Unknown/GDT_TypeCount argument");
435
0
        return CE_Failure;
436
0
    }
437
438
0
    return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
439
0
                            nBufXSize, nBufYSize, eBufType, nPixelSpace,
440
0
                            nLineSpace, psExtraArg);
441
0
}
442
443
/************************************************************************/
444
/*                         RasterIOInternal()                           */
445
/************************************************************************/
446
447
CPLErr GDALRasterBand::RasterIOInternal(
448
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
449
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
450
    GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
451
0
{
452
    /* -------------------------------------------------------------------- */
453
    /*      Call the format specific function.                              */
454
    /* -------------------------------------------------------------------- */
455
456
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
457
458
0
    CPLErr eErr;
459
0
    if (bForceCachedIO)
460
0
        eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
461
0
                                         pData, nBufXSize, nBufYSize, eBufType,
462
0
                                         nPixelSpace, nLineSpace, psExtraArg);
463
0
    else
464
0
        eErr =
465
0
            IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
466
0
                      nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
467
468
0
    if (bCallLeaveReadWrite)
469
0
        LeaveReadWrite();
470
471
0
    return eErr;
472
0
}
473
474
/************************************************************************/
475
/*                            GDALRasterIO()                            */
476
/************************************************************************/
477
478
/**
479
 * \brief Read/write a region of image data for this band.
480
 *
481
 * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
482
 * resolution, progress callback, etc. are needed)
483
 *
484
 * @see GDALRasterBand::RasterIO()
485
 */
486
487
CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
488
                                int nXOff, int nYOff, int nXSize, int nYSize,
489
                                void *pData, int nBufXSize, int nBufYSize,
490
                                GDALDataType eBufType, int nPixelSpace,
491
                                int nLineSpace)
492
493
0
{
494
0
    VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
495
496
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
497
498
0
    return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
499
0
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
500
0
                             nLineSpace, nullptr));
501
0
}
502
503
/************************************************************************/
504
/*                            GDALRasterIOEx()                          */
505
/************************************************************************/
506
507
/**
508
 * \brief Read/write a region of image data for this band.
509
 *
510
 * @see GDALRasterBand::RasterIO()
511
 */
512
513
CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
514
                                  int nXOff, int nYOff, int nXSize, int nYSize,
515
                                  void *pData, int nBufXSize, int nBufYSize,
516
                                  GDALDataType eBufType, GSpacing nPixelSpace,
517
                                  GSpacing nLineSpace,
518
                                  GDALRasterIOExtraArg *psExtraArg)
519
520
0
{
521
0
    VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
522
523
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
524
525
0
    return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
526
0
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
527
0
                             nLineSpace, psExtraArg));
528
0
}
529
530
/************************************************************************/
531
/*                           GetGDTFromCppType()                        */
532
/************************************************************************/
533
534
namespace
535
{
536
template <class T> struct GetGDTFromCppType;
537
538
#define DEFINE_GetGDTFromCppType(T, eDT)                                       \
539
    template <> struct GetGDTFromCppType<T>                                    \
540
    {                                                                          \
541
        static constexpr GDALDataType GDT = eDT;                               \
542
    }
543
544
DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
545
DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
546
DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
547
DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
548
DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
549
DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
550
DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
551
DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
552
DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
553
DEFINE_GetGDTFromCppType(float, GDT_Float32);
554
DEFINE_GetGDTFromCppType(double, GDT_Float64);
555
// Not allowed by C++ standard
556
//DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
557
//DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
558
DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
559
DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
560
}  // namespace
561
562
/************************************************************************/
563
/*                           ReadRaster()                               */
564
/************************************************************************/
565
566
// clang-format off
567
/** Read a region of image data for this band.
568
 *
569
 * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
570
 * for common use cases, like reading a whole band.
571
 * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
572
 * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
573
 * float, double, std::complex<float|double>.
574
 *
575
 * 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>&,
576
 * and can allocate memory automatically.
577
 *
578
 * To read a whole band (assuming it fits into memory), as an array of double:
579
 *
580
\code{.cpp}
581
 double* myArray = static_cast<double*>(
582
     VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
583
 // TODO: check here that myArray != nullptr
584
 const size_t nArrayEltCount =
585
     static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
586
 if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
587
 {
588
     // do something
589
 }
590
 VSIFree(myArray)
591
\endcode
592
 *
593
 * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
594
 *
595
\code{.cpp}
596
 double* myArray = static_cast<double*>(
597
     VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
598
 // TODO: check here that myArray != nullptr
599
 const size_t nArrayEltCount = 128 * 128;
600
 if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
601
 {
602
     // do something
603
 }
604
 VSIFree(myArray)
605
\endcode
606
 *
607
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
608
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
609
 * instance of this dataset) concurrently from several threads.
610
 *
611
 * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
612
 * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
613
 * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
614
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
615
 * Or use nLineSpace and a possibly shifted pData value.
616
 *
617
 * @param[out] pData The buffer into which the data should be written.
618
 * This buffer must contain at least nBufXSize *
619
 * nBufYSize words of type T. It is organized in left to right,
620
 * top to bottom pixel order, and fully packed.
621
 * The type of the buffer does not need to be the one of GetDataType(). The
622
 * method will perform data type translation (with potential rounding, clamping)
623
 * if needed.
624
 *
625
 * @param nArrayEltCount Number of values of pData. If non zero, the method will
626
 * check that it is at least greater or equal to nBufXSize * nBufYSize, and
627
 * return in error if it is not. If set to zero, then pData is trusted to be
628
 * large enough.
629
 *
630
 * @param dfXOff The pixel offset to the top left corner of the region
631
 * of the band to be accessed. This would be zero to start from the left side.
632
 * Defaults to 0.
633
 *
634
 * @param dfYOff The line offset to the top left corner of the region
635
 * of the band to be accessed. This would be zero to start from the top.
636
 * Defaults to 0.
637
 *
638
 * @param dfXSize The width of the region of the band to be accessed in pixels.
639
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
640
 * dfXSize is set to the band width.
641
 *
642
 * @param dfYSize The height of the region of the band to be accessed in lines.
643
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
644
 * dfYSize is set to the band height.
645
 *
646
 * @param nBufXSize the width of the buffer image into which the desired region
647
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
648
 * then nBufXSize is initialized with dfXSize.
649
 *
650
 * @param nBufYSize the height of the buffer image into which the desired region
651
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
652
 * then nBufYSize is initialized with dfYSize.
653
 *
654
 * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
655
 *
656
 * @param pfnProgress Progress function. May be nullptr.
657
 *
658
 * @param pProgressData User data of pfnProgress. May be nullptr.
659
 *
660
 * @return CE_Failure if the access fails, otherwise CE_None.
661
 *
662
 * @see GDALRasterBand::RasterIO()
663
 * @since GDAL 3.10
664
 */
665
// clang-format on
666
667
template <class T>
668
CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
669
                                  double dfXOff, double dfYOff, double dfXSize,
670
                                  double dfYSize, size_t nBufXSize,
671
                                  size_t nBufYSize,
672
                                  GDALRIOResampleAlg eResampleAlg,
673
                                  GDALProgressFunc pfnProgress,
674
                                  void *pProgressData) const
675
0
{
676
0
    if (((nBufXSize | nBufYSize) >> 31) != 0)
677
0
    {
678
0
        return CE_Failure;
679
0
    }
680
681
0
    if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
682
0
    {
683
0
        dfXSize = nRasterXSize;
684
0
        dfYSize = nRasterYSize;
685
0
    }
686
0
    else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
687
0
             !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
688
0
             !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
689
0
             dfYOff + dfYSize > INT_MAX)
690
0
    {
691
0
        return CE_Failure;
692
0
    }
693
694
0
    GDALRasterIOExtraArg sExtraArg;
695
0
    sExtraArg.nVersion = 1;
696
0
    sExtraArg.eResampleAlg = eResampleAlg;
697
0
    sExtraArg.pfnProgress = pfnProgress;
698
0
    sExtraArg.pProgressData = pProgressData;
699
0
    sExtraArg.bFloatingPointWindowValidity = true;
700
0
    sExtraArg.dfXOff = dfXOff;
701
0
    sExtraArg.dfYOff = dfYOff;
702
0
    sExtraArg.dfXSize = dfXSize;
703
0
    sExtraArg.dfYSize = dfYSize;
704
0
    const int nXOff = static_cast<int>(dfXOff);
705
0
    const int nYOff = static_cast<int>(dfYOff);
706
0
    const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
707
0
    const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
708
0
    if (nBufXSize == 0 && nBufYSize == 0)
709
0
    {
710
0
        if (static_cast<int>(dfXSize) == dfXSize &&
711
0
            static_cast<int>(dfYSize) == dfYSize)
712
0
        {
713
0
            nBufXSize = static_cast<int>(dfXSize);
714
0
            nBufYSize = static_cast<int>(dfYSize);
715
0
        }
716
0
        else
717
0
        {
718
0
            CPLError(CE_Failure, CPLE_AppDefined,
719
0
                     "nBufXSize and nBufYSize must be provided if dfXSize or "
720
0
                     "dfYSize is not an integer value");
721
0
            return CE_Failure;
722
0
        }
723
0
    }
724
0
    if (nBufXSize == 0 || nBufYSize == 0)
725
0
    {
726
0
        CPLDebug("GDAL",
727
0
                 "RasterIO() skipped for odd window or buffer size.\n"
728
0
                 "  Window = (%d,%d)x%dx%d\n"
729
0
                 "  Buffer = %dx%d\n",
730
0
                 nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
731
0
                 static_cast<int>(nBufYSize));
732
733
0
        return CE_None;
734
0
    }
735
736
0
    if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
737
0
    {
738
0
        CPLError(CE_Failure, CPLE_AppDefined,
739
0
                 "Provided array is not large enough");
740
0
        return CE_Failure;
741
0
    }
742
743
0
    constexpr GSpacing nPixelSpace = sizeof(T);
744
0
    const GSpacing nLineSpace = nPixelSpace * nBufXSize;
745
0
    constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
746
747
0
    GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
748
749
0
    return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
750
0
                                   static_cast<int>(nBufXSize),
751
0
                                   static_cast<int>(nBufYSize), eBufType,
752
0
                                   nPixelSpace, nLineSpace, &sExtraArg);
753
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
754
755
//! @cond Doxygen_Suppress
756
757
#define INSTANTIATE_READ_RASTER(T)                                             \
758
    template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
759
        T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
760
        double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
761
        GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
762
        void *pProgressData) const;
763
764
INSTANTIATE_READ_RASTER(uint8_t)
765
INSTANTIATE_READ_RASTER(int8_t)
766
INSTANTIATE_READ_RASTER(uint16_t)
767
INSTANTIATE_READ_RASTER(int16_t)
768
INSTANTIATE_READ_RASTER(uint32_t)
769
INSTANTIATE_READ_RASTER(int32_t)
770
INSTANTIATE_READ_RASTER(uint64_t)
771
INSTANTIATE_READ_RASTER(int64_t)
772
INSTANTIATE_READ_RASTER(GFloat16)
773
INSTANTIATE_READ_RASTER(float)
774
INSTANTIATE_READ_RASTER(double)
775
// Not allowed by C++ standard
776
// INSTANTIATE_READ_RASTER(std::complex<int16_t>)
777
// INSTANTIATE_READ_RASTER(std::complex<int32_t>)
778
INSTANTIATE_READ_RASTER(std::complex<float>)
779
INSTANTIATE_READ_RASTER(std::complex<double>)
780
781
//! @endcond
782
783
/************************************************************************/
784
/*                           ReadRaster()                               */
785
/************************************************************************/
786
787
/** Read a region of image data for this band.
788
 *
789
 * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
790
 * for common use cases, like reading a whole band.
791
 * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
792
 * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
793
 * float, double, std::complex<float|double>.
794
 *
795
 * To read a whole band (assuming it fits into memory), as a vector of double:
796
 *
797
\code
798
 std::vector<double> myArray;
799
 if (poBand->ReadRaster(myArray) == CE_None)
800
 {
801
     // do something
802
 }
803
\endcode
804
 *
805
 * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
806
 *
807
\code{.cpp}
808
 std::vector<double> myArray;
809
 if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
810
 {
811
     // do something
812
 }
813
\endcode
814
 *
815
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
816
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
817
 * instance of this dataset) concurrently from several threads.
818
 *
819
 * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
820
 * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
821
 * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
822
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
823
 * Or use nLineSpace and a possibly shifted pData value.
824
 *
825
 * @param[out] vData The vector into which the data should be written.
826
 * The vector will be resized, if needed, to contain at least nBufXSize *
827
 * nBufYSize values. The values in the vector are organized in left to right,
828
 * top to bottom pixel order, and fully packed.
829
 * The type of the vector does not need to be the one of GetDataType(). The
830
 * method will perform data type translation (with potential rounding, clamping)
831
 * if needed.
832
 *
833
 * @param dfXOff The pixel offset to the top left corner of the region
834
 * of the band to be accessed. This would be zero to start from the left side.
835
 * Defaults to 0.
836
 *
837
 * @param dfYOff The line offset to the top left corner of the region
838
 * of the band to be accessed. This would be zero to start from the top.
839
 * Defaults to 0.
840
 *
841
 * @param dfXSize The width of the region of the band to be accessed in pixels.
842
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
843
 * dfXSize is set to the band width.
844
 *
845
 * @param dfYSize The height of the region of the band to be accessed in lines.
846
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
847
 * dfYSize is set to the band height.
848
 *
849
 * @param nBufXSize the width of the buffer image into which the desired region
850
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
851
 * then nBufXSize is initialized with dfXSize.
852
 *
853
 * @param nBufYSize the height of the buffer image into which the desired region
854
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
855
 * then nBufYSize is initialized with dfYSize.
856
 *
857
 * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
858
 *
859
 * @param pfnProgress Progress function. May be nullptr.
860
 *
861
 * @param pProgressData User data of pfnProgress. May be nullptr.
862
 *
863
 * @return CE_Failure if the access fails, otherwise CE_None.
864
 *
865
 * @see GDALRasterBand::RasterIO()
866
 * @since GDAL 3.10
867
 */
868
template <class T>
869
CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
870
                                  double dfYOff, double dfXSize, double dfYSize,
871
                                  size_t nBufXSize, size_t nBufYSize,
872
                                  GDALRIOResampleAlg eResampleAlg,
873
                                  GDALProgressFunc pfnProgress,
874
                                  void *pProgressData) const
875
0
{
876
0
    if (((nBufXSize | nBufYSize) >> 31) != 0)
877
0
    {
878
0
        return CE_Failure;
879
0
    }
880
881
0
    if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
882
0
    {
883
0
        dfXSize = nRasterXSize;
884
0
        dfYSize = nRasterYSize;
885
0
    }
886
0
    else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
887
0
             !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
888
0
             !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
889
0
             dfYOff + dfYSize > INT_MAX)
890
0
    {
891
0
        return CE_Failure;
892
0
    }
893
894
0
    GDALRasterIOExtraArg sExtraArg;
895
0
    sExtraArg.nVersion = 1;
896
0
    sExtraArg.eResampleAlg = eResampleAlg;
897
0
    sExtraArg.pfnProgress = pfnProgress;
898
0
    sExtraArg.pProgressData = pProgressData;
899
0
    sExtraArg.bFloatingPointWindowValidity = true;
900
0
    sExtraArg.dfXOff = dfXOff;
901
0
    sExtraArg.dfYOff = dfYOff;
902
0
    sExtraArg.dfXSize = dfXSize;
903
0
    sExtraArg.dfYSize = dfYSize;
904
0
    const int nXOff = static_cast<int>(dfXOff);
905
0
    const int nYOff = static_cast<int>(dfYOff);
906
0
    const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
907
0
    const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
908
0
    if (nBufXSize == 0 && nBufYSize == 0)
909
0
    {
910
0
        if (static_cast<int>(dfXSize) == dfXSize &&
911
0
            static_cast<int>(dfYSize) == dfYSize)
912
0
        {
913
0
            nBufXSize = static_cast<int>(dfXSize);
914
0
            nBufYSize = static_cast<int>(dfYSize);
915
0
        }
916
0
        else
917
0
        {
918
0
            CPLError(CE_Failure, CPLE_AppDefined,
919
0
                     "nBufXSize and nBufYSize must be provided if "
920
0
                     "dfXSize or dfYSize is not an integer value");
921
0
            return CE_Failure;
922
0
        }
923
0
    }
924
0
    if (nBufXSize == 0 || nBufYSize == 0)
925
0
    {
926
0
        CPLDebug("GDAL",
927
0
                 "RasterIO() skipped for odd window or buffer size.\n"
928
0
                 "  Window = (%d,%d)x%dx%d\n"
929
0
                 "  Buffer = %dx%d\n",
930
0
                 nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
931
0
                 static_cast<int>(nBufYSize));
932
933
0
        return CE_None;
934
0
    }
935
936
    if constexpr (SIZEOF_VOIDP < 8)
937
    {
938
        if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
939
        {
940
            CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
941
            return CE_Failure;
942
        }
943
    }
944
945
0
    if (vData.size() < nBufXSize * nBufYSize)
946
0
    {
947
0
        try
948
0
        {
949
0
            vData.resize(nBufXSize * nBufYSize);
950
0
        }
951
0
        catch (const std::exception &)
952
0
        {
953
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
954
0
            return CE_Failure;
955
0
        }
956
0
    }
957
958
0
    constexpr GSpacing nPixelSpace = sizeof(T);
959
0
    const GSpacing nLineSpace = nPixelSpace * nBufXSize;
960
0
    constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
961
962
0
    GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
963
964
0
    return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
965
0
                                   vData.data(), static_cast<int>(nBufXSize),
966
0
                                   static_cast<int>(nBufYSize), eBufType,
967
0
                                   nPixelSpace, nLineSpace, &sExtraArg);
968
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
969
970
//! @cond Doxygen_Suppress
971
972
#define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
973
    template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
974
        std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
975
        double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
976
        GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
977
        void *pProgressData) const;
978
979
INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
980
INSTANTIATE_READ_RASTER_VECTOR(int8_t)
981
INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
982
INSTANTIATE_READ_RASTER_VECTOR(int16_t)
983
INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
984
INSTANTIATE_READ_RASTER_VECTOR(int32_t)
985
INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
986
INSTANTIATE_READ_RASTER_VECTOR(int64_t)
987
INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
988
INSTANTIATE_READ_RASTER_VECTOR(float)
989
INSTANTIATE_READ_RASTER_VECTOR(double)
990
// Not allowed by C++ standard
991
// INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
992
// INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
993
INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
994
INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
995
996
//! @endcond
997
998
/************************************************************************/
999
/*                             ReadBlock()                              */
1000
/************************************************************************/
1001
1002
/**
1003
 * \brief Read a block of image data efficiently.
1004
 *
1005
 * This method accesses a "natural" block from the raster band without
1006
 * resampling, or data type conversion.  For a more generalized, but
1007
 * potentially less efficient access use RasterIO().
1008
 *
1009
 * This method is the same as the C GDALReadBlock() function.
1010
 *
1011
 * See the GetLockedBlockRef() method for a way of accessing internally cached
1012
 * block oriented data without an extra copy into an application buffer.
1013
 *
1014
 * The following code would efficiently compute a histogram of eight bit
1015
 * raster data.  Note that the final block may be partial ... data beyond
1016
 * the edge of the underlying raster band in these edge blocks is of an
1017
 * undetermined value.
1018
 *
1019
\code{.cpp}
1020
 CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1021
1022
 {
1023
     memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1024
1025
     CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1026
1027
     int nXBlockSize, nYBlockSize;
1028
1029
     poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1030
     int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1031
     int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1032
1033
     GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1034
1035
     for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1036
     {
1037
         for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1038
         {
1039
             int        nXValid, nYValid;
1040
1041
             poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1042
1043
             // Compute the portion of the block that is valid
1044
             // for partial edge blocks.
1045
             poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1046
1047
             // Collect the histogram counts.
1048
             for( int iY = 0; iY < nYValid; iY++ )
1049
             {
1050
                 for( int iX = 0; iX < nXValid; iX++ )
1051
                 {
1052
                     panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1053
                 }
1054
             }
1055
         }
1056
     }
1057
 }
1058
\endcode
1059
 *
1060
 * @param nXBlockOff the horizontal block offset, with zero indicating
1061
 * the left most block, 1 the next block and so forth.
1062
 *
1063
 * @param nYBlockOff the vertical block offset, with zero indicating
1064
 * the top most block, 1 the next block and so forth.
1065
 *
1066
 * @param pImage the buffer into which the data will be read.  The buffer
1067
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1068
 * of type GetRasterDataType().
1069
 *
1070
 * @return CE_None on success or CE_Failure on an error.
1071
 */
1072
1073
CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1074
1075
0
{
1076
    /* -------------------------------------------------------------------- */
1077
    /*      Validate arguments.                                             */
1078
    /* -------------------------------------------------------------------- */
1079
0
    CPLAssert(pImage != nullptr);
1080
1081
0
    if (!InitBlockInfo())
1082
0
        return CE_Failure;
1083
1084
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1085
0
    {
1086
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1087
0
                    "Illegal nXBlockOff value (%d) in "
1088
0
                    "GDALRasterBand::ReadBlock()\n",
1089
0
                    nXBlockOff);
1090
1091
0
        return (CE_Failure);
1092
0
    }
1093
1094
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1095
0
    {
1096
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1097
0
                    "Illegal nYBlockOff value (%d) in "
1098
0
                    "GDALRasterBand::ReadBlock()\n",
1099
0
                    nYBlockOff);
1100
1101
0
        return (CE_Failure);
1102
0
    }
1103
1104
    /* -------------------------------------------------------------------- */
1105
    /*      Invoke underlying implementation method.                        */
1106
    /* -------------------------------------------------------------------- */
1107
1108
0
    int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1109
0
    CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1110
0
    if (bCallLeaveReadWrite)
1111
0
        LeaveReadWrite();
1112
0
    return eErr;
1113
0
}
1114
1115
/************************************************************************/
1116
/*                           GDALReadBlock()                            */
1117
/************************************************************************/
1118
1119
/**
1120
 * \brief Read a block of image data efficiently.
1121
 *
1122
 * @see GDALRasterBand::ReadBlock()
1123
 */
1124
1125
CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1126
                                 void *pData)
1127
1128
0
{
1129
0
    VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1130
1131
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1132
0
    return (poBand->ReadBlock(nXOff, nYOff, pData));
1133
0
}
1134
1135
/************************************************************************/
1136
/*                            IReadBlock()                             */
1137
/************************************************************************/
1138
1139
/** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1140
 * ) \brief Read a block of data.
1141
 *
1142
 * Default internal implementation ... to be overridden by
1143
 * subclasses that support reading.
1144
 * @param nBlockXOff Block X Offset
1145
 * @param nBlockYOff Block Y Offset
1146
 * @param pData Pixel buffer into which to place read data.
1147
 * @return CE_None on success or CE_Failure on an error.
1148
 */
1149
1150
/************************************************************************/
1151
/*                            IWriteBlock()                             */
1152
/************************************************************************/
1153
1154
/**
1155
 * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1156
 * Write a block of data.
1157
 *
1158
 * Default internal implementation ... to be overridden by
1159
 * subclasses that support writing.
1160
 * @param nBlockXOff Block X Offset
1161
 * @param nBlockYOff Block Y Offset
1162
 * @param pData Pixel buffer to write
1163
 * @return CE_None on success or CE_Failure on an error.
1164
 */
1165
1166
/**/
1167
/**/
1168
1169
CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1170
                                   void * /*pData*/)
1171
1172
0
{
1173
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1174
0
        ReportError(CE_Failure, CPLE_NotSupported,
1175
0
                    "WriteBlock() not supported for this dataset.");
1176
1177
0
    return (CE_Failure);
1178
0
}
1179
1180
/************************************************************************/
1181
/*                             WriteBlock()                             */
1182
/************************************************************************/
1183
1184
/**
1185
 * \brief Write a block of image data efficiently.
1186
 *
1187
 * This method accesses a "natural" block from the raster band without
1188
 * resampling, or data type conversion.  For a more generalized, but
1189
 * potentially less efficient access use RasterIO().
1190
 *
1191
 * This method is the same as the C GDALWriteBlock() function.
1192
 *
1193
 * See ReadBlock() for an example of block oriented data access.
1194
 *
1195
 * @param nXBlockOff the horizontal block offset, with zero indicating
1196
 * the left most block, 1 the next block and so forth.
1197
 *
1198
 * @param nYBlockOff the vertical block offset, with zero indicating
1199
 * the left most block, 1 the next block and so forth.
1200
 *
1201
 * @param pImage the buffer from which the data will be written.  The buffer
1202
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1203
 * of type GetRasterDataType(). Note that the content of the buffer might be
1204
 * temporarily modified during the execution of this method (and eventually
1205
 * restored back to its original content), so it is not safe to use a buffer
1206
 * stored in a read-only section of the calling program.
1207
 *
1208
 * @return CE_None on success or CE_Failure on an error.
1209
 */
1210
1211
CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1212
1213
0
{
1214
    /* -------------------------------------------------------------------- */
1215
    /*      Validate arguments.                                             */
1216
    /* -------------------------------------------------------------------- */
1217
0
    CPLAssert(pImage != nullptr);
1218
1219
0
    if (!InitBlockInfo())
1220
0
        return CE_Failure;
1221
1222
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1223
0
    {
1224
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1225
0
                    "Illegal nXBlockOff value (%d) in "
1226
0
                    "GDALRasterBand::WriteBlock()\n",
1227
0
                    nXBlockOff);
1228
1229
0
        return (CE_Failure);
1230
0
    }
1231
1232
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1233
0
    {
1234
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1235
0
                    "Illegal nYBlockOff value (%d) in "
1236
0
                    "GDALRasterBand::WriteBlock()\n",
1237
0
                    nYBlockOff);
1238
1239
0
        return (CE_Failure);
1240
0
    }
1241
1242
0
    if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1243
0
    {
1244
0
        return CE_Failure;
1245
0
    }
1246
1247
0
    if (eFlushBlockErr != CE_None)
1248
0
    {
1249
0
        ReportError(eFlushBlockErr, CPLE_AppDefined,
1250
0
                    "An error occurred while writing a dirty block "
1251
0
                    "from GDALRasterBand::WriteBlock");
1252
0
        CPLErr eErr = eFlushBlockErr;
1253
0
        eFlushBlockErr = CE_None;
1254
0
        return eErr;
1255
0
    }
1256
1257
    /* -------------------------------------------------------------------- */
1258
    /*      Invoke underlying implementation method.                        */
1259
    /* -------------------------------------------------------------------- */
1260
1261
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1262
0
    CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1263
0
    if (bCallLeaveReadWrite)
1264
0
        LeaveReadWrite();
1265
1266
0
    return eErr;
1267
0
}
1268
1269
/************************************************************************/
1270
/*                           GDALWriteBlock()                           */
1271
/************************************************************************/
1272
1273
/**
1274
 * \brief Write a block of image data efficiently.
1275
 *
1276
 * @see GDALRasterBand::WriteBlock()
1277
 */
1278
1279
CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1280
                                  void *pData)
1281
1282
0
{
1283
0
    VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1284
1285
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1286
0
    return (poBand->WriteBlock(nXOff, nYOff, pData));
1287
0
}
1288
1289
/************************************************************************/
1290
/*                   EmitErrorMessageIfWriteNotSupported()              */
1291
/************************************************************************/
1292
1293
/**
1294
 * Emit an error message if a write operation to this band is not supported.
1295
 *
1296
 * The base implementation will emit an error message if the access mode is
1297
 * read-only. Derived classes may implement it to provide a custom message.
1298
 *
1299
 * @param pszCaller Calling function.
1300
 * @return true if an error message has been emitted.
1301
 */
1302
bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1303
    const char *pszCaller) const
1304
0
{
1305
0
    if (eAccess == GA_ReadOnly)
1306
0
    {
1307
0
        ReportError(CE_Failure, CPLE_NoWriteAccess,
1308
0
                    "%s: attempt to write to dataset opened in read-only mode.",
1309
0
                    pszCaller);
1310
1311
0
        return true;
1312
0
    }
1313
0
    return false;
1314
0
}
1315
1316
/************************************************************************/
1317
/*                         GetActualBlockSize()                         */
1318
/************************************************************************/
1319
/**
1320
 * \brief Fetch the actual block size for a given block offset.
1321
 *
1322
 * Handles partial blocks at the edges of the raster and returns the true
1323
 * number of pixels
1324
 *
1325
 * @param nXBlockOff the horizontal block offset for which to calculate the
1326
 * number of valid pixels, with zero indicating the left most block, 1 the next
1327
 * block and so forth.
1328
 *
1329
 * @param nYBlockOff the vertical block offset, with zero indicating
1330
 * the top most block, 1 the next block and so forth.
1331
 *
1332
 * @param pnXValid pointer to an integer in which the number of valid pixels in
1333
 * the x direction will be stored
1334
 *
1335
 * @param pnYValid pointer to an integer in which the number of valid pixels in
1336
 * the y direction will be stored
1337
 *
1338
 * @return CE_None if the input parameters are valid, CE_Failure otherwise
1339
 *
1340
 */
1341
CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1342
                                          int *pnXValid, int *pnYValid) const
1343
0
{
1344
0
    if (nXBlockOff < 0 || nBlockXSize == 0 ||
1345
0
        nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1346
0
        nYBlockOff < 0 || nBlockYSize == 0 ||
1347
0
        nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1348
0
    {
1349
0
        return CE_Failure;
1350
0
    }
1351
1352
0
    const int nXPixelOff = nXBlockOff * nBlockXSize;
1353
0
    const int nYPixelOff = nYBlockOff * nBlockYSize;
1354
1355
0
    *pnXValid = nBlockXSize;
1356
0
    *pnYValid = nBlockYSize;
1357
1358
0
    if (nXPixelOff >= nRasterXSize - nBlockXSize)
1359
0
    {
1360
0
        *pnXValid = nRasterXSize - nXPixelOff;
1361
0
    }
1362
1363
0
    if (nYPixelOff >= nRasterYSize - nBlockYSize)
1364
0
    {
1365
0
        *pnYValid = nRasterYSize - nYPixelOff;
1366
0
    }
1367
1368
0
    return CE_None;
1369
0
}
1370
1371
/************************************************************************/
1372
/*                           GDALGetActualBlockSize()                   */
1373
/************************************************************************/
1374
1375
/**
1376
 * \brief Retrieve the actual block size for a given block offset.
1377
 *
1378
 * @see GDALRasterBand::GetActualBlockSize()
1379
 */
1380
1381
CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1382
                                          int nYBlockOff, int *pnXValid,
1383
                                          int *pnYValid)
1384
1385
0
{
1386
0
    VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1387
1388
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1389
0
    return (
1390
0
        poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1391
0
}
1392
1393
/************************************************************************/
1394
/*                     GetSuggestedBlockAccessPattern()                 */
1395
/************************************************************************/
1396
1397
/**
1398
 * \brief Return the suggested/most efficient access pattern to blocks
1399
 *        (for read operations).
1400
 *
1401
 * While all GDAL drivers have to expose a block size, not all can guarantee
1402
 * efficient random access (GSBAP_RANDOM) to any block.
1403
 * Some drivers for example decompress sequentially a compressed stream from
1404
 * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1405
 * case best performance will be achieved while reading blocks in that order.
1406
 * (accessing blocks in random access in such rasters typically causes the
1407
 * decoding to be re-initialized from the start if accessing blocks in
1408
 * a non-sequential order)
1409
 *
1410
 * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1411
 * returned by drivers that expose a somewhat artificial block size, because
1412
 * they can extract any part of a raster, but in a rather inefficient way.
1413
 *
1414
 * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1415
 * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1416
 * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1417
 * most efficient strategy is to read as many pixels as possible in the less
1418
 * RasterIO() operations.
1419
 *
1420
 * The return of this method is for example used to determine the swath size
1421
 * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1422
 *
1423
 * @since GDAL 3.6
1424
 */
1425
1426
GDALSuggestedBlockAccessPattern
1427
GDALRasterBand::GetSuggestedBlockAccessPattern() const
1428
0
{
1429
0
    return GSBAP_UNKNOWN;
1430
0
}
1431
1432
/************************************************************************/
1433
/*                         GetRasterDataType()                          */
1434
/************************************************************************/
1435
1436
/**
1437
 * \brief Fetch the pixel data type for this band.
1438
 *
1439
 * This method is the same as the C function GDALGetRasterDataType().
1440
 *
1441
 * @return the data type of pixels for this band.
1442
 */
1443
1444
GDALDataType GDALRasterBand::GetRasterDataType() const
1445
1446
0
{
1447
0
    return eDataType;
1448
0
}
1449
1450
/************************************************************************/
1451
/*                       GDALGetRasterDataType()                        */
1452
/************************************************************************/
1453
1454
/**
1455
 * \brief Fetch the pixel data type for this band.
1456
 *
1457
 * @see GDALRasterBand::GetRasterDataType()
1458
 */
1459
1460
GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1461
1462
0
{
1463
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1464
1465
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1466
0
    return poBand->GetRasterDataType();
1467
0
}
1468
1469
/************************************************************************/
1470
/*                            GetBlockSize()                            */
1471
/************************************************************************/
1472
1473
/**
1474
 * \brief Fetch the "natural" block size of this band.
1475
 *
1476
 * GDAL contains a concept of the natural block size of rasters so that
1477
 * applications can organized data access efficiently for some file formats.
1478
 * The natural block size is the block size that is most efficient for
1479
 * accessing the format.  For many formats this is simple a whole scanline
1480
 * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1481
 *
1482
 * However, for tiled images this will typically be the tile size.
1483
 *
1484
 * Note that the X and Y block sizes don't have to divide the image size
1485
 * evenly, meaning that right and bottom edge blocks may be incomplete.
1486
 * See ReadBlock() for an example of code dealing with these issues.
1487
 *
1488
 * This method is the same as the C function GDALGetBlockSize().
1489
 *
1490
 * @param pnXSize integer to put the X block size into or NULL.
1491
 *
1492
 * @param pnYSize integer to put the Y block size into or NULL.
1493
 */
1494
1495
void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1496
1497
0
{
1498
0
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
1499
0
    {
1500
0
        ReportError(CE_Failure, CPLE_AppDefined,
1501
0
                    "Invalid block dimension : %d * %d", nBlockXSize,
1502
0
                    nBlockYSize);
1503
0
        if (pnXSize != nullptr)
1504
0
            *pnXSize = 0;
1505
0
        if (pnYSize != nullptr)
1506
0
            *pnYSize = 0;
1507
0
    }
1508
0
    else
1509
0
    {
1510
0
        if (pnXSize != nullptr)
1511
0
            *pnXSize = nBlockXSize;
1512
0
        if (pnYSize != nullptr)
1513
0
            *pnYSize = nBlockYSize;
1514
0
    }
1515
0
}
1516
1517
/************************************************************************/
1518
/*                          GDALGetBlockSize()                          */
1519
/************************************************************************/
1520
1521
/**
1522
 * \brief Fetch the "natural" block size of this band.
1523
 *
1524
 * @see GDALRasterBand::GetBlockSize()
1525
 */
1526
1527
void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1528
                                  int *pnYSize)
1529
1530
0
{
1531
0
    VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1532
1533
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1534
0
    poBand->GetBlockSize(pnXSize, pnYSize);
1535
0
}
1536
1537
/************************************************************************/
1538
/*                           InitBlockInfo()                            */
1539
/************************************************************************/
1540
1541
//! @cond Doxygen_Suppress
1542
int GDALRasterBand::InitBlockInfo()
1543
1544
0
{
1545
0
    if (poBandBlockCache != nullptr)
1546
0
        return poBandBlockCache->IsInitOK();
1547
1548
    /* Do some validation of raster and block dimensions in case the driver */
1549
    /* would have neglected to do it itself */
1550
0
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
1551
0
    {
1552
0
        ReportError(CE_Failure, CPLE_AppDefined,
1553
0
                    "Invalid block dimension : %d * %d", nBlockXSize,
1554
0
                    nBlockYSize);
1555
0
        return FALSE;
1556
0
    }
1557
1558
0
    if (nRasterXSize <= 0 || nRasterYSize <= 0)
1559
0
    {
1560
0
        ReportError(CE_Failure, CPLE_AppDefined,
1561
0
                    "Invalid raster dimension : %d * %d", nRasterXSize,
1562
0
                    nRasterYSize);
1563
0
        return FALSE;
1564
0
    }
1565
1566
0
    const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1567
0
    if (nDataTypeSize == 0)
1568
0
    {
1569
0
        ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1570
0
        return FALSE;
1571
0
    }
1572
1573
#if SIZEOF_VOIDP == 4
1574
    if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1575
    {
1576
        /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1577
         * multiplication in other cases */
1578
        if (nBlockXSize > INT_MAX / nDataTypeSize ||
1579
            nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1580
        {
1581
            ReportError(CE_Failure, CPLE_NotSupported,
1582
                        "Too big block : %d * %d for 32-bit build", nBlockXSize,
1583
                        nBlockYSize);
1584
            return FALSE;
1585
        }
1586
    }
1587
#endif
1588
1589
0
    nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1590
0
    nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1591
1592
0
    const char *pszBlockStrategy =
1593
0
        CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1594
0
    bool bUseArray = true;
1595
0
    if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1596
0
    {
1597
0
        if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1598
0
                                   GDAL_OF_DEFAULT_BLOCK_ACCESS)
1599
0
        {
1600
0
            GUIntBig nBlockCount =
1601
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1602
0
            if (poDS != nullptr)
1603
0
                nBlockCount *= poDS->GetRasterCount();
1604
0
            bUseArray = (nBlockCount < 1024 * 1024);
1605
0
        }
1606
0
        else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1607
0
                 GDAL_OF_HASHSET_BLOCK_ACCESS)
1608
0
        {
1609
0
            bUseArray = false;
1610
0
        }
1611
0
    }
1612
0
    else if (EQUAL(pszBlockStrategy, "HASHSET"))
1613
0
        bUseArray = false;
1614
0
    else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1615
0
        CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1616
0
                 pszBlockStrategy);
1617
1618
0
    if (bUseArray)
1619
0
        poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1620
0
    else
1621
0
    {
1622
0
        if (nBand == 1)
1623
0
            CPLDebug("GDAL", "Use hashset band block cache");
1624
0
        poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1625
0
    }
1626
0
    if (poBandBlockCache == nullptr)
1627
0
        return FALSE;
1628
0
    return poBandBlockCache->Init();
1629
0
}
1630
1631
//! @endcond
1632
1633
/************************************************************************/
1634
/*                             FlushCache()                             */
1635
/************************************************************************/
1636
1637
/**
1638
 * \brief Flush raster data cache.
1639
 *
1640
 * This call will recover memory used to cache data blocks for this raster
1641
 * band, and ensure that new requests are referred to the underlying driver.
1642
 *
1643
 * This method is the same as the C function GDALFlushRasterCache().
1644
 *
1645
 * @param bAtClosing Whether this is called from a GDALDataset destructor
1646
 * @return CE_None on success.
1647
 */
1648
1649
CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1650
1651
0
{
1652
0
    if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1653
0
        poBandBlockCache)
1654
0
        poBandBlockCache->DisableDirtyBlockWriting();
1655
1656
0
    CPLErr eGlobalErr = eFlushBlockErr;
1657
1658
0
    if (eFlushBlockErr != CE_None)
1659
0
    {
1660
0
        ReportError(
1661
0
            eFlushBlockErr, CPLE_AppDefined,
1662
0
            "An error occurred while writing a dirty block from FlushCache");
1663
0
        eFlushBlockErr = CE_None;
1664
0
    }
1665
1666
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1667
0
        return eGlobalErr;
1668
1669
0
    return poBandBlockCache->FlushCache();
1670
0
}
1671
1672
/************************************************************************/
1673
/*                        GDALFlushRasterCache()                        */
1674
/************************************************************************/
1675
1676
/**
1677
 * \brief Flush raster data cache.
1678
 *
1679
 * @see GDALRasterBand::FlushCache()
1680
 */
1681
1682
CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1683
1684
0
{
1685
0
    VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1686
1687
0
    return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1688
0
}
1689
1690
/************************************************************************/
1691
/*                             DropCache()                              */
1692
/************************************************************************/
1693
1694
/**
1695
* \brief Drop raster data cache : data in cache will be lost.
1696
*
1697
* This call will recover memory used to cache data blocks for this raster
1698
* band, and ensure that new requests are referred to the underlying driver.
1699
*
1700
* This method is the same as the C function GDALDropRasterCache().
1701
*
1702
* @return CE_None on success.
1703
* @since 3.9
1704
*/
1705
1706
CPLErr GDALRasterBand::DropCache()
1707
1708
0
{
1709
0
    CPLErr result = CE_None;
1710
1711
0
    if (poBandBlockCache)
1712
0
        poBandBlockCache->DisableDirtyBlockWriting();
1713
1714
0
    CPLErr eGlobalErr = eFlushBlockErr;
1715
1716
0
    if (eFlushBlockErr != CE_None)
1717
0
    {
1718
0
        ReportError(
1719
0
            eFlushBlockErr, CPLE_AppDefined,
1720
0
            "An error occurred while writing a dirty block from DropCache");
1721
0
        eFlushBlockErr = CE_None;
1722
0
    }
1723
1724
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1725
0
        result = eGlobalErr;
1726
0
    else
1727
0
        result = poBandBlockCache->FlushCache();
1728
1729
0
    if (poBandBlockCache)
1730
0
        poBandBlockCache->EnableDirtyBlockWriting();
1731
1732
0
    return result;
1733
0
}
1734
1735
/************************************************************************/
1736
/*                        GDALDropRasterCache()                         */
1737
/************************************************************************/
1738
1739
/**
1740
* \brief Drop raster data cache.
1741
*
1742
* @see GDALRasterBand::DropCache()
1743
* @since 3.9
1744
*/
1745
1746
CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1747
1748
0
{
1749
0
    VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1750
1751
0
    return GDALRasterBand::FromHandle(hBand)->DropCache();
1752
0
}
1753
1754
/************************************************************************/
1755
/*                        UnreferenceBlock()                            */
1756
/*                                                                      */
1757
/*      Unreference the block from our array of blocks                  */
1758
/*      This method should only be called by                            */
1759
/*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1760
/*      the block cache mutex)                                          */
1761
/************************************************************************/
1762
1763
CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1764
0
{
1765
#ifdef notdef
1766
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1767
    {
1768
        if (poBandBlockCache == nullptr)
1769
            printf("poBandBlockCache == NULL\n"); /*ok*/
1770
        else
1771
            printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1772
        printf("caller = %s\n", pszCaller);            /*ok*/
1773
        printf("GDALRasterBand: %p\n", this);          /*ok*/
1774
        printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
1775
        printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
1776
        printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
1777
        printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
1778
        printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
1779
        poBlock->DumpBlock();
1780
        if (GetDataset() != nullptr)
1781
            printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1782
        GDALRasterBlock::Verify();
1783
        abort();
1784
    }
1785
#endif
1786
0
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1787
0
    return poBandBlockCache->UnreferenceBlock(poBlock);
1788
0
}
1789
1790
/************************************************************************/
1791
/*                        AddBlockToFreeList()                          */
1792
/*                                                                      */
1793
/*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
1794
/*      finished with a block about to be free'd, they pass it to that  */
1795
/*      method.                                                         */
1796
/************************************************************************/
1797
1798
//! @cond Doxygen_Suppress
1799
void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1800
0
{
1801
0
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1802
0
    return poBandBlockCache->AddBlockToFreeList(poBlock);
1803
0
}
1804
1805
//! @endcond
1806
1807
/************************************************************************/
1808
/*                           HasDirtyBlocks()                           */
1809
/************************************************************************/
1810
1811
//! @cond Doxygen_Suppress
1812
bool GDALRasterBand::HasDirtyBlocks() const
1813
0
{
1814
0
    return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
1815
0
}
1816
1817
//! @endcond
1818
1819
/************************************************************************/
1820
/*                             FlushBlock()                             */
1821
/************************************************************************/
1822
1823
/** Flush a block out of the block cache.
1824
 * @param nXBlockOff block x offset
1825
 * @param nYBlockOff blocky offset
1826
 * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1827
 * @return CE_None in case of success, an error code otherwise.
1828
 */
1829
CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1830
                                  int bWriteDirtyBlock)
1831
1832
0
{
1833
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1834
0
        return (CE_Failure);
1835
1836
    /* -------------------------------------------------------------------- */
1837
    /*      Validate the request                                            */
1838
    /* -------------------------------------------------------------------- */
1839
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1840
0
    {
1841
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1842
0
                    "Illegal nBlockXOff value (%d) in "
1843
0
                    "GDALRasterBand::FlushBlock()\n",
1844
0
                    nXBlockOff);
1845
1846
0
        return (CE_Failure);
1847
0
    }
1848
1849
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1850
0
    {
1851
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1852
0
                    "Illegal nBlockYOff value (%d) in "
1853
0
                    "GDALRasterBand::FlushBlock()\n",
1854
0
                    nYBlockOff);
1855
1856
0
        return (CE_Failure);
1857
0
    }
1858
1859
0
    return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1860
0
                                        bWriteDirtyBlock);
1861
0
}
1862
1863
/************************************************************************/
1864
/*                        TryGetLockedBlockRef()                        */
1865
/************************************************************************/
1866
1867
/**
1868
 * \brief Try fetching block ref.
1869
 *
1870
 * This method will returned the requested block (locked) if it is already
1871
 * in the block cache for the layer.  If not, nullptr is returned.
1872
 *
1873
 * If a non-NULL value is returned, then a lock for the block will have been
1874
 * acquired on behalf of the caller.  It is absolutely imperative that the
1875
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1876
 * severe problems may result.
1877
 *
1878
 * @param nXBlockOff the horizontal block offset, with zero indicating
1879
 * the left most block, 1 the next block and so forth.
1880
 *
1881
 * @param nYBlockOff the vertical block offset, with zero indicating
1882
 * the top most block, 1 the next block and so forth.
1883
 *
1884
 * @return NULL if block not available, or locked block pointer.
1885
 */
1886
1887
GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1888
                                                      int nYBlockOff)
1889
1890
0
{
1891
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1892
0
        return nullptr;
1893
1894
    /* -------------------------------------------------------------------- */
1895
    /*      Validate the request                                            */
1896
    /* -------------------------------------------------------------------- */
1897
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1898
0
    {
1899
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1900
0
                    "Illegal nBlockXOff value (%d) in "
1901
0
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1902
0
                    nXBlockOff);
1903
1904
0
        return (nullptr);
1905
0
    }
1906
1907
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1908
0
    {
1909
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1910
0
                    "Illegal nBlockYOff value (%d) in "
1911
0
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1912
0
                    nYBlockOff);
1913
1914
0
        return (nullptr);
1915
0
    }
1916
1917
0
    return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1918
0
}
1919
1920
/************************************************************************/
1921
/*                         GetLockedBlockRef()                          */
1922
/************************************************************************/
1923
1924
/**
1925
 * \brief Fetch a pointer to an internally cached raster block.
1926
 *
1927
 * This method will returned the requested block (locked) if it is already
1928
 * in the block cache for the layer.  If not, the block will be read from
1929
 * the driver, and placed in the layer block cached, then returned.  If an
1930
 * error occurs reading the block from the driver, a NULL value will be
1931
 * returned.
1932
 *
1933
 * If a non-NULL value is returned, then a lock for the block will have been
1934
 * acquired on behalf of the caller.  It is absolutely imperative that the
1935
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1936
 * severe problems may result.
1937
 *
1938
 * Note that calling GetLockedBlockRef() on a previously uncached band will
1939
 * enable caching.
1940
 *
1941
 * @param nXBlockOff the horizontal block offset, with zero indicating
1942
 * the left most block, 1 the next block and so forth.
1943
 *
1944
 * @param nYBlockOff the vertical block offset, with zero indicating
1945
 * the top most block, 1 the next block and so forth.
1946
 *
1947
 * @param bJustInitialize If TRUE the block will be allocated and initialized,
1948
 * but not actually read from the source.  This is useful when it will just
1949
 * be completely set and written back.
1950
 *
1951
 * @return pointer to the block object, or NULL on failure.
1952
 */
1953
1954
GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1955
                                                   int nYBlockOff,
1956
                                                   int bJustInitialize)
1957
1958
0
{
1959
    /* -------------------------------------------------------------------- */
1960
    /*      Try and fetch from cache.                                       */
1961
    /* -------------------------------------------------------------------- */
1962
0
    GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1963
1964
    /* -------------------------------------------------------------------- */
1965
    /*      If we didn't find it in our memory cache, instantiate a         */
1966
    /*      block (potentially load from disk) and "adopt" it into the      */
1967
    /*      cache.                                                          */
1968
    /* -------------------------------------------------------------------- */
1969
0
    if (poBlock == nullptr)
1970
0
    {
1971
0
        if (!InitBlockInfo())
1972
0
            return (nullptr);
1973
1974
        /* --------------------------------------------------------------------
1975
         */
1976
        /*      Validate the request */
1977
        /* --------------------------------------------------------------------
1978
         */
1979
0
        if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1980
0
        {
1981
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1982
0
                        "Illegal nBlockXOff value (%d) in "
1983
0
                        "GDALRasterBand::GetLockedBlockRef()\n",
1984
0
                        nXBlockOff);
1985
1986
0
            return (nullptr);
1987
0
        }
1988
1989
0
        if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1990
0
        {
1991
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1992
0
                        "Illegal nBlockYOff value (%d) in "
1993
0
                        "GDALRasterBand::GetLockedBlockRef()\n",
1994
0
                        nYBlockOff);
1995
1996
0
            return (nullptr);
1997
0
        }
1998
1999
0
        poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2000
0
        if (poBlock == nullptr)
2001
0
            return nullptr;
2002
2003
0
        poBlock->AddLock();
2004
2005
        /* We need to temporarily drop the read-write lock in the following */
2006
        /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
2007
         */
2008
        /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
2009
        /* block cache fills, T1 might need to flush dirty blocks of D2 in the
2010
         */
2011
        /* below Internalize(), which will cause GDALRasterBlock::Write() to be
2012
         */
2013
        /* called and attempt at taking the lock on T2 (already taken).
2014
         * Similarly */
2015
        /* for T2 with D1, hence a deadlock situation (#6163) */
2016
        /* But this may open the door to other problems... */
2017
0
        if (poDS)
2018
0
            poDS->TemporarilyDropReadWriteLock();
2019
        /* allocate data space */
2020
0
        CPLErr eErr = poBlock->Internalize();
2021
0
        if (poDS)
2022
0
            poDS->ReacquireReadWriteLock();
2023
0
        if (eErr != CE_None)
2024
0
        {
2025
0
            poBlock->DropLock();
2026
0
            delete poBlock;
2027
0
            return nullptr;
2028
0
        }
2029
2030
0
        if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2031
0
        {
2032
0
            poBlock->DropLock();
2033
0
            delete poBlock;
2034
0
            return nullptr;
2035
0
        }
2036
2037
0
        if (!bJustInitialize)
2038
0
        {
2039
0
            const GUInt32 nErrorCounter = CPLGetErrorCounter();
2040
0
            int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2041
0
            eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2042
0
            if (bCallLeaveReadWrite)
2043
0
                LeaveReadWrite();
2044
0
            if (eErr != CE_None)
2045
0
            {
2046
0
                poBlock->DropLock();
2047
0
                FlushBlock(nXBlockOff, nYBlockOff);
2048
0
                ReportError(CE_Failure, CPLE_AppDefined,
2049
0
                            "IReadBlock failed at X offset %d, Y offset %d%s",
2050
0
                            nXBlockOff, nYBlockOff,
2051
0
                            (nErrorCounter != CPLGetErrorCounter())
2052
0
                                ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2053
0
                                : "");
2054
0
                return nullptr;
2055
0
            }
2056
2057
0
            nBlockReads++;
2058
0
            if (static_cast<GIntBig>(nBlockReads) ==
2059
0
                    static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2060
0
                        1 &&
2061
0
                nBand == 1 && poDS != nullptr)
2062
0
            {
2063
0
                CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2064
0
                         poDS->GetDescription());
2065
0
            }
2066
0
        }
2067
0
    }
2068
2069
0
    return poBlock;
2070
0
}
2071
2072
/************************************************************************/
2073
/*                               Fill()                                 */
2074
/************************************************************************/
2075
2076
/**
2077
 * \brief Fill this band with a constant value.
2078
 *
2079
 * GDAL makes no guarantees
2080
 * about what values pixels in newly created files are set to, so this
2081
 * method can be used to clear a band to a specified "default" value.
2082
 * The fill value is passed in as a double but this will be converted
2083
 * to the underlying type before writing to the file. An optional
2084
 * second argument allows the imaginary component of a complex
2085
 * constant value to be specified.
2086
 *
2087
 * This method is the same as the C function GDALFillRaster().
2088
 *
2089
 * @param dfRealValue Real component of fill value
2090
 * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2091
 *
2092
 * @return CE_Failure if the write fails, otherwise CE_None
2093
 */
2094
CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2095
0
{
2096
2097
    // General approach is to construct a source block of the file's
2098
    // native type containing the appropriate value and then copy this
2099
    // to each block in the image via the RasterBlock cache. Using
2100
    // the cache means we avoid file I/O if it is not necessary, at the
2101
    // expense of some extra memcpy's (since we write to the
2102
    // RasterBlock cache, which is then at some point written to the
2103
    // underlying file, rather than simply directly to the underlying
2104
    // file.)
2105
2106
    // Check we can write to the file.
2107
0
    if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2108
0
    {
2109
0
        return CE_Failure;
2110
0
    }
2111
2112
    // Make sure block parameters are set.
2113
0
    if (!InitBlockInfo())
2114
0
        return CE_Failure;
2115
2116
    // Allocate the source block.
2117
0
    auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2118
0
    int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2119
0
    auto blockByteSize = blockSize * elementSize;
2120
0
    unsigned char *srcBlock =
2121
0
        static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2122
0
    if (srcBlock == nullptr)
2123
0
    {
2124
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
2125
0
                    "GDALRasterBand::Fill(): Out of memory "
2126
0
                    "allocating " CPL_FRMT_GUIB " bytes.\n",
2127
0
                    static_cast<GUIntBig>(blockByteSize));
2128
0
        return CE_Failure;
2129
0
    }
2130
2131
    // Initialize the source block.
2132
0
    double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2133
0
    GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2134
0
                    elementSize, blockSize);
2135
2136
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2137
2138
    // Write block to block cache
2139
0
    for (int j = 0; j < nBlocksPerColumn; ++j)
2140
0
    {
2141
0
        for (int i = 0; i < nBlocksPerRow; ++i)
2142
0
        {
2143
0
            GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2144
0
            if (destBlock == nullptr)
2145
0
            {
2146
0
                ReportError(CE_Failure, CPLE_OutOfMemory,
2147
0
                            "GDALRasterBand::Fill(): Error "
2148
0
                            "while retrieving cache block.");
2149
0
                VSIFree(srcBlock);
2150
0
                return CE_Failure;
2151
0
            }
2152
0
            memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2153
0
            destBlock->MarkDirty();
2154
0
            destBlock->DropLock();
2155
0
        }
2156
0
    }
2157
2158
0
    if (bCallLeaveReadWrite)
2159
0
        LeaveReadWrite();
2160
2161
    // Free up the source block
2162
0
    VSIFree(srcBlock);
2163
2164
0
    return CE_None;
2165
0
}
2166
2167
/************************************************************************/
2168
/*                         GDALFillRaster()                             */
2169
/************************************************************************/
2170
2171
/**
2172
 * \brief Fill this band with a constant value.
2173
 *
2174
 * @see GDALRasterBand::Fill()
2175
 */
2176
CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2177
                                  double dfImaginaryValue)
2178
0
{
2179
0
    VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2180
2181
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2182
0
    return poBand->Fill(dfRealValue, dfImaginaryValue);
2183
0
}
2184
2185
/************************************************************************/
2186
/*                             GetAccess()                              */
2187
/************************************************************************/
2188
2189
/**
2190
 * \brief Find out if we have update permission for this band.
2191
 *
2192
 * This method is the same as the C function GDALGetRasterAccess().
2193
 *
2194
 * @return Either GA_Update or GA_ReadOnly.
2195
 */
2196
2197
GDALAccess GDALRasterBand::GetAccess()
2198
2199
0
{
2200
0
    return eAccess;
2201
0
}
2202
2203
/************************************************************************/
2204
/*                        GDALGetRasterAccess()                         */
2205
/************************************************************************/
2206
2207
/**
2208
 * \brief Find out if we have update permission for this band.
2209
 *
2210
 * @see GDALRasterBand::GetAccess()
2211
 */
2212
2213
GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2214
2215
0
{
2216
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2217
2218
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2219
0
    return poBand->GetAccess();
2220
0
}
2221
2222
/************************************************************************/
2223
/*                          GetCategoryNames()                          */
2224
/************************************************************************/
2225
2226
/**
2227
 * \brief Fetch the list of category names for this raster.
2228
 *
2229
 * The return list is a "StringList" in the sense of the CPL functions.
2230
 * That is a NULL terminated array of strings.  Raster values without
2231
 * associated names will have an empty string in the returned list.  The
2232
 * first entry in the list is for raster values of zero, and so on.
2233
 *
2234
 * The returned stringlist should not be altered or freed by the application.
2235
 * It may change on the next GDAL call, so please copy it if it is needed
2236
 * for any period of time.
2237
 *
2238
 * This method is the same as the C function GDALGetRasterCategoryNames().
2239
 *
2240
 * @return list of names, or NULL if none.
2241
 */
2242
2243
char **GDALRasterBand::GetCategoryNames()
2244
2245
0
{
2246
0
    return nullptr;
2247
0
}
2248
2249
/************************************************************************/
2250
/*                     GDALGetRasterCategoryNames()                     */
2251
/************************************************************************/
2252
2253
/**
2254
 * \brief Fetch the list of category names for this raster.
2255
 *
2256
 * @see GDALRasterBand::GetCategoryNames()
2257
 */
2258
2259
char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2260
2261
0
{
2262
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2263
2264
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2265
0
    return poBand->GetCategoryNames();
2266
0
}
2267
2268
/************************************************************************/
2269
/*                          SetCategoryNames()                          */
2270
/************************************************************************/
2271
2272
/**
2273
 * \fn GDALRasterBand::SetCategoryNames(char**)
2274
 * \brief Set the category names for this band.
2275
 *
2276
 * See the GetCategoryNames() method for more on the interpretation of
2277
 * category names.
2278
 *
2279
 * This method is the same as the C function GDALSetRasterCategoryNames().
2280
 *
2281
 * @param papszNames the NULL terminated StringList of category names.  May
2282
 * be NULL to just clear the existing list.
2283
 *
2284
 * @return CE_None on success of CE_Failure on failure.  If unsupported
2285
 * by the driver CE_Failure is returned, but no error message is reported.
2286
 */
2287
2288
/**/
2289
/**/
2290
2291
CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2292
0
{
2293
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2294
0
        ReportError(CE_Failure, CPLE_NotSupported,
2295
0
                    "SetCategoryNames() not supported for this dataset.");
2296
2297
0
    return CE_Failure;
2298
0
}
2299
2300
/************************************************************************/
2301
/*                        GDALSetCategoryNames()                        */
2302
/************************************************************************/
2303
2304
/**
2305
 * \brief Set the category names for this band.
2306
 *
2307
 * @see GDALRasterBand::SetCategoryNames()
2308
 */
2309
2310
CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2311
                                              CSLConstList papszNames)
2312
2313
0
{
2314
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2315
2316
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2317
0
    return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2318
0
}
2319
2320
/************************************************************************/
2321
/*                           GetNoDataValue()                           */
2322
/************************************************************************/
2323
2324
/**
2325
 * \brief Fetch the no data value for this band.
2326
 *
2327
 * If there is no out of data value, an out of range value will generally
2328
 * be returned.  The no data value for a band is generally a special marker
2329
 * value used to mark pixels that are not valid data.  Such pixels should
2330
 * generally not be displayed, nor contribute to analysis operations.
2331
 *
2332
 * The no data value returned is 'raw', meaning that it has no offset and
2333
 * scale applied.
2334
 *
2335
 * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2336
 * lossy if the nodata value cannot exactly been represented by a double.
2337
 * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2338
 *
2339
 * This method is the same as the C function GDALGetRasterNoDataValue().
2340
 *
2341
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2342
 * is actually associated with this layer.  May be NULL (default).
2343
 *
2344
 * @return the nodata value for this band.
2345
 */
2346
2347
double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2348
2349
0
{
2350
0
    if (pbSuccess != nullptr)
2351
0
        *pbSuccess = FALSE;
2352
2353
0
    return -1e10;
2354
0
}
2355
2356
/************************************************************************/
2357
/*                      GDALGetRasterNoDataValue()                      */
2358
/************************************************************************/
2359
2360
/**
2361
 * \brief Fetch the no data value for this band.
2362
 *
2363
 * @see GDALRasterBand::GetNoDataValue()
2364
 */
2365
2366
double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2367
                                            int *pbSuccess)
2368
2369
0
{
2370
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2371
2372
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2373
0
    return poBand->GetNoDataValue(pbSuccess);
2374
0
}
2375
2376
/************************************************************************/
2377
/*                       GetNoDataValueAsInt64()                        */
2378
/************************************************************************/
2379
2380
/**
2381
 * \brief Fetch the no data value for this band.
2382
 *
2383
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2384
 *
2385
 * If there is no out of data value, an out of range value will generally
2386
 * be returned.  The no data value for a band is generally a special marker
2387
 * value used to mark pixels that are not valid data.  Such pixels should
2388
 * generally not be displayed, nor contribute to analysis operations.
2389
 *
2390
 * The no data value returned is 'raw', meaning that it has no offset and
2391
 * scale applied.
2392
 *
2393
 * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2394
 *
2395
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2396
 * is actually associated with this layer.  May be NULL (default).
2397
 *
2398
 * @return the nodata value for this band.
2399
 *
2400
 * @since GDAL 3.5
2401
 */
2402
2403
int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2404
2405
0
{
2406
0
    if (pbSuccess != nullptr)
2407
0
        *pbSuccess = FALSE;
2408
2409
0
    return std::numeric_limits<int64_t>::min();
2410
0
}
2411
2412
/************************************************************************/
2413
/*                   GDALGetRasterNoDataValueAsInt64()                  */
2414
/************************************************************************/
2415
2416
/**
2417
 * \brief Fetch the no data value for this band.
2418
 *
2419
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2420
 *
2421
 * @see GDALRasterBand::GetNoDataValueAsInt64()
2422
 *
2423
 * @since GDAL 3.5
2424
 */
2425
2426
int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2427
                                                    int *pbSuccess)
2428
2429
0
{
2430
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2431
0
                      std::numeric_limits<int64_t>::min());
2432
2433
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2434
0
    return poBand->GetNoDataValueAsInt64(pbSuccess);
2435
0
}
2436
2437
/************************************************************************/
2438
/*                       GetNoDataValueAsUInt64()                        */
2439
/************************************************************************/
2440
2441
/**
2442
 * \brief Fetch the no data value for this band.
2443
 *
2444
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2445
 *
2446
 * If there is no out of data value, an out of range value will generally
2447
 * be returned.  The no data value for a band is generally a special marker
2448
 * value used to mark pixels that are not valid data.  Such pixels should
2449
 * generally not be displayed, nor contribute to analysis operations.
2450
 *
2451
 * The no data value returned is 'raw', meaning that it has no offset and
2452
 * scale applied.
2453
 *
2454
 * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2455
 *
2456
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2457
 * is actually associated with this layer.  May be NULL (default).
2458
 *
2459
 * @return the nodata value for this band.
2460
 *
2461
 * @since GDAL 3.5
2462
 */
2463
2464
uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2465
2466
0
{
2467
0
    if (pbSuccess != nullptr)
2468
0
        *pbSuccess = FALSE;
2469
2470
0
    return std::numeric_limits<uint64_t>::max();
2471
0
}
2472
2473
/************************************************************************/
2474
/*                   GDALGetRasterNoDataValueAsUInt64()                  */
2475
/************************************************************************/
2476
2477
/**
2478
 * \brief Fetch the no data value for this band.
2479
 *
2480
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2481
 *
2482
 * @see GDALRasterBand::GetNoDataValueAsUInt64()
2483
 *
2484
 * @since GDAL 3.5
2485
 */
2486
2487
uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2488
                                                      int *pbSuccess)
2489
2490
0
{
2491
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2492
0
                      std::numeric_limits<uint64_t>::max());
2493
2494
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2495
0
    return poBand->GetNoDataValueAsUInt64(pbSuccess);
2496
0
}
2497
2498
/************************************************************************/
2499
/*                        SetNoDataValueAsString()                      */
2500
/************************************************************************/
2501
2502
/**
2503
 * \brief Set the no data value for this band.
2504
 *
2505
 * Depending on drivers, changing the no data value may or may not have an
2506
 * effect on the pixel values of a raster that has just been created. It is
2507
 * thus advised to explicitly called Fill() if the intent is to initialize
2508
 * the raster to the nodata value.
2509
 * In any case, changing an existing no data value, when one already exists and
2510
 * the dataset exists or has been initialized, has no effect on the pixel whose
2511
 * value matched the previous nodata value.
2512
 *
2513
 * To clear the nodata value, use DeleteNoDataValue().
2514
 *
2515
 * @param pszNoData the value to set.
2516
 * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2517
 *             If the value cannot be exactly represented on the output data
2518
 *             type, *pbCannotBeExactlyRepresented will be set to true.
2519
 *
2520
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2521
 * by the driver, CE_Failure is returned but no error message will have
2522
 * been emitted.
2523
 *
2524
 * @since 3.11
2525
 */
2526
2527
CPLErr
2528
GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2529
                                       bool *pbCannotBeExactlyRepresented)
2530
0
{
2531
0
    if (pbCannotBeExactlyRepresented)
2532
0
        *pbCannotBeExactlyRepresented = false;
2533
0
    if (eDataType == GDT_Int64)
2534
0
    {
2535
0
        if (strchr(pszNoData, '.') ||
2536
0
            CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2537
0
        {
2538
0
            char *endptr = nullptr;
2539
0
            const double dfVal = CPLStrtod(pszNoData, &endptr);
2540
0
            if (endptr == pszNoData + strlen(pszNoData) &&
2541
0
                GDALIsValueExactAs<int64_t>(dfVal))
2542
0
            {
2543
0
                return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2544
0
            }
2545
0
        }
2546
0
        else
2547
0
        {
2548
0
            try
2549
0
            {
2550
0
                const auto val = std::stoll(pszNoData);
2551
0
                return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2552
0
            }
2553
0
            catch (const std::exception &)
2554
0
            {
2555
0
            }
2556
0
        }
2557
0
    }
2558
0
    else if (eDataType == GDT_UInt64)
2559
0
    {
2560
0
        if (strchr(pszNoData, '.') ||
2561
0
            CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2562
0
        {
2563
0
            char *endptr = nullptr;
2564
0
            const double dfVal = CPLStrtod(pszNoData, &endptr);
2565
0
            if (endptr == pszNoData + strlen(pszNoData) &&
2566
0
                GDALIsValueExactAs<uint64_t>(dfVal))
2567
0
            {
2568
0
                return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2569
0
            }
2570
0
        }
2571
0
        else
2572
0
        {
2573
0
            try
2574
0
            {
2575
0
                const auto val = std::stoull(pszNoData);
2576
0
                return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2577
0
            }
2578
0
            catch (const std::exception &)
2579
0
            {
2580
0
            }
2581
0
        }
2582
0
    }
2583
0
    else if (eDataType == GDT_Float32)
2584
0
    {
2585
0
        char *endptr = nullptr;
2586
0
        const float fVal = CPLStrtof(pszNoData, &endptr);
2587
0
        if (endptr == pszNoData + strlen(pszNoData))
2588
0
        {
2589
0
            return SetNoDataValue(double(fVal));
2590
0
        }
2591
0
    }
2592
0
    else
2593
0
    {
2594
0
        char *endptr = nullptr;
2595
0
        const double dfVal = CPLStrtod(pszNoData, &endptr);
2596
0
        if (endptr == pszNoData + strlen(pszNoData) &&
2597
0
            GDALIsValueExactAs(dfVal, eDataType))
2598
0
        {
2599
0
            return SetNoDataValue(dfVal);
2600
0
        }
2601
0
    }
2602
0
    if (pbCannotBeExactlyRepresented)
2603
0
        *pbCannotBeExactlyRepresented = true;
2604
0
    return CE_Failure;
2605
0
}
2606
2607
/************************************************************************/
2608
/*                           SetNoDataValue()                           */
2609
/************************************************************************/
2610
2611
/**
2612
 * \fn GDALRasterBand::SetNoDataValue(double)
2613
 * \brief Set the no data value for this band.
2614
 *
2615
 * Depending on drivers, changing the no data value may or may not have an
2616
 * effect on the pixel values of a raster that has just been created. It is
2617
 * thus advised to explicitly called Fill() if the intent is to initialize
2618
 * the raster to the nodata value.
2619
 * In any case, changing an existing no data value, when one already exists and
2620
 * the dataset exists or has been initialized, has no effect on the pixel whose
2621
 * value matched the previous nodata value.
2622
 *
2623
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2624
 * be represented by a double, use SetNoDataValueAsInt64() or
2625
 * SetNoDataValueAsUInt64() instead.
2626
 *
2627
 * To clear the nodata value, use DeleteNoDataValue().
2628
 *
2629
 * This method is the same as the C function GDALSetRasterNoDataValue().
2630
 *
2631
 * @param dfNoData the value to set.
2632
 *
2633
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2634
 * by the driver, CE_Failure is returned but no error message will have
2635
 * been emitted.
2636
 */
2637
2638
/**/
2639
/**/
2640
2641
CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2642
2643
0
{
2644
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2645
0
        ReportError(CE_Failure, CPLE_NotSupported,
2646
0
                    "SetNoDataValue() not supported for this dataset.");
2647
2648
0
    return CE_Failure;
2649
0
}
2650
2651
/************************************************************************/
2652
/*                         GDALSetRasterNoDataValue()                   */
2653
/************************************************************************/
2654
2655
/**
2656
 * \brief Set the no data value for this band.
2657
 *
2658
 * Depending on drivers, changing the no data value may or may not have an
2659
 * effect on the pixel values of a raster that has just been created. It is
2660
 * thus advised to explicitly called Fill() if the intent is to initialize
2661
 * the raster to the nodata value.
2662
 * In any case, changing an existing no data value, when one already exists and
2663
 * the dataset exists or has been initialized, has no effect on the pixel whose
2664
 * value matched the previous nodata value.
2665
 *
2666
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2667
 * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2668
 * GDALSetRasterNoDataValueAsUInt64() instead.
2669
 *
2670
 * @see GDALRasterBand::SetNoDataValue()
2671
 */
2672
2673
CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2674
                                            double dfValue)
2675
2676
0
{
2677
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2678
2679
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2680
0
    return poBand->SetNoDataValue(dfValue);
2681
0
}
2682
2683
/************************************************************************/
2684
/*                       SetNoDataValueAsInt64()                        */
2685
/************************************************************************/
2686
2687
/**
2688
 * \brief Set the no data value for this band.
2689
 *
2690
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2691
 *
2692
 * Depending on drivers, changing the no data value may or may not have an
2693
 * effect on the pixel values of a raster that has just been created. It is
2694
 * thus advised to explicitly called Fill() if the intent is to initialize
2695
 * the raster to the nodata value.
2696
 * In ay case, changing an existing no data value, when one already exists and
2697
 * the dataset exists or has been initialized, has no effect on the pixel whose
2698
 * value matched the previous nodata value.
2699
 *
2700
 * To clear the nodata value, use DeleteNoDataValue().
2701
 *
2702
 * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2703
 *
2704
 * @param nNoDataValue the value to set.
2705
 *
2706
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2707
 * by the driver, CE_Failure is returned but no error message will have
2708
 * been emitted.
2709
 *
2710
 * @since GDAL 3.5
2711
 */
2712
2713
CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2714
2715
0
{
2716
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2717
0
        ReportError(CE_Failure, CPLE_NotSupported,
2718
0
                    "SetNoDataValueAsInt64() not supported for this dataset.");
2719
2720
0
    return CE_Failure;
2721
0
}
2722
2723
/************************************************************************/
2724
/*                 GDALSetRasterNoDataValueAsInt64()                    */
2725
/************************************************************************/
2726
2727
/**
2728
 * \brief Set the no data value for this band.
2729
 *
2730
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2731
 *
2732
 * Depending on drivers, changing the no data value may or may not have an
2733
 * effect on the pixel values of a raster that has just been created. It is
2734
 * thus advised to explicitly called Fill() if the intent is to initialize
2735
 * the raster to the nodata value.
2736
 * In ay case, changing an existing no data value, when one already exists and
2737
 * the dataset exists or has been initialized, has no effect on the pixel whose
2738
 * value matched the previous nodata value.
2739
 *
2740
 * @see GDALRasterBand::SetNoDataValueAsInt64()
2741
 *
2742
 * @since GDAL 3.5
2743
 */
2744
2745
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2746
                                                   int64_t nValue)
2747
2748
0
{
2749
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2750
2751
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2752
0
    return poBand->SetNoDataValueAsInt64(nValue);
2753
0
}
2754
2755
/************************************************************************/
2756
/*                       SetNoDataValueAsUInt64()                       */
2757
/************************************************************************/
2758
2759
/**
2760
 * \brief Set the no data value for this band.
2761
 *
2762
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2763
 *
2764
 * Depending on drivers, changing the no data value may or may not have an
2765
 * effect on the pixel values of a raster that has just been created. It is
2766
 * thus advised to explicitly called Fill() if the intent is to initialize
2767
 * the raster to the nodata value.
2768
 * In ay case, changing an existing no data value, when one already exists and
2769
 * the dataset exists or has been initialized, has no effect on the pixel whose
2770
 * value matched the previous nodata value.
2771
 *
2772
 * To clear the nodata value, use DeleteNoDataValue().
2773
 *
2774
 * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2775
 *
2776
 * @param nNoDataValue the value to set.
2777
 *
2778
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2779
 * by the driver, CE_Failure is returned but no error message will have
2780
 * been emitted.
2781
 *
2782
 * @since GDAL 3.5
2783
 */
2784
2785
CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2786
2787
0
{
2788
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2789
0
        ReportError(CE_Failure, CPLE_NotSupported,
2790
0
                    "SetNoDataValueAsUInt64() not supported for this dataset.");
2791
2792
0
    return CE_Failure;
2793
0
}
2794
2795
/************************************************************************/
2796
/*                 GDALSetRasterNoDataValueAsUInt64()                    */
2797
/************************************************************************/
2798
2799
/**
2800
 * \brief Set the no data value for this band.
2801
 *
2802
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2803
 *
2804
 * Depending on drivers, changing the no data value may or may not have an
2805
 * effect on the pixel values of a raster that has just been created. It is
2806
 * thus advised to explicitly called Fill() if the intent is to initialize
2807
 * the raster to the nodata value.
2808
 * In ay case, changing an existing no data value, when one already exists and
2809
 * the dataset exists or has been initialized, has no effect on the pixel whose
2810
 * value matched the previous nodata value.
2811
 *
2812
 * @see GDALRasterBand::SetNoDataValueAsUInt64()
2813
 *
2814
 * @since GDAL 3.5
2815
 */
2816
2817
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2818
                                                    uint64_t nValue)
2819
2820
0
{
2821
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2822
2823
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2824
0
    return poBand->SetNoDataValueAsUInt64(nValue);
2825
0
}
2826
2827
/************************************************************************/
2828
/*                        DeleteNoDataValue()                           */
2829
/************************************************************************/
2830
2831
/**
2832
 * \brief Remove the no data value for this band.
2833
 *
2834
 * This method is the same as the C function GDALDeleteRasterNoDataValue().
2835
 *
2836
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2837
 * by the driver, CE_Failure is returned but no error message will have
2838
 * been emitted.
2839
 *
2840
 */
2841
2842
CPLErr GDALRasterBand::DeleteNoDataValue()
2843
2844
0
{
2845
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2846
0
        ReportError(CE_Failure, CPLE_NotSupported,
2847
0
                    "DeleteNoDataValue() not supported for this dataset.");
2848
2849
0
    return CE_Failure;
2850
0
}
2851
2852
/************************************************************************/
2853
/*                       GDALDeleteRasterNoDataValue()                  */
2854
/************************************************************************/
2855
2856
/**
2857
 * \brief Remove the no data value for this band.
2858
 *
2859
 * @see GDALRasterBand::DeleteNoDataValue()
2860
 *
2861
 */
2862
2863
CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2864
2865
0
{
2866
0
    VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2867
2868
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2869
0
    return poBand->DeleteNoDataValue();
2870
0
}
2871
2872
/************************************************************************/
2873
/*                             GetMaximum()                             */
2874
/************************************************************************/
2875
2876
/**
2877
 * \brief Fetch the maximum value for this band.
2878
 *
2879
 * For file formats that don't know this intrinsically, the maximum supported
2880
 * value for the data type will generally be returned.
2881
 *
2882
 * This method is the same as the C function GDALGetRasterMaximum().
2883
 *
2884
 * @param pbSuccess pointer to a boolean to use to indicate if the
2885
 * returned value is a tight maximum or not.  May be NULL (default).
2886
 *
2887
 * @return the maximum raster value (excluding no data pixels)
2888
 */
2889
2890
double GDALRasterBand::GetMaximum(int *pbSuccess)
2891
2892
0
{
2893
0
    const char *pszValue = nullptr;
2894
2895
0
    if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2896
0
    {
2897
0
        if (pbSuccess != nullptr)
2898
0
            *pbSuccess = TRUE;
2899
2900
0
        return CPLAtofM(pszValue);
2901
0
    }
2902
2903
0
    if (pbSuccess != nullptr)
2904
0
        *pbSuccess = FALSE;
2905
2906
0
    switch (eDataType)
2907
0
    {
2908
0
        case GDT_Byte:
2909
0
        {
2910
0
            EnablePixelTypeSignedByteWarning(false);
2911
0
            const char *pszPixelType =
2912
0
                GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2913
0
            EnablePixelTypeSignedByteWarning(true);
2914
0
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2915
0
                return 127;
2916
2917
0
            return 255;
2918
0
        }
2919
2920
0
        case GDT_Int8:
2921
0
            return 127;
2922
2923
0
        case GDT_UInt16:
2924
0
            return 65535;
2925
2926
0
        case GDT_Int16:
2927
0
        case GDT_CInt16:
2928
0
            return 32767;
2929
2930
0
        case GDT_Int32:
2931
0
        case GDT_CInt32:
2932
0
            return 2147483647.0;
2933
2934
0
        case GDT_UInt32:
2935
0
            return 4294967295.0;
2936
2937
0
        case GDT_Int64:
2938
0
            return static_cast<double>(std::numeric_limits<GInt64>::max());
2939
2940
0
        case GDT_UInt64:
2941
0
            return static_cast<double>(std::numeric_limits<GUInt64>::max());
2942
2943
0
        case GDT_Float16:
2944
0
        case GDT_CFloat16:
2945
0
            return 65504.0;
2946
2947
0
        case GDT_Float32:
2948
0
        case GDT_CFloat32:
2949
0
            return 4294967295.0;  // Not actually accurate.
2950
2951
0
        case GDT_Float64:
2952
0
        case GDT_CFloat64:
2953
0
            return 4294967295.0;  // Not actually accurate.
2954
2955
0
        case GDT_Unknown:
2956
0
        case GDT_TypeCount:
2957
0
            break;
2958
0
    }
2959
0
    return 4294967295.0;  // Not actually accurate.
2960
0
}
2961
2962
/************************************************************************/
2963
/*                        GDALGetRasterMaximum()                        */
2964
/************************************************************************/
2965
2966
/**
2967
 * \brief Fetch the maximum value for this band.
2968
 *
2969
 * @see GDALRasterBand::GetMaximum()
2970
 */
2971
2972
double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2973
2974
0
{
2975
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2976
2977
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2978
0
    return poBand->GetMaximum(pbSuccess);
2979
0
}
2980
2981
/************************************************************************/
2982
/*                             GetMinimum()                             */
2983
/************************************************************************/
2984
2985
/**
2986
 * \brief Fetch the minimum value for this band.
2987
 *
2988
 * For file formats that don't know this intrinsically, the minimum supported
2989
 * value for the data type will generally be returned.
2990
 *
2991
 * This method is the same as the C function GDALGetRasterMinimum().
2992
 *
2993
 * @param pbSuccess pointer to a boolean to use to indicate if the
2994
 * returned value is a tight minimum or not.  May be NULL (default).
2995
 *
2996
 * @return the minimum raster value (excluding no data pixels)
2997
 */
2998
2999
double GDALRasterBand::GetMinimum(int *pbSuccess)
3000
3001
0
{
3002
0
    const char *pszValue = nullptr;
3003
3004
0
    if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
3005
0
    {
3006
0
        if (pbSuccess != nullptr)
3007
0
            *pbSuccess = TRUE;
3008
3009
0
        return CPLAtofM(pszValue);
3010
0
    }
3011
3012
0
    if (pbSuccess != nullptr)
3013
0
        *pbSuccess = FALSE;
3014
3015
0
    switch (eDataType)
3016
0
    {
3017
0
        case GDT_Byte:
3018
0
        {
3019
0
            EnablePixelTypeSignedByteWarning(false);
3020
0
            const char *pszPixelType =
3021
0
                GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3022
0
            EnablePixelTypeSignedByteWarning(true);
3023
0
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3024
0
                return -128;
3025
3026
0
            return 0;
3027
0
        }
3028
3029
0
        case GDT_Int8:
3030
0
            return -128;
3031
3032
0
        case GDT_UInt16:
3033
0
            return 0;
3034
3035
0
        case GDT_Int16:
3036
0
        case GDT_CInt16:
3037
0
            return -32768;
3038
3039
0
        case GDT_Int32:
3040
0
        case GDT_CInt32:
3041
0
            return -2147483648.0;
3042
3043
0
        case GDT_UInt32:
3044
0
            return 0;
3045
3046
0
        case GDT_Int64:
3047
0
            return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3048
3049
0
        case GDT_UInt64:
3050
0
            return 0;
3051
3052
0
        case GDT_Float16:
3053
0
        case GDT_CFloat16:
3054
0
            return -65504.0;
3055
3056
0
        case GDT_Float32:
3057
0
        case GDT_CFloat32:
3058
0
            return -4294967295.0;  // Not actually accurate.
3059
3060
0
        case GDT_Float64:
3061
0
        case GDT_CFloat64:
3062
0
            return -4294967295.0;  // Not actually accurate.
3063
3064
0
        case GDT_Unknown:
3065
0
        case GDT_TypeCount:
3066
0
            break;
3067
0
    }
3068
0
    return -4294967295.0;  // Not actually accurate.
3069
0
}
3070
3071
/************************************************************************/
3072
/*                        GDALGetRasterMinimum()                        */
3073
/************************************************************************/
3074
3075
/**
3076
 * \brief Fetch the minimum value for this band.
3077
 *
3078
 * @see GDALRasterBand::GetMinimum()
3079
 */
3080
3081
double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3082
3083
0
{
3084
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3085
3086
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3087
0
    return poBand->GetMinimum(pbSuccess);
3088
0
}
3089
3090
/************************************************************************/
3091
/*                       GetColorInterpretation()                       */
3092
/************************************************************************/
3093
3094
/**
3095
 * \brief How should this band be interpreted as color?
3096
 *
3097
 * GCI_Undefined is returned when the format doesn't know anything
3098
 * about the color interpretation.
3099
 *
3100
 * This method is the same as the C function
3101
 * GDALGetRasterColorInterpretation().
3102
 *
3103
 * @return color interpretation value for band.
3104
 */
3105
3106
GDALColorInterp GDALRasterBand::GetColorInterpretation()
3107
3108
0
{
3109
0
    return GCI_Undefined;
3110
0
}
3111
3112
/************************************************************************/
3113
/*                  GDALGetRasterColorInterpretation()                  */
3114
/************************************************************************/
3115
3116
/**
3117
 * \brief How should this band be interpreted as color?
3118
 *
3119
 * @see GDALRasterBand::GetColorInterpretation()
3120
 */
3121
3122
GDALColorInterp CPL_STDCALL
3123
GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3124
3125
0
{
3126
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3127
3128
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3129
0
    return poBand->GetColorInterpretation();
3130
0
}
3131
3132
/************************************************************************/
3133
/*                       SetColorInterpretation()                       */
3134
/************************************************************************/
3135
3136
/**
3137
 * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3138
 * \brief Set color interpretation of a band.
3139
 *
3140
 * This method is the same as the C function GDALSetRasterColorInterpretation().
3141
 *
3142
 * @param eColorInterp the new color interpretation to apply to this band.
3143
 *
3144
 * @return CE_None on success or CE_Failure if method is unsupported by format.
3145
 */
3146
3147
/**/
3148
/**/
3149
3150
CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3151
3152
0
{
3153
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3154
0
        ReportError(CE_Failure, CPLE_NotSupported,
3155
0
                    "SetColorInterpretation() not supported for this dataset.");
3156
0
    return CE_Failure;
3157
0
}
3158
3159
/************************************************************************/
3160
/*                  GDALSetRasterColorInterpretation()                  */
3161
/************************************************************************/
3162
3163
/**
3164
 * \brief Set color interpretation of a band.
3165
 *
3166
 * @see GDALRasterBand::SetColorInterpretation()
3167
 */
3168
3169
CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3170
    GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3171
3172
0
{
3173
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3174
3175
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3176
0
    return poBand->SetColorInterpretation(eColorInterp);
3177
0
}
3178
3179
/************************************************************************/
3180
/*                           GetColorTable()                            */
3181
/************************************************************************/
3182
3183
/**
3184
 * \brief Fetch the color table associated with band.
3185
 *
3186
 * If there is no associated color table, the return result is NULL.  The
3187
 * returned color table remains owned by the GDALRasterBand, and can't
3188
 * be depended on for long, nor should it ever be modified by the caller.
3189
 *
3190
 * This method is the same as the C function GDALGetRasterColorTable().
3191
 *
3192
 * @return internal color table, or NULL.
3193
 */
3194
3195
GDALColorTable *GDALRasterBand::GetColorTable()
3196
3197
0
{
3198
0
    return nullptr;
3199
0
}
3200
3201
/************************************************************************/
3202
/*                      GDALGetRasterColorTable()                       */
3203
/************************************************************************/
3204
3205
/**
3206
 * \brief Fetch the color table associated with band.
3207
 *
3208
 * @see GDALRasterBand::GetColorTable()
3209
 */
3210
3211
GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3212
3213
0
{
3214
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3215
3216
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3217
0
    return GDALColorTable::ToHandle(poBand->GetColorTable());
3218
0
}
3219
3220
/************************************************************************/
3221
/*                           SetColorTable()                            */
3222
/************************************************************************/
3223
3224
/**
3225
 * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3226
 * \brief Set the raster color table.
3227
 *
3228
 * The driver will make a copy of all desired data in the colortable.  It
3229
 * remains owned by the caller after the call.
3230
 *
3231
 * This method is the same as the C function GDALSetRasterColorTable().
3232
 *
3233
 * @param poCT the color table to apply.  This may be NULL to clear the color
3234
 * table (where supported).
3235
 *
3236
 * @return CE_None on success, or CE_Failure on failure.  If the action is
3237
 * unsupported by the driver, a value of CE_Failure is returned, but no
3238
 * error is issued.
3239
 */
3240
3241
/**/
3242
/**/
3243
3244
CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3245
3246
0
{
3247
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3248
0
        ReportError(CE_Failure, CPLE_NotSupported,
3249
0
                    "SetColorTable() not supported for this dataset.");
3250
0
    return CE_Failure;
3251
0
}
3252
3253
/************************************************************************/
3254
/*                      GDALSetRasterColorTable()                       */
3255
/************************************************************************/
3256
3257
/**
3258
 * \brief Set the raster color table.
3259
 *
3260
 * @see GDALRasterBand::SetColorTable()
3261
 */
3262
3263
CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3264
                                           GDALColorTableH hCT)
3265
3266
0
{
3267
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3268
3269
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3270
0
    return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3271
0
}
3272
3273
/************************************************************************/
3274
/*                       HasArbitraryOverviews()                        */
3275
/************************************************************************/
3276
3277
/**
3278
 * \brief Check for arbitrary overviews.
3279
 *
3280
 * This returns TRUE if the underlying datastore can compute arbitrary
3281
 * overviews efficiently, such as is the case with OGDI over a network.
3282
 * Datastores with arbitrary overviews don't generally have any fixed
3283
 * overviews, but the RasterIO() method can be used in downsampling mode
3284
 * to get overview data efficiently.
3285
 *
3286
 * This method is the same as the C function GDALHasArbitraryOverviews(),
3287
 *
3288
 * @return TRUE if arbitrary overviews available (efficiently), otherwise
3289
 * FALSE.
3290
 */
3291
3292
int GDALRasterBand::HasArbitraryOverviews()
3293
3294
0
{
3295
0
    return FALSE;
3296
0
}
3297
3298
/************************************************************************/
3299
/*                     GDALHasArbitraryOverviews()                      */
3300
/************************************************************************/
3301
3302
/**
3303
 * \brief Check for arbitrary overviews.
3304
 *
3305
 * @see GDALRasterBand::HasArbitraryOverviews()
3306
 */
3307
3308
int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3309
3310
0
{
3311
0
    VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3312
3313
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3314
0
    return poBand->HasArbitraryOverviews();
3315
0
}
3316
3317
/************************************************************************/
3318
/*                          GetOverviewCount()                          */
3319
/************************************************************************/
3320
3321
/**
3322
 * \brief Return the number of overview layers available.
3323
 *
3324
 * This method is the same as the C function GDALGetOverviewCount().
3325
 *
3326
 * @return overview count, zero if none.
3327
 */
3328
3329
int GDALRasterBand::GetOverviewCount()
3330
3331
0
{
3332
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3333
0
        poDS->AreOverviewsEnabled())
3334
0
        return poDS->oOvManager.GetOverviewCount(nBand);
3335
3336
0
    return 0;
3337
0
}
3338
3339
/************************************************************************/
3340
/*                        GDALGetOverviewCount()                        */
3341
/************************************************************************/
3342
3343
/**
3344
 * \brief Return the number of overview layers available.
3345
 *
3346
 * @see GDALRasterBand::GetOverviewCount()
3347
 */
3348
3349
int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3350
3351
0
{
3352
0
    VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3353
3354
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3355
0
    return poBand->GetOverviewCount();
3356
0
}
3357
3358
/************************************************************************/
3359
/*                            GetOverview()                             */
3360
/************************************************************************/
3361
3362
/**
3363
 * \brief Fetch overview raster band object.
3364
 *
3365
 * This method is the same as the C function GDALGetOverview().
3366
 *
3367
 * @param i overview index between 0 and GetOverviewCount()-1.
3368
 *
3369
 * @return overview GDALRasterBand.
3370
 */
3371
3372
GDALRasterBand *GDALRasterBand::GetOverview(int i)
3373
3374
0
{
3375
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3376
0
        poDS->AreOverviewsEnabled())
3377
0
        return poDS->oOvManager.GetOverview(nBand, i);
3378
3379
0
    return nullptr;
3380
0
}
3381
3382
/************************************************************************/
3383
/*                          GDALGetOverview()                           */
3384
/************************************************************************/
3385
3386
/**
3387
 * \brief Fetch overview raster band object.
3388
 *
3389
 * @see GDALRasterBand::GetOverview()
3390
 */
3391
3392
GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3393
3394
0
{
3395
0
    VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3396
3397
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3398
0
    return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3399
0
}
3400
3401
/************************************************************************/
3402
/*                      GetRasterSampleOverview()                       */
3403
/************************************************************************/
3404
3405
/**
3406
 * \brief Fetch best sampling overview.
3407
 *
3408
 * Returns the most reduced overview of the given band that still satisfies
3409
 * the desired number of samples.  This function can be used with zero
3410
 * as the number of desired samples to fetch the most reduced overview.
3411
 * The same band as was passed in will be returned if it has not overviews,
3412
 * or if none of the overviews have enough samples.
3413
 *
3414
 * This method is the same as the C functions GDALGetRasterSampleOverview()
3415
 * and GDALGetRasterSampleOverviewEx().
3416
 *
3417
 * @param nDesiredSamples the returned band will have at least this many
3418
 * pixels.
3419
 *
3420
 * @return optimal overview or the band itself.
3421
 */
3422
3423
GDALRasterBand *
3424
GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3425
3426
0
{
3427
0
    GDALRasterBand *poBestBand = this;
3428
3429
0
    double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3430
3431
0
    for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3432
0
    {
3433
0
        GDALRasterBand *poOBand = GetOverview(iOverview);
3434
3435
0
        if (poOBand == nullptr)
3436
0
            continue;
3437
3438
0
        const double dfOSamples =
3439
0
            poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3440
3441
0
        if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3442
0
        {
3443
0
            dfBestSamples = dfOSamples;
3444
0
            poBestBand = poOBand;
3445
0
        }
3446
0
    }
3447
3448
0
    return poBestBand;
3449
0
}
3450
3451
/************************************************************************/
3452
/*                    GDALGetRasterSampleOverview()                     */
3453
/************************************************************************/
3454
3455
/**
3456
 * \brief Fetch best sampling overview.
3457
 *
3458
 * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3459
 * billion samples.
3460
 *
3461
 * @see GDALRasterBand::GetRasterSampleOverview()
3462
 * @see GDALGetRasterSampleOverviewEx()
3463
 */
3464
3465
GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3466
                                                        int nDesiredSamples)
3467
3468
0
{
3469
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3470
3471
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3472
0
    return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3473
0
        nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3474
0
}
3475
3476
/************************************************************************/
3477
/*                    GDALGetRasterSampleOverviewEx()                   */
3478
/************************************************************************/
3479
3480
/**
3481
 * \brief Fetch best sampling overview.
3482
 *
3483
 * @see GDALRasterBand::GetRasterSampleOverview()
3484
 */
3485
3486
GDALRasterBandH CPL_STDCALL
3487
GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3488
3489
0
{
3490
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3491
3492
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3493
0
    return GDALRasterBand::ToHandle(
3494
0
        poBand->GetRasterSampleOverview(nDesiredSamples));
3495
0
}
3496
3497
/************************************************************************/
3498
/*                           BuildOverviews()                           */
3499
/************************************************************************/
3500
3501
/**
3502
 * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3503
 * GDALProgressFunc, void*) \brief Build raster overview(s)
3504
 *
3505
 * If the operation is unsupported for the indicated dataset, then
3506
 * CE_Failure is returned, and CPLGetLastErrorNo() will return
3507
 * CPLE_NotSupported.
3508
 *
3509
 * WARNING: Most formats don't support per-band overview computation, but
3510
 * require that overviews are computed for all bands of a dataset, using
3511
 * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3512
 * is the HFA driver which supports this method.
3513
 *
3514
 * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3515
 * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3516
 * applied.
3517
 * @param nOverviews number of overviews to build.
3518
 * @param panOverviewList the list of overview decimation factors to build.
3519
 * @param pfnProgress a function to call to report progress, or NULL.
3520
 * @param pProgressData application data to pass to the progress function.
3521
 * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3522
 *                     key=value pairs, or NULL
3523
 *
3524
 * @return CE_None on success or CE_Failure if the operation doesn't work.
3525
 */
3526
3527
/**/
3528
/**/
3529
3530
CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3531
                                      int /*nOverviews*/,
3532
                                      const int * /*panOverviewList*/,
3533
                                      GDALProgressFunc /*pfnProgress*/,
3534
                                      void * /*pProgressData*/,
3535
                                      CSLConstList /* papszOptions */)
3536
3537
0
{
3538
0
    ReportError(CE_Failure, CPLE_NotSupported,
3539
0
                "BuildOverviews() not supported for this dataset.");
3540
3541
0
    return (CE_Failure);
3542
0
}
3543
3544
/************************************************************************/
3545
/*                             GetOffset()                              */
3546
/************************************************************************/
3547
3548
/**
3549
 * \brief Fetch the raster value offset.
3550
 *
3551
 * This value (in combination with the GetScale() value) can be used to
3552
 * transform raw pixel values into the units returned by GetUnitType().
3553
 * For example this might be used to store elevations in GUInt16 bands
3554
 * with a precision of 0.1, and starting from -100.
3555
 *
3556
 * Units value = (raw value * scale) + offset
3557
 *
3558
 * Note that applying scale and offset is of the responsibility of the user,
3559
 * and is not done by methods such as RasterIO() or ReadBlock().
3560
 *
3561
 * For file formats that don't know this intrinsically a value of zero
3562
 * is returned.
3563
 *
3564
 * This method is the same as the C function GDALGetRasterOffset().
3565
 *
3566
 * @param pbSuccess pointer to a boolean to use to indicate if the
3567
 * returned value is meaningful or not.  May be NULL (default).
3568
 *
3569
 * @return the raster offset.
3570
 */
3571
3572
double GDALRasterBand::GetOffset(int *pbSuccess)
3573
3574
0
{
3575
0
    if (pbSuccess != nullptr)
3576
0
        *pbSuccess = FALSE;
3577
3578
0
    return 0.0;
3579
0
}
3580
3581
/************************************************************************/
3582
/*                        GDALGetRasterOffset()                         */
3583
/************************************************************************/
3584
3585
/**
3586
 * \brief Fetch the raster value offset.
3587
 *
3588
 * @see GDALRasterBand::GetOffset()
3589
 */
3590
3591
double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3592
3593
0
{
3594
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3595
3596
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3597
0
    return poBand->GetOffset(pbSuccess);
3598
0
}
3599
3600
/************************************************************************/
3601
/*                             SetOffset()                              */
3602
/************************************************************************/
3603
3604
/**
3605
 * \fn GDALRasterBand::SetOffset(double)
3606
 * \brief Set scaling offset.
3607
 *
3608
 * Very few formats implement this method.   When not implemented it will
3609
 * issue a CPLE_NotSupported error and return CE_Failure.
3610
 *
3611
 * This method is the same as the C function GDALSetRasterOffset().
3612
 *
3613
 * @param dfNewOffset the new offset.
3614
 *
3615
 * @return CE_None or success or CE_Failure on failure.
3616
 */
3617
3618
/**/
3619
/**/
3620
3621
CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3622
0
{
3623
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3624
0
        ReportError(CE_Failure, CPLE_NotSupported,
3625
0
                    "SetOffset() not supported on this raster band.");
3626
3627
0
    return CE_Failure;
3628
0
}
3629
3630
/************************************************************************/
3631
/*                        GDALSetRasterOffset()                         */
3632
/************************************************************************/
3633
3634
/**
3635
 * \brief Set scaling offset.
3636
 *
3637
 * @see GDALRasterBand::SetOffset()
3638
 */
3639
3640
CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3641
                                       double dfNewOffset)
3642
3643
0
{
3644
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3645
3646
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3647
0
    return poBand->SetOffset(dfNewOffset);
3648
0
}
3649
3650
/************************************************************************/
3651
/*                              GetScale()                              */
3652
/************************************************************************/
3653
3654
/**
3655
 * \brief Fetch the raster value scale.
3656
 *
3657
 * This value (in combination with the GetOffset() value) can be used to
3658
 * transform raw pixel values into the units returned by GetUnitType().
3659
 * For example this might be used to store elevations in GUInt16 bands
3660
 * with a precision of 0.1, and starting from -100.
3661
 *
3662
 * Units value = (raw value * scale) + offset
3663
 *
3664
 * Note that applying scale and offset is of the responsibility of the user,
3665
 * and is not done by methods such as RasterIO() or ReadBlock().
3666
 *
3667
 * For file formats that don't know this intrinsically a value of one
3668
 * is returned.
3669
 *
3670
 * This method is the same as the C function GDALGetRasterScale().
3671
 *
3672
 * @param pbSuccess pointer to a boolean to use to indicate if the
3673
 * returned value is meaningful or not.  May be NULL (default).
3674
 *
3675
 * @return the raster scale.
3676
 */
3677
3678
double GDALRasterBand::GetScale(int *pbSuccess)
3679
3680
0
{
3681
0
    if (pbSuccess != nullptr)
3682
0
        *pbSuccess = FALSE;
3683
3684
0
    return 1.0;
3685
0
}
3686
3687
/************************************************************************/
3688
/*                         GDALGetRasterScale()                         */
3689
/************************************************************************/
3690
3691
/**
3692
 * \brief Fetch the raster value scale.
3693
 *
3694
 * @see GDALRasterBand::GetScale()
3695
 */
3696
3697
double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3698
3699
0
{
3700
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3701
3702
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3703
0
    return poBand->GetScale(pbSuccess);
3704
0
}
3705
3706
/************************************************************************/
3707
/*                              SetScale()                              */
3708
/************************************************************************/
3709
3710
/**
3711
 * \fn GDALRasterBand::SetScale(double)
3712
 * \brief Set scaling ratio.
3713
 *
3714
 * Very few formats implement this method.   When not implemented it will
3715
 * issue a CPLE_NotSupported error and return CE_Failure.
3716
 *
3717
 * This method is the same as the C function GDALSetRasterScale().
3718
 *
3719
 * @param dfNewScale the new scale.
3720
 *
3721
 * @return CE_None or success or CE_Failure on failure.
3722
 */
3723
3724
/**/
3725
/**/
3726
3727
CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3728
3729
0
{
3730
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3731
0
        ReportError(CE_Failure, CPLE_NotSupported,
3732
0
                    "SetScale() not supported on this raster band.");
3733
3734
0
    return CE_Failure;
3735
0
}
3736
3737
/************************************************************************/
3738
/*                        GDALSetRasterScale()                          */
3739
/************************************************************************/
3740
3741
/**
3742
 * \brief Set scaling ratio.
3743
 *
3744
 * @see GDALRasterBand::SetScale()
3745
 */
3746
3747
CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3748
3749
0
{
3750
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3751
3752
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3753
0
    return poBand->SetScale(dfNewOffset);
3754
0
}
3755
3756
/************************************************************************/
3757
/*                            GetUnitType()                             */
3758
/************************************************************************/
3759
3760
/**
3761
 * \brief Return raster unit type.
3762
 *
3763
 * Return a name for the units of this raster's values.  For instance, it
3764
 * might be "m" for an elevation model in meters, or "ft" for feet.  If no
3765
 * units are available, a value of "" will be returned.  The returned string
3766
 * should not be modified, nor freed by the calling application.
3767
 *
3768
 * This method is the same as the C function GDALGetRasterUnitType().
3769
 *
3770
 * @return unit name string.
3771
 */
3772
3773
const char *GDALRasterBand::GetUnitType()
3774
3775
0
{
3776
0
    return "";
3777
0
}
3778
3779
/************************************************************************/
3780
/*                       GDALGetRasterUnitType()                        */
3781
/************************************************************************/
3782
3783
/**
3784
 * \brief Return raster unit type.
3785
 *
3786
 * @see GDALRasterBand::GetUnitType()
3787
 */
3788
3789
const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3790
3791
0
{
3792
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3793
3794
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3795
0
    return poBand->GetUnitType();
3796
0
}
3797
3798
/************************************************************************/
3799
/*                            SetUnitType()                             */
3800
/************************************************************************/
3801
3802
/**
3803
 * \fn GDALRasterBand::SetUnitType(const char*)
3804
 * \brief Set unit type.
3805
 *
3806
 * Set the unit type for a raster band.  Values should be one of
3807
 * "" (the default indicating it is unknown), "m" indicating meters,
3808
 * or "ft" indicating feet, though other nonstandard values are allowed.
3809
 *
3810
 * This method is the same as the C function GDALSetRasterUnitType().
3811
 *
3812
 * @param pszNewValue the new unit type value.
3813
 *
3814
 * @return CE_None on success or CE_Failure if not successful, or
3815
 * unsupported.
3816
 */
3817
3818
/**/
3819
/**/
3820
3821
CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3822
3823
0
{
3824
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3825
0
        ReportError(CE_Failure, CPLE_NotSupported,
3826
0
                    "SetUnitType() not supported on this raster band.");
3827
0
    return CE_Failure;
3828
0
}
3829
3830
/************************************************************************/
3831
/*                       GDALSetRasterUnitType()                        */
3832
/************************************************************************/
3833
3834
/**
3835
 * \brief Set unit type.
3836
 *
3837
 * @see GDALRasterBand::SetUnitType()
3838
 *
3839
 */
3840
3841
CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3842
                                         const char *pszNewValue)
3843
3844
0
{
3845
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3846
3847
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3848
0
    return poBand->SetUnitType(pszNewValue);
3849
0
}
3850
3851
/************************************************************************/
3852
/*                              GetXSize()                              */
3853
/************************************************************************/
3854
3855
/**
3856
 * \brief Fetch XSize of raster.
3857
 *
3858
 * This method is the same as the C function GDALGetRasterBandXSize().
3859
 *
3860
 * @return the width in pixels of this band.
3861
 */
3862
3863
int GDALRasterBand::GetXSize() const
3864
3865
0
{
3866
0
    return nRasterXSize;
3867
0
}
3868
3869
/************************************************************************/
3870
/*                       GDALGetRasterBandXSize()                       */
3871
/************************************************************************/
3872
3873
/**
3874
 * \brief Fetch XSize of raster.
3875
 *
3876
 * @see GDALRasterBand::GetXSize()
3877
 */
3878
3879
int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3880
3881
0
{
3882
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3883
3884
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3885
0
    return poBand->GetXSize();
3886
0
}
3887
3888
/************************************************************************/
3889
/*                              GetYSize()                              */
3890
/************************************************************************/
3891
3892
/**
3893
 * \brief Fetch YSize of raster.
3894
 *
3895
 * This method is the same as the C function GDALGetRasterBandYSize().
3896
 *
3897
 * @return the height in pixels of this band.
3898
 */
3899
3900
int GDALRasterBand::GetYSize() const
3901
3902
0
{
3903
0
    return nRasterYSize;
3904
0
}
3905
3906
/************************************************************************/
3907
/*                       GDALGetRasterBandYSize()                       */
3908
/************************************************************************/
3909
3910
/**
3911
 * \brief Fetch YSize of raster.
3912
 *
3913
 * @see GDALRasterBand::GetYSize()
3914
 */
3915
3916
int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3917
3918
0
{
3919
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3920
3921
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3922
0
    return poBand->GetYSize();
3923
0
}
3924
3925
/************************************************************************/
3926
/*                              GetBand()                               */
3927
/************************************************************************/
3928
3929
/**
3930
 * \brief Fetch the band number.
3931
 *
3932
 * This method returns the band that this GDALRasterBand objects represents
3933
 * within its dataset.  This method may return a value of 0 to indicate
3934
 * GDALRasterBand objects without an apparently relationship to a dataset,
3935
 * such as GDALRasterBands serving as overviews.
3936
 *
3937
 * This method is the same as the C function GDALGetBandNumber().
3938
 *
3939
 * @return band number (1+) or 0 if the band number isn't known.
3940
 */
3941
3942
int GDALRasterBand::GetBand() const
3943
3944
0
{
3945
0
    return nBand;
3946
0
}
3947
3948
/************************************************************************/
3949
/*                         GDALGetBandNumber()                          */
3950
/************************************************************************/
3951
3952
/**
3953
 * \brief Fetch the band number.
3954
 *
3955
 * @see GDALRasterBand::GetBand()
3956
 */
3957
3958
int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3959
3960
0
{
3961
0
    VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3962
3963
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3964
0
    return poBand->GetBand();
3965
0
}
3966
3967
/************************************************************************/
3968
/*                             GetDataset()                             */
3969
/************************************************************************/
3970
3971
/**
3972
 * \brief Fetch the owning dataset handle.
3973
 *
3974
 * Note that some GDALRasterBands are not considered to be a part of a dataset,
3975
 * such as overviews or other "freestanding" bands.
3976
 *
3977
 * This method is the same as the C function GDALGetBandDataset().
3978
 *
3979
 * @return the pointer to the GDALDataset to which this band belongs, or
3980
 * NULL if this cannot be determined.
3981
 */
3982
3983
GDALDataset *GDALRasterBand::GetDataset() const
3984
3985
0
{
3986
0
    return poDS;
3987
0
}
3988
3989
/************************************************************************/
3990
/*                         GDALGetBandDataset()                         */
3991
/************************************************************************/
3992
3993
/**
3994
 * \brief Fetch the owning dataset handle.
3995
 *
3996
 * @see GDALRasterBand::GetDataset()
3997
 */
3998
3999
GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4000
4001
0
{
4002
0
    VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4003
4004
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4005
0
    return GDALDataset::ToHandle(poBand->GetDataset());
4006
0
}
4007
4008
/************************************************************************/
4009
/*                        ComputeFloat16NoDataValue()                     */
4010
/************************************************************************/
4011
4012
static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4013
                                             double dfNoDataValue,
4014
                                             int &bGotNoDataValue,
4015
                                             GFloat16 &fNoDataValue,
4016
                                             bool &bGotFloat16NoDataValue)
4017
0
{
4018
0
    if (eDataType == GDT_Float16 && bGotNoDataValue)
4019
0
    {
4020
0
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4021
0
        if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4022
0
        {
4023
0
            fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4024
0
            bGotFloat16NoDataValue = true;
4025
0
            bGotNoDataValue = false;
4026
0
        }
4027
0
    }
4028
0
}
4029
4030
/************************************************************************/
4031
/*                        ComputeFloatNoDataValue()                     */
4032
/************************************************************************/
4033
4034
static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4035
                                           double dfNoDataValue,
4036
                                           int &bGotNoDataValue,
4037
                                           float &fNoDataValue,
4038
                                           bool &bGotFloatNoDataValue)
4039
0
{
4040
0
    if (eDataType == GDT_Float32 && bGotNoDataValue)
4041
0
    {
4042
0
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4043
0
        if (GDALIsValueInRange<float>(dfNoDataValue))
4044
0
        {
4045
0
            fNoDataValue = static_cast<float>(dfNoDataValue);
4046
0
            bGotFloatNoDataValue = true;
4047
0
            bGotNoDataValue = false;
4048
0
        }
4049
0
    }
4050
0
}
4051
4052
/************************************************************************/
4053
/*                        struct GDALNoDataValues                       */
4054
/************************************************************************/
4055
4056
/**
4057
 * \brief No-data-values for all types
4058
 *
4059
 * The functions below pass various no-data-values around. To avoid
4060
 * long argument lists, this struct collects the no-data-values for
4061
 * all types into a single, convenient place.
4062
 **/
4063
4064
struct GDALNoDataValues
4065
{
4066
    int bGotNoDataValue;
4067
    double dfNoDataValue;
4068
4069
    bool bGotInt64NoDataValue;
4070
    int64_t nInt64NoDataValue;
4071
4072
    bool bGotUInt64NoDataValue;
4073
    uint64_t nUInt64NoDataValue;
4074
4075
    bool bGotFloatNoDataValue;
4076
    float fNoDataValue;
4077
4078
    bool bGotFloat16NoDataValue;
4079
    GFloat16 hfNoDataValue;
4080
4081
    GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4082
0
        : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4083
0
          bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4084
0
          bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4085
0
          bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4086
0
          bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4087
0
    {
4088
0
        if (eDataType == GDT_Int64)
4089
0
        {
4090
0
            int nGot = false;
4091
0
            nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4092
0
            bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4093
0
            if (bGotInt64NoDataValue)
4094
0
            {
4095
0
                dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4096
0
                bGotNoDataValue =
4097
0
                    nInt64NoDataValue <=
4098
0
                        std::numeric_limits<int64_t>::max() - 1024 &&
4099
0
                    static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4100
0
            }
4101
0
            else
4102
0
                dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4103
0
        }
4104
0
        else if (eDataType == GDT_UInt64)
4105
0
        {
4106
0
            int nGot = false;
4107
0
            nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4108
0
            bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4109
0
            if (bGotUInt64NoDataValue)
4110
0
            {
4111
0
                dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4112
0
                bGotNoDataValue =
4113
0
                    nUInt64NoDataValue <=
4114
0
                        std::numeric_limits<uint64_t>::max() - 2048 &&
4115
0
                    static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4116
0
            }
4117
0
            else
4118
0
                dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4119
0
        }
4120
0
        else
4121
0
        {
4122
0
            dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4123
0
            bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4124
4125
0
            ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4126
0
                                    fNoDataValue, bGotFloatNoDataValue);
4127
4128
0
            ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4129
0
                                      hfNoDataValue, bGotFloat16NoDataValue);
4130
0
        }
4131
0
    }
4132
};
4133
4134
/************************************************************************/
4135
/*                            ARE_REAL_EQUAL()                          */
4136
/************************************************************************/
4137
4138
inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4139
0
{
4140
0
    using std::abs;
4141
0
    return dfVal1 == dfVal2 || /* Should cover infinity */
4142
0
           abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4143
0
                                      abs(dfVal1 + dfVal2) * ulp;
4144
0
}
4145
4146
/************************************************************************/
4147
/*                            GetHistogram()                            */
4148
/************************************************************************/
4149
4150
/**
4151
 * \brief Compute raster histogram.
4152
 *
4153
 * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4154
 *
4155
 * For example to compute a simple 256 entry histogram of eight bit data,
4156
 * the following would be suitable.  The unusual bounds are to ensure that
4157
 * bucket boundaries don't fall right on integer values causing possible errors
4158
 * due to rounding after scaling.
4159
\code{.cpp}
4160
    GUIntBig anHistogram[256];
4161
4162
    poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4163
                          GDALDummyProgress, nullptr );
4164
\endcode
4165
 *
4166
 * Note that setting bApproxOK will generally result in a subsampling of the
4167
 * file, and will utilize overviews if available.  It should generally
4168
 * produce a representative histogram for the data that is suitable for use
4169
 * in generating histogram based luts for instance.  Generally bApproxOK is
4170
 * much faster than an exactly computed histogram.
4171
 *
4172
 * This method is the same as the C functions GDALGetRasterHistogram() and
4173
 * GDALGetRasterHistogramEx().
4174
 *
4175
 * @param dfMin the lower bound of the histogram.
4176
 * @param dfMax the upper bound of the histogram.
4177
 * @param nBuckets the number of buckets in panHistogram.
4178
 * @param panHistogram array into which the histogram totals are placed.
4179
 * @param bIncludeOutOfRange if TRUE values below the histogram range will
4180
 * mapped into panHistogram[0], and values above will be mapped into
4181
 * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4182
 * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4183
 * @param pfnProgress function to report progress to completion.
4184
 * @param pProgressData application data to pass to pfnProgress.
4185
 *
4186
 * @return CE_None on success, or CE_Failure if something goes wrong.
4187
 */
4188
4189
CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4190
                                    GUIntBig *panHistogram,
4191
                                    int bIncludeOutOfRange, int bApproxOK,
4192
                                    GDALProgressFunc pfnProgress,
4193
                                    void *pProgressData)
4194
4195
0
{
4196
0
    CPLAssert(nullptr != panHistogram);
4197
4198
0
    if (pfnProgress == nullptr)
4199
0
        pfnProgress = GDALDummyProgress;
4200
4201
    /* -------------------------------------------------------------------- */
4202
    /*      If we have overviews, use them for the histogram.               */
4203
    /* -------------------------------------------------------------------- */
4204
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4205
0
    {
4206
        // FIXME: should we use the most reduced overview here or use some
4207
        // minimum number of samples like GDALRasterBand::ComputeStatistics()
4208
        // does?
4209
0
        GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4210
4211
0
        if (poBestOverview != this)
4212
0
        {
4213
0
            return poBestOverview->GetHistogram(
4214
0
                dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4215
0
                bApproxOK, pfnProgress, pProgressData);
4216
0
        }
4217
0
    }
4218
4219
    /* -------------------------------------------------------------------- */
4220
    /*      Read actual data and build histogram.                           */
4221
    /* -------------------------------------------------------------------- */
4222
0
    if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4223
0
    {
4224
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4225
0
        return CE_Failure;
4226
0
    }
4227
4228
    // Written this way to deal with NaN
4229
0
    if (!(dfMax > dfMin))
4230
0
    {
4231
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4232
0
                    "dfMax should be strictly greater than dfMin");
4233
0
        return CE_Failure;
4234
0
    }
4235
4236
0
    GDALRasterIOExtraArg sExtraArg;
4237
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4238
4239
0
    const double dfScale = nBuckets / (dfMax - dfMin);
4240
0
    if (dfScale == 0 || !std::isfinite(dfScale))
4241
0
    {
4242
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4243
0
                    "dfMin and dfMax should be finite values such that "
4244
0
                    "nBuckets / (dfMax - dfMin) is non-zero");
4245
0
        return CE_Failure;
4246
0
    }
4247
0
    memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4248
4249
0
    GDALNoDataValues sNoDataValues(this, eDataType);
4250
0
    GDALRasterBand *poMaskBand = nullptr;
4251
0
    if (!sNoDataValues.bGotNoDataValue)
4252
0
    {
4253
0
        const int l_nMaskFlags = GetMaskFlags();
4254
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
4255
0
            GetColorInterpretation() != GCI_AlphaBand)
4256
0
        {
4257
0
            poMaskBand = GetMaskBand();
4258
0
        }
4259
0
    }
4260
4261
0
    bool bSignedByte = false;
4262
0
    if (eDataType == GDT_Byte)
4263
0
    {
4264
0
        EnablePixelTypeSignedByteWarning(false);
4265
0
        const char *pszPixelType =
4266
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4267
0
        EnablePixelTypeSignedByteWarning(true);
4268
0
        bSignedByte =
4269
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4270
0
    }
4271
4272
0
    if (bApproxOK && HasArbitraryOverviews())
4273
0
    {
4274
        /* --------------------------------------------------------------------
4275
         */
4276
        /*      Figure out how much the image should be reduced to get an */
4277
        /*      approximate value. */
4278
        /* --------------------------------------------------------------------
4279
         */
4280
0
        const double dfReduction =
4281
0
            sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4282
0
                 GDALSTAT_APPROX_NUMSAMPLES);
4283
4284
0
        int nXReduced = nRasterXSize;
4285
0
        int nYReduced = nRasterYSize;
4286
0
        if (dfReduction > 1.0)
4287
0
        {
4288
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4289
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4290
4291
            // Catch the case of huge resizing ratios here
4292
0
            if (nXReduced == 0)
4293
0
                nXReduced = 1;
4294
0
            if (nYReduced == 0)
4295
0
                nYReduced = 1;
4296
0
        }
4297
4298
0
        void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4299
0
                                          nXReduced, nYReduced);
4300
0
        if (!pData)
4301
0
            return CE_Failure;
4302
4303
0
        const CPLErr eErr =
4304
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4305
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4306
0
        if (eErr != CE_None)
4307
0
        {
4308
0
            CPLFree(pData);
4309
0
            return eErr;
4310
0
        }
4311
4312
0
        GByte *pabyMaskData = nullptr;
4313
0
        if (poMaskBand)
4314
0
        {
4315
0
            pabyMaskData =
4316
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4317
0
            if (!pabyMaskData)
4318
0
            {
4319
0
                CPLFree(pData);
4320
0
                return CE_Failure;
4321
0
            }
4322
4323
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4324
0
                                     pabyMaskData, nXReduced, nYReduced,
4325
0
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
4326
0
            {
4327
0
                CPLFree(pData);
4328
0
                CPLFree(pabyMaskData);
4329
0
                return CE_Failure;
4330
0
            }
4331
0
        }
4332
4333
        // This isn't the fastest way to do this, but is easier for now.
4334
0
        for (int iY = 0; iY < nYReduced; iY++)
4335
0
        {
4336
0
            for (int iX = 0; iX < nXReduced; iX++)
4337
0
            {
4338
0
                const int iOffset = iX + iY * nXReduced;
4339
0
                double dfValue = 0.0;
4340
4341
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
4342
0
                    continue;
4343
4344
0
                switch (eDataType)
4345
0
                {
4346
0
                    case GDT_Byte:
4347
0
                    {
4348
0
                        if (bSignedByte)
4349
0
                            dfValue =
4350
0
                                static_cast<signed char *>(pData)[iOffset];
4351
0
                        else
4352
0
                            dfValue = static_cast<GByte *>(pData)[iOffset];
4353
0
                        break;
4354
0
                    }
4355
0
                    case GDT_Int8:
4356
0
                        dfValue = static_cast<GInt8 *>(pData)[iOffset];
4357
0
                        break;
4358
0
                    case GDT_UInt16:
4359
0
                        dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4360
0
                        break;
4361
0
                    case GDT_Int16:
4362
0
                        dfValue = static_cast<GInt16 *>(pData)[iOffset];
4363
0
                        break;
4364
0
                    case GDT_UInt32:
4365
0
                        dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4366
0
                        break;
4367
0
                    case GDT_Int32:
4368
0
                        dfValue = static_cast<GInt32 *>(pData)[iOffset];
4369
0
                        break;
4370
0
                    case GDT_UInt64:
4371
0
                        dfValue = static_cast<double>(
4372
0
                            static_cast<GUInt64 *>(pData)[iOffset]);
4373
0
                        break;
4374
0
                    case GDT_Int64:
4375
0
                        dfValue = static_cast<double>(
4376
0
                            static_cast<GInt64 *>(pData)[iOffset]);
4377
0
                        break;
4378
0
                    case GDT_Float16:
4379
0
                    {
4380
0
                        using namespace std;
4381
0
                        const GFloat16 hfValue =
4382
0
                            static_cast<GFloat16 *>(pData)[iOffset];
4383
0
                        if (isnan(hfValue) ||
4384
0
                            (sNoDataValues.bGotFloat16NoDataValue &&
4385
0
                             ARE_REAL_EQUAL(hfValue,
4386
0
                                            sNoDataValues.hfNoDataValue)))
4387
0
                            continue;
4388
0
                        dfValue = hfValue;
4389
0
                        break;
4390
0
                    }
4391
0
                    case GDT_Float32:
4392
0
                    {
4393
0
                        const float fValue =
4394
0
                            static_cast<float *>(pData)[iOffset];
4395
0
                        if (std::isnan(fValue) ||
4396
0
                            (sNoDataValues.bGotFloatNoDataValue &&
4397
0
                             ARE_REAL_EQUAL(fValue,
4398
0
                                            sNoDataValues.fNoDataValue)))
4399
0
                            continue;
4400
0
                        dfValue = double(fValue);
4401
0
                        break;
4402
0
                    }
4403
0
                    case GDT_Float64:
4404
0
                        dfValue = static_cast<double *>(pData)[iOffset];
4405
0
                        if (std::isnan(dfValue))
4406
0
                            continue;
4407
0
                        break;
4408
0
                    case GDT_CInt16:
4409
0
                    {
4410
0
                        const double dfReal =
4411
0
                            static_cast<GInt16 *>(pData)[iOffset * 2];
4412
0
                        const double dfImag =
4413
0
                            static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4414
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4415
0
                            continue;
4416
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4417
0
                    }
4418
0
                    break;
4419
0
                    case GDT_CInt32:
4420
0
                    {
4421
0
                        const double dfReal =
4422
0
                            static_cast<GInt32 *>(pData)[iOffset * 2];
4423
0
                        const double dfImag =
4424
0
                            static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4425
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4426
0
                            continue;
4427
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4428
0
                    }
4429
0
                    break;
4430
0
                    case GDT_CFloat16:
4431
0
                    {
4432
0
                        const double dfReal =
4433
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2];
4434
0
                        const double dfImag =
4435
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4436
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4437
0
                            continue;
4438
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4439
0
                        break;
4440
0
                    }
4441
0
                    case GDT_CFloat32:
4442
0
                    {
4443
0
                        const double dfReal =
4444
0
                            double(static_cast<float *>(pData)[iOffset * 2]);
4445
0
                        const double dfImag = double(
4446
0
                            static_cast<float *>(pData)[iOffset * 2 + 1]);
4447
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4448
0
                            continue;
4449
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4450
0
                        break;
4451
0
                    }
4452
0
                    case GDT_CFloat64:
4453
0
                    {
4454
0
                        const double dfReal =
4455
0
                            static_cast<double *>(pData)[iOffset * 2];
4456
0
                        const double dfImag =
4457
0
                            static_cast<double *>(pData)[iOffset * 2 + 1];
4458
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4459
0
                            continue;
4460
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4461
0
                        break;
4462
0
                    }
4463
0
                    case GDT_Unknown:
4464
0
                    case GDT_TypeCount:
4465
0
                        CPLAssert(false);
4466
0
                }
4467
4468
0
                if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4469
0
                    sNoDataValues.bGotNoDataValue &&
4470
0
                    ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4471
0
                    continue;
4472
4473
                // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4474
                // finite, the result of the multiplication cannot be NaN
4475
0
                const double dfIndex = floor((dfValue - dfMin) * dfScale);
4476
4477
0
                if (dfIndex < 0)
4478
0
                {
4479
0
                    if (bIncludeOutOfRange)
4480
0
                        panHistogram[0]++;
4481
0
                }
4482
0
                else if (dfIndex >= nBuckets)
4483
0
                {
4484
0
                    if (bIncludeOutOfRange)
4485
0
                        ++panHistogram[nBuckets - 1];
4486
0
                }
4487
0
                else
4488
0
                {
4489
0
                    ++panHistogram[static_cast<int>(dfIndex)];
4490
0
                }
4491
0
            }
4492
0
        }
4493
4494
0
        CPLFree(pData);
4495
0
        CPLFree(pabyMaskData);
4496
0
    }
4497
0
    else  // No arbitrary overviews.
4498
0
    {
4499
0
        if (!InitBlockInfo())
4500
0
            return CE_Failure;
4501
4502
        /* --------------------------------------------------------------------
4503
         */
4504
        /*      Figure out the ratio of blocks we will read to get an */
4505
        /*      approximate value. */
4506
        /* --------------------------------------------------------------------
4507
         */
4508
4509
0
        int nSampleRate = 1;
4510
0
        if (bApproxOK)
4511
0
        {
4512
0
            nSampleRate = static_cast<int>(std::max(
4513
0
                1.0,
4514
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4515
            // We want to avoid probing only the first column of blocks for
4516
            // a square shaped raster, because it is not unlikely that it may
4517
            // be padding only (#6378).
4518
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4519
0
                nSampleRate += 1;
4520
0
        }
4521
4522
0
        GByte *pabyMaskData = nullptr;
4523
0
        if (poMaskBand)
4524
0
        {
4525
0
            pabyMaskData = static_cast<GByte *>(
4526
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4527
0
            if (!pabyMaskData)
4528
0
            {
4529
0
                return CE_Failure;
4530
0
            }
4531
0
        }
4532
4533
        /* --------------------------------------------------------------------
4534
         */
4535
        /*      Read the blocks, and add to histogram. */
4536
        /* --------------------------------------------------------------------
4537
         */
4538
0
        for (GIntBig iSampleBlock = 0;
4539
0
             iSampleBlock <
4540
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4541
0
             iSampleBlock += nSampleRate)
4542
0
        {
4543
0
            if (!pfnProgress(
4544
0
                    static_cast<double>(iSampleBlock) /
4545
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4546
0
                    "Compute Histogram", pProgressData))
4547
0
            {
4548
0
                CPLFree(pabyMaskData);
4549
0
                return CE_Failure;
4550
0
            }
4551
4552
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4553
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4554
4555
0
            int nXCheck = 0, nYCheck = 0;
4556
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4557
4558
0
            if (poMaskBand &&
4559
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4560
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
4561
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4562
0
                                     0, nBlockXSize, nullptr) != CE_None)
4563
0
            {
4564
0
                CPLFree(pabyMaskData);
4565
0
                return CE_Failure;
4566
0
            }
4567
4568
0
            GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4569
0
            if (poBlock == nullptr)
4570
0
            {
4571
0
                CPLFree(pabyMaskData);
4572
0
                return CE_Failure;
4573
0
            }
4574
4575
0
            void *pData = poBlock->GetDataRef();
4576
4577
            // this is a special case for a common situation.
4578
0
            if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4579
0
                (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4580
0
                nXCheck == nBlockXSize && nBuckets == 256)
4581
0
            {
4582
0
                const GPtrDiff_t nPixels =
4583
0
                    static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4584
0
                GByte *pabyData = static_cast<GByte *>(pData);
4585
4586
0
                for (GPtrDiff_t i = 0; i < nPixels; i++)
4587
0
                {
4588
0
                    if (pabyMaskData && pabyMaskData[i] == 0)
4589
0
                        continue;
4590
0
                    if (!(sNoDataValues.bGotNoDataValue &&
4591
0
                          (pabyData[i] ==
4592
0
                           static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4593
0
                    {
4594
0
                        panHistogram[pabyData[i]]++;
4595
0
                    }
4596
0
                }
4597
4598
0
                poBlock->DropLock();
4599
0
                continue;  // To next sample block.
4600
0
            }
4601
4602
            // This isn't the fastest way to do this, but is easier for now.
4603
0
            for (int iY = 0; iY < nYCheck; iY++)
4604
0
            {
4605
0
                for (int iX = 0; iX < nXCheck; iX++)
4606
0
                {
4607
0
                    const GPtrDiff_t iOffset =
4608
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4609
4610
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
4611
0
                        continue;
4612
4613
0
                    double dfValue = 0.0;
4614
4615
0
                    switch (eDataType)
4616
0
                    {
4617
0
                        case GDT_Byte:
4618
0
                        {
4619
0
                            if (bSignedByte)
4620
0
                                dfValue =
4621
0
                                    static_cast<signed char *>(pData)[iOffset];
4622
0
                            else
4623
0
                                dfValue = static_cast<GByte *>(pData)[iOffset];
4624
0
                            break;
4625
0
                        }
4626
0
                        case GDT_Int8:
4627
0
                            dfValue = static_cast<GInt8 *>(pData)[iOffset];
4628
0
                            break;
4629
0
                        case GDT_UInt16:
4630
0
                            dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4631
0
                            break;
4632
0
                        case GDT_Int16:
4633
0
                            dfValue = static_cast<GInt16 *>(pData)[iOffset];
4634
0
                            break;
4635
0
                        case GDT_UInt32:
4636
0
                            dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4637
0
                            break;
4638
0
                        case GDT_Int32:
4639
0
                            dfValue = static_cast<GInt32 *>(pData)[iOffset];
4640
0
                            break;
4641
0
                        case GDT_UInt64:
4642
0
                            dfValue = static_cast<double>(
4643
0
                                static_cast<GUInt64 *>(pData)[iOffset]);
4644
0
                            break;
4645
0
                        case GDT_Int64:
4646
0
                            dfValue = static_cast<double>(
4647
0
                                static_cast<GInt64 *>(pData)[iOffset]);
4648
0
                            break;
4649
0
                        case GDT_Float16:
4650
0
                        {
4651
0
                            using namespace std;
4652
0
                            const GFloat16 hfValue =
4653
0
                                static_cast<GFloat16 *>(pData)[iOffset];
4654
0
                            if (isnan(hfValue) ||
4655
0
                                (sNoDataValues.bGotFloat16NoDataValue &&
4656
0
                                 ARE_REAL_EQUAL(hfValue,
4657
0
                                                sNoDataValues.hfNoDataValue)))
4658
0
                                continue;
4659
0
                            dfValue = hfValue;
4660
0
                            break;
4661
0
                        }
4662
0
                        case GDT_Float32:
4663
0
                        {
4664
0
                            const float fValue =
4665
0
                                static_cast<float *>(pData)[iOffset];
4666
0
                            if (std::isnan(fValue) ||
4667
0
                                (sNoDataValues.bGotFloatNoDataValue &&
4668
0
                                 ARE_REAL_EQUAL(fValue,
4669
0
                                                sNoDataValues.fNoDataValue)))
4670
0
                                continue;
4671
0
                            dfValue = double(fValue);
4672
0
                            break;
4673
0
                        }
4674
0
                        case GDT_Float64:
4675
0
                            dfValue = static_cast<double *>(pData)[iOffset];
4676
0
                            if (std::isnan(dfValue))
4677
0
                                continue;
4678
0
                            break;
4679
0
                        case GDT_CInt16:
4680
0
                        {
4681
0
                            double dfReal =
4682
0
                                static_cast<GInt16 *>(pData)[iOffset * 2];
4683
0
                            double dfImag =
4684
0
                                static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4685
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4686
0
                            break;
4687
0
                        }
4688
0
                        case GDT_CInt32:
4689
0
                        {
4690
0
                            double dfReal =
4691
0
                                static_cast<GInt32 *>(pData)[iOffset * 2];
4692
0
                            double dfImag =
4693
0
                                static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4694
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4695
0
                            break;
4696
0
                        }
4697
0
                        case GDT_CFloat16:
4698
0
                        {
4699
0
                            double dfReal =
4700
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2];
4701
0
                            double dfImag =
4702
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4703
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4704
0
                                continue;
4705
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4706
0
                            break;
4707
0
                        }
4708
0
                        case GDT_CFloat32:
4709
0
                        {
4710
0
                            double dfReal = double(
4711
0
                                static_cast<float *>(pData)[iOffset * 2]);
4712
0
                            double dfImag = double(
4713
0
                                static_cast<float *>(pData)[iOffset * 2 + 1]);
4714
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4715
0
                                continue;
4716
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4717
0
                            break;
4718
0
                        }
4719
0
                        case GDT_CFloat64:
4720
0
                        {
4721
0
                            double dfReal =
4722
0
                                static_cast<double *>(pData)[iOffset * 2];
4723
0
                            double dfImag =
4724
0
                                static_cast<double *>(pData)[iOffset * 2 + 1];
4725
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4726
0
                                continue;
4727
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4728
0
                            break;
4729
0
                        }
4730
0
                        case GDT_Unknown:
4731
0
                        case GDT_TypeCount:
4732
0
                            CPLAssert(false);
4733
0
                            CPLFree(pabyMaskData);
4734
0
                            return CE_Failure;
4735
0
                    }
4736
4737
0
                    if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4738
0
                        sNoDataValues.bGotNoDataValue &&
4739
0
                        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4740
0
                        continue;
4741
4742
                    // Given that dfValue and dfMin are not NaN, and dfScale > 0
4743
                    // and finite, the result of the multiplication cannot be
4744
                    // NaN
4745
0
                    const double dfIndex = floor((dfValue - dfMin) * dfScale);
4746
4747
0
                    if (dfIndex < 0)
4748
0
                    {
4749
0
                        if (bIncludeOutOfRange)
4750
0
                            panHistogram[0]++;
4751
0
                    }
4752
0
                    else if (dfIndex >= nBuckets)
4753
0
                    {
4754
0
                        if (bIncludeOutOfRange)
4755
0
                            ++panHistogram[nBuckets - 1];
4756
0
                    }
4757
0
                    else
4758
0
                    {
4759
0
                        ++panHistogram[static_cast<int>(dfIndex)];
4760
0
                    }
4761
0
                }
4762
0
            }
4763
4764
0
            poBlock->DropLock();
4765
0
        }
4766
4767
0
        CPLFree(pabyMaskData);
4768
0
    }
4769
4770
0
    pfnProgress(1.0, "Compute Histogram", pProgressData);
4771
4772
0
    return CE_None;
4773
0
}
4774
4775
/************************************************************************/
4776
/*                       GDALGetRasterHistogram()                       */
4777
/************************************************************************/
4778
4779
/**
4780
 * \brief Compute raster histogram.
4781
 *
4782
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4783
 * exceeding 2 billion.
4784
 *
4785
 * @see GDALRasterBand::GetHistogram()
4786
 * @see GDALGetRasterHistogramEx()
4787
 */
4788
4789
CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4790
                                          double dfMax, int nBuckets,
4791
                                          int *panHistogram,
4792
                                          int bIncludeOutOfRange, int bApproxOK,
4793
                                          GDALProgressFunc pfnProgress,
4794
                                          void *pProgressData)
4795
4796
0
{
4797
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4798
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4799
4800
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4801
4802
0
    GUIntBig *panHistogramTemp =
4803
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4804
0
    if (panHistogramTemp == nullptr)
4805
0
    {
4806
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4807
0
                            "Out of memory in GDALGetRasterHistogram().");
4808
0
        return CE_Failure;
4809
0
    }
4810
4811
0
    CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4812
0
                                       bIncludeOutOfRange, bApproxOK,
4813
0
                                       pfnProgress, pProgressData);
4814
4815
0
    if (eErr == CE_None)
4816
0
    {
4817
0
        for (int i = 0; i < nBuckets; i++)
4818
0
        {
4819
0
            if (panHistogramTemp[i] > INT_MAX)
4820
0
            {
4821
0
                CPLError(CE_Warning, CPLE_AppDefined,
4822
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
4823
0
                         " exceeds maximum 32 bit value",
4824
0
                         i, panHistogramTemp[i]);
4825
0
                panHistogram[i] = INT_MAX;
4826
0
            }
4827
0
            else
4828
0
            {
4829
0
                panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4830
0
            }
4831
0
        }
4832
0
    }
4833
4834
0
    CPLFree(panHistogramTemp);
4835
4836
0
    return eErr;
4837
0
}
4838
4839
/************************************************************************/
4840
/*                      GDALGetRasterHistogramEx()                      */
4841
/************************************************************************/
4842
4843
/**
4844
 * \brief Compute raster histogram.
4845
 *
4846
 * @see GDALRasterBand::GetHistogram()
4847
 *
4848
 */
4849
4850
CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4851
    GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4852
    GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4853
    GDALProgressFunc pfnProgress, void *pProgressData)
4854
4855
0
{
4856
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4857
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4858
4859
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4860
4861
0
    return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4862
0
                                bIncludeOutOfRange, bApproxOK, pfnProgress,
4863
0
                                pProgressData);
4864
0
}
4865
4866
/************************************************************************/
4867
/*                        GetDefaultHistogram()                         */
4868
/************************************************************************/
4869
4870
/**
4871
 * \brief Fetch default raster histogram.
4872
 *
4873
 * The default method in GDALRasterBand will compute a default histogram. This
4874
 * method is overridden by derived classes (such as GDALPamRasterBand,
4875
 * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4876
 * stored histogram.
4877
 *
4878
 * This method is the same as the C functions GDALGetDefaultHistogram() and
4879
 * GDALGetDefaultHistogramEx().
4880
 *
4881
 * @param pdfMin pointer to double value that will contain the lower bound of
4882
 * the histogram.
4883
 * @param pdfMax pointer to double value that will contain the upper bound of
4884
 * the histogram.
4885
 * @param pnBuckets pointer to int value that will contain the number of buckets
4886
 * in *ppanHistogram.
4887
 * @param ppanHistogram pointer to array into which the histogram totals are
4888
 * placed. To be freed with VSIFree
4889
 * @param bForce TRUE to force the computation. If FALSE and no default
4890
 * histogram is available, the method will return CE_Warning
4891
 * @param pfnProgress function to report progress to completion.
4892
 * @param pProgressData application data to pass to pfnProgress.
4893
 *
4894
 * @return CE_None on success, CE_Failure if something goes wrong, or
4895
 * CE_Warning if no default histogram is available.
4896
 */
4897
4898
CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4899
                                           int *pnBuckets,
4900
                                           GUIntBig **ppanHistogram, int bForce,
4901
                                           GDALProgressFunc pfnProgress,
4902
                                           void *pProgressData)
4903
4904
0
{
4905
0
    CPLAssert(nullptr != pnBuckets);
4906
0
    CPLAssert(nullptr != ppanHistogram);
4907
0
    CPLAssert(nullptr != pdfMin);
4908
0
    CPLAssert(nullptr != pdfMax);
4909
4910
0
    *pnBuckets = 0;
4911
0
    *ppanHistogram = nullptr;
4912
4913
0
    if (!bForce)
4914
0
        return CE_Warning;
4915
4916
0
    int nBuckets = 256;
4917
4918
0
    bool bSignedByte = false;
4919
0
    if (eDataType == GDT_Byte)
4920
0
    {
4921
0
        EnablePixelTypeSignedByteWarning(false);
4922
0
        const char *pszPixelType =
4923
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4924
0
        EnablePixelTypeSignedByteWarning(true);
4925
0
        bSignedByte =
4926
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4927
0
    }
4928
4929
0
    if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4930
0
    {
4931
0
        *pdfMin = -0.5;
4932
0
        *pdfMax = 255.5;
4933
0
    }
4934
0
    else if (GetRasterDataType() == GDT_Int8)
4935
0
    {
4936
0
        *pdfMin = -128 - 0.5;
4937
0
        *pdfMax = 127 + 0.5;
4938
0
    }
4939
0
    else
4940
0
    {
4941
4942
0
        const CPLErr eErr =
4943
0
            GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4944
0
        if (eErr != CE_None)
4945
0
            return eErr;
4946
0
        if (*pdfMin == *pdfMax)
4947
0
        {
4948
0
            nBuckets = 1;
4949
0
            *pdfMin -= 0.5;
4950
0
            *pdfMax += 0.5;
4951
0
        }
4952
0
        else
4953
0
        {
4954
0
            const double dfHalfBucket =
4955
0
                (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4956
0
            *pdfMin -= dfHalfBucket;
4957
0
            *pdfMax += dfHalfBucket;
4958
0
        }
4959
0
    }
4960
4961
0
    *ppanHistogram =
4962
0
        static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4963
0
    if (*ppanHistogram == nullptr)
4964
0
    {
4965
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
4966
0
                    "Out of memory in InitBlockInfo().");
4967
0
        return CE_Failure;
4968
0
    }
4969
4970
0
    *pnBuckets = nBuckets;
4971
0
    CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4972
0
                               TRUE, FALSE, pfnProgress, pProgressData);
4973
0
    if (eErr != CE_None)
4974
0
    {
4975
0
        *pnBuckets = 0;
4976
0
    }
4977
0
    return eErr;
4978
0
}
4979
4980
/************************************************************************/
4981
/*                      GDALGetDefaultHistogram()                       */
4982
/************************************************************************/
4983
4984
/**
4985
 * \brief Fetch default raster histogram.
4986
 *
4987
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4988
 * exceeding 2 billion.
4989
 *
4990
 * @see GDALRasterBand::GDALGetDefaultHistogram()
4991
 * @see GDALGetRasterHistogramEx()
4992
 */
4993
4994
CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4995
                                           double *pdfMin, double *pdfMax,
4996
                                           int *pnBuckets, int **ppanHistogram,
4997
                                           int bForce,
4998
                                           GDALProgressFunc pfnProgress,
4999
                                           void *pProgressData)
5000
5001
0
{
5002
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5003
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5004
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5005
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5006
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5007
5008
0
    GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
5009
0
    GUIntBig *panHistogramTemp = nullptr;
5010
0
    CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
5011
0
                                              &panHistogramTemp, bForce,
5012
0
                                              pfnProgress, pProgressData);
5013
0
    if (eErr == CE_None)
5014
0
    {
5015
0
        const int nBuckets = *pnBuckets;
5016
0
        *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5017
0
        if (*ppanHistogram == nullptr)
5018
0
        {
5019
0
            poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5020
0
                                "Out of memory in GDALGetDefaultHistogram().");
5021
0
            VSIFree(panHistogramTemp);
5022
0
            return CE_Failure;
5023
0
        }
5024
5025
0
        for (int i = 0; i < nBuckets; ++i)
5026
0
        {
5027
0
            if (panHistogramTemp[i] > INT_MAX)
5028
0
            {
5029
0
                CPLError(CE_Warning, CPLE_AppDefined,
5030
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
5031
0
                         " exceeds maximum 32 bit value",
5032
0
                         i, panHistogramTemp[i]);
5033
0
                (*ppanHistogram)[i] = INT_MAX;
5034
0
            }
5035
0
            else
5036
0
            {
5037
0
                (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5038
0
            }
5039
0
        }
5040
5041
0
        CPLFree(panHistogramTemp);
5042
0
    }
5043
0
    else
5044
0
    {
5045
0
        *ppanHistogram = nullptr;
5046
0
    }
5047
5048
0
    return eErr;
5049
0
}
5050
5051
/************************************************************************/
5052
/*                      GDALGetDefaultHistogramEx()                     */
5053
/************************************************************************/
5054
5055
/**
5056
 * \brief Fetch default raster histogram.
5057
 *
5058
 * @see GDALRasterBand::GetDefaultHistogram()
5059
 *
5060
 */
5061
5062
CPLErr CPL_STDCALL
5063
GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5064
                          int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5065
                          GDALProgressFunc pfnProgress, void *pProgressData)
5066
5067
0
{
5068
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5069
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5070
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5071
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5072
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5073
5074
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5075
0
    return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5076
0
                                       bForce, pfnProgress, pProgressData);
5077
0
}
5078
5079
/************************************************************************/
5080
/*                             AdviseRead()                             */
5081
/************************************************************************/
5082
5083
/**
5084
 * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5085
 * \brief Advise driver of upcoming read requests.
5086
 *
5087
 * Some GDAL drivers operate more efficiently if they know in advance what
5088
 * set of upcoming read requests will be made.  The AdviseRead() method allows
5089
 * an application to notify the driver of the region of interest,
5090
 * and at what resolution the region will be read.
5091
 *
5092
 * Many drivers just ignore the AdviseRead() call, but it can dramatically
5093
 * accelerate access via some drivers.
5094
 *
5095
 * Depending on call paths, drivers might receive several calls to
5096
 * AdviseRead() with the same parameters.
5097
 *
5098
 * @param nXOff The pixel offset to the top left corner of the region
5099
 * of the band to be accessed.  This would be zero to start from the left side.
5100
 *
5101
 * @param nYOff The line offset to the top left corner of the region
5102
 * of the band to be accessed.  This would be zero to start from the top.
5103
 *
5104
 * @param nXSize The width of the region of the band to be accessed in pixels.
5105
 *
5106
 * @param nYSize The height of the region of the band to be accessed in lines.
5107
 *
5108
 * @param nBufXSize the width of the buffer image into which the desired region
5109
 * is to be read, or from which it is to be written.
5110
 *
5111
 * @param nBufYSize the height of the buffer image into which the desired
5112
 * region is to be read, or from which it is to be written.
5113
 *
5114
 * @param eBufType the type of the pixel values in the pData data buffer.  The
5115
 * pixel values will automatically be translated to/from the GDALRasterBand
5116
 * data type as needed.
5117
 *
5118
 * @param papszOptions a list of name=value strings with special control
5119
 * options.  Normally this is NULL.
5120
 *
5121
 * @return CE_Failure if the request is invalid and CE_None if it works or
5122
 * is ignored.
5123
 */
5124
5125
/**/
5126
/**/
5127
5128
CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5129
                                  int /*nYSize*/, int /*nBufXSize*/,
5130
                                  int /*nBufYSize*/, GDALDataType /*eBufType*/,
5131
                                  char ** /*papszOptions*/)
5132
0
{
5133
0
    return CE_None;
5134
0
}
5135
5136
/************************************************************************/
5137
/*                        GDALRasterAdviseRead()                        */
5138
/************************************************************************/
5139
5140
/**
5141
 * \brief Advise driver of upcoming read requests.
5142
 *
5143
 * @see GDALRasterBand::AdviseRead()
5144
 */
5145
5146
CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5147
                                        int nYOff, int nXSize, int nYSize,
5148
                                        int nBufXSize, int nBufYSize,
5149
                                        GDALDataType eDT,
5150
                                        CSLConstList papszOptions)
5151
5152
0
{
5153
0
    VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5154
5155
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5156
0
    return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5157
0
                              nBufYSize, eDT,
5158
0
                              const_cast<char **>(papszOptions));
5159
0
}
5160
5161
/************************************************************************/
5162
/*                           GetStatistics()                            */
5163
/************************************************************************/
5164
5165
/**
5166
 * \brief Fetch image statistics.
5167
 *
5168
 * Returns the minimum, maximum, mean and standard deviation of all
5169
 * pixel values in this band.  If approximate statistics are sufficient,
5170
 * the bApproxOK flag can be set to true in which case overviews, or a
5171
 * subset of image tiles may be used in computing the statistics.
5172
 *
5173
 * If bForce is FALSE results will only be returned if it can be done
5174
 * quickly (i.e. without scanning the image, typically by using pre-existing
5175
 * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5176
 * returned efficiently, the method will return CE_Warning but no warning will
5177
 * be issued. This is a non-standard use of the CE_Warning return value
5178
 * to indicate "nothing done".
5179
 *
5180
 * If bForce is TRUE, and results are quickly available without scanning the
5181
 * image, they will be used. If bForce is TRUE and results are not quickly
5182
 * available, GetStatistics() forwards the computation to ComputeStatistics(),
5183
 * which will scan the image.
5184
 *
5185
 * To always force recomputation of statistics, use ComputeStatistics() instead
5186
 * of this method.
5187
 *
5188
 * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5189
 * will generally cache statistics in the .pam file allowing fast fetch
5190
 * after the first request.
5191
 *
5192
 * This method is the same as the C function GDALGetRasterStatistics().
5193
 *
5194
 * @param bApproxOK If TRUE statistics may be computed based on overviews
5195
 * or a subset of all tiles.
5196
 *
5197
 * @param bForce If FALSE statistics will only be returned if it can
5198
 * be done without rescanning the image. If TRUE, statistics computation will
5199
 * be forced if pre-existing values are not quickly available.
5200
 *
5201
 * @param pdfMin Location into which to load image minimum (may be NULL).
5202
 *
5203
 * @param pdfMax Location into which to load image maximum (may be NULL).-
5204
 *
5205
 * @param pdfMean Location into which to load image mean (may be NULL).
5206
 *
5207
 * @param pdfStdDev Location into which to load image standard deviation
5208
 * (may be NULL).
5209
 *
5210
 * @return CE_None on success, CE_Warning if no values returned,
5211
 * CE_Failure if an error occurs.
5212
 */
5213
5214
CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5215
                                     double *pdfMax, double *pdfMean,
5216
                                     double *pdfStdDev)
5217
5218
0
{
5219
    /* -------------------------------------------------------------------- */
5220
    /*      Do we already have metadata items for the requested values?     */
5221
    /* -------------------------------------------------------------------- */
5222
0
    if ((pdfMin == nullptr ||
5223
0
         GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5224
0
        (pdfMax == nullptr ||
5225
0
         GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5226
0
        (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5227
0
        (pdfStdDev == nullptr ||
5228
0
         GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5229
0
    {
5230
0
        if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5231
0
        {
5232
0
            if (pdfMin != nullptr)
5233
0
                *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5234
0
            if (pdfMax != nullptr)
5235
0
                *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5236
0
            if (pdfMean != nullptr)
5237
0
                *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5238
0
            if (pdfStdDev != nullptr)
5239
0
                *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5240
5241
0
            return CE_None;
5242
0
        }
5243
0
    }
5244
5245
    /* -------------------------------------------------------------------- */
5246
    /*      Does the driver already know the min/max?                       */
5247
    /* -------------------------------------------------------------------- */
5248
0
    if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5249
0
    {
5250
0
        int bSuccessMin = FALSE;
5251
0
        int bSuccessMax = FALSE;
5252
5253
0
        const double dfMin = GetMinimum(&bSuccessMin);
5254
0
        const double dfMax = GetMaximum(&bSuccessMax);
5255
5256
0
        if (bSuccessMin && bSuccessMax)
5257
0
        {
5258
0
            if (pdfMin != nullptr)
5259
0
                *pdfMin = dfMin;
5260
0
            if (pdfMax != nullptr)
5261
0
                *pdfMax = dfMax;
5262
0
            return CE_None;
5263
0
        }
5264
0
    }
5265
5266
    /* -------------------------------------------------------------------- */
5267
    /*      Either return without results, or force computation.            */
5268
    /* -------------------------------------------------------------------- */
5269
0
    if (!bForce)
5270
0
        return CE_Warning;
5271
0
    else
5272
0
        return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5273
0
                                 GDALDummyProgress, nullptr);
5274
0
}
5275
5276
/************************************************************************/
5277
/*                      GDALGetRasterStatistics()                       */
5278
/************************************************************************/
5279
5280
/**
5281
 * \brief Fetch image statistics.
5282
 *
5283
 * @see GDALRasterBand::GetStatistics()
5284
 */
5285
5286
CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5287
                                           int bForce, double *pdfMin,
5288
                                           double *pdfMax, double *pdfMean,
5289
                                           double *pdfStdDev)
5290
5291
0
{
5292
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5293
5294
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5295
0
    return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5296
0
                                 pdfStdDev);
5297
0
}
5298
5299
/************************************************************************/
5300
/*                         GDALUInt128                                  */
5301
/************************************************************************/
5302
5303
#ifdef HAVE_UINT128_T
5304
class GDALUInt128
5305
{
5306
    __uint128_t val;
5307
5308
0
    explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5309
0
    {
5310
0
    }
5311
5312
  public:
5313
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5314
0
    {
5315
        // Evaluates to just a single mul on x86_64
5316
0
        return GDALUInt128(static_cast<__uint128_t>(first) * second);
5317
0
    }
5318
5319
    GDALUInt128 operator-(const GDALUInt128 &other) const
5320
0
    {
5321
0
        return GDALUInt128(val - other.val);
5322
0
    }
5323
5324
    operator double() const
5325
0
    {
5326
0
        return static_cast<double>(val);
5327
0
    }
5328
};
5329
#else
5330
5331
#if defined(_MSC_VER) && defined(_M_X64)
5332
#include <intrin.h>
5333
#endif
5334
5335
class GDALUInt128
5336
{
5337
    GUIntBig low, high;
5338
5339
    GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5340
    {
5341
    }
5342
5343
  public:
5344
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5345
    {
5346
#if defined(_MSC_VER) && defined(_M_X64)
5347
        GUIntBig highRes;
5348
        GUIntBig lowRes = _umul128(first, second, &highRes);
5349
        return GDALUInt128(lowRes, highRes);
5350
#else
5351
        const GUInt32 firstLow = static_cast<GUInt32>(first);
5352
        const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5353
        const GUInt32 secondLow = static_cast<GUInt32>(second);
5354
        const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5355
        GUIntBig highRes = 0;
5356
        const GUIntBig firstLowSecondHigh =
5357
            static_cast<GUIntBig>(firstLow) * secondHigh;
5358
        const GUIntBig firstHighSecondLow =
5359
            static_cast<GUIntBig>(firstHigh) * secondLow;
5360
        const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5361
        if (middleTerm < firstLowSecondHigh)  // check for overflow
5362
            highRes += static_cast<GUIntBig>(1) << 32;
5363
        const GUIntBig firstLowSecondLow =
5364
            static_cast<GUIntBig>(firstLow) * secondLow;
5365
        GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5366
        if (lowRes < firstLowSecondLow)  // check for overflow
5367
            highRes++;
5368
        highRes +=
5369
            (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5370
        return GDALUInt128(lowRes, highRes);
5371
#endif
5372
    }
5373
5374
    GDALUInt128 operator-(const GDALUInt128 &other) const
5375
    {
5376
        GUIntBig highRes = high - other.high;
5377
        GUIntBig lowRes = low - other.low;
5378
        if (lowRes > low)  // check for underflow
5379
            --highRes;
5380
        return GDALUInt128(lowRes, highRes);
5381
    }
5382
5383
    operator double() const
5384
    {
5385
        const double twoPow64 = 18446744073709551616.0;
5386
        return high * twoPow64 + low;
5387
    }
5388
};
5389
#endif
5390
5391
/************************************************************************/
5392
/*                    ComputeStatisticsInternal()                       */
5393
/************************************************************************/
5394
5395
// Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5396
// not needed.
5397
0
#define static_cast_for_coverity_scan static_cast
5398
5399
// The rationale for below optimizations is detailed in statistics.txt
5400
5401
// Use with T = GByte or GUInt16 only !
5402
template <class T, bool COMPUTE_OTHER_STATS>
5403
struct ComputeStatisticsInternalGeneric
5404
{
5405
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5406
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5407
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5408
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5409
0
    {
5410
0
        static_assert(std::is_same<T, GByte>::value ||
5411
0
                          std::is_same<T, GUInt16>::value,
5412
0
                      "bad type for T");
5413
0
        if (bHasNoData)
5414
0
        {
5415
            // General case
5416
0
            for (int iY = 0; iY < nYCheck; iY++)
5417
0
            {
5418
0
                for (int iX = 0; iX < nXCheck; iX++)
5419
0
                {
5420
0
                    const GPtrDiff_t iOffset =
5421
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5422
0
                    const GUInt32 nValue = pData[iOffset];
5423
0
                    if (nValue == nNoDataValue)
5424
0
                        continue;
5425
0
                    if (nValue < nMin)
5426
0
                        nMin = nValue;
5427
0
                    if (nValue > nMax)
5428
0
                        nMax = nValue;
5429
                    if constexpr (COMPUTE_OTHER_STATS)
5430
0
                    {
5431
0
                        nValidCount++;
5432
0
                        nSum += nValue;
5433
0
                        nSumSquare +=
5434
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5435
0
                            nValue;
5436
0
                    }
5437
0
                }
5438
0
            }
5439
            if constexpr (COMPUTE_OTHER_STATS)
5440
0
            {
5441
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5442
0
            }
5443
0
        }
5444
0
        else if (nMin == std::numeric_limits<T>::lowest() &&
5445
0
                 nMax == std::numeric_limits<T>::max())
5446
0
        {
5447
            if constexpr (COMPUTE_OTHER_STATS)
5448
0
            {
5449
                // Optimization when there is no nodata and we know we have already
5450
                // reached the min and max
5451
0
                for (int iY = 0; iY < nYCheck; iY++)
5452
0
                {
5453
0
                    int iX;
5454
0
                    for (iX = 0; iX + 3 < nXCheck; iX += 4)
5455
0
                    {
5456
0
                        const GPtrDiff_t iOffset =
5457
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5458
0
                        const GUIntBig nValue = pData[iOffset];
5459
0
                        const GUIntBig nValue2 = pData[iOffset + 1];
5460
0
                        const GUIntBig nValue3 = pData[iOffset + 2];
5461
0
                        const GUIntBig nValue4 = pData[iOffset + 3];
5462
0
                        nSum += nValue;
5463
0
                        nSumSquare += nValue * nValue;
5464
0
                        nSum += nValue2;
5465
0
                        nSumSquare += nValue2 * nValue2;
5466
0
                        nSum += nValue3;
5467
0
                        nSumSquare += nValue3 * nValue3;
5468
0
                        nSum += nValue4;
5469
0
                        nSumSquare += nValue4 * nValue4;
5470
0
                    }
5471
0
                    for (; iX < nXCheck; ++iX)
5472
0
                    {
5473
0
                        const GPtrDiff_t iOffset =
5474
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5475
0
                        const GUIntBig nValue = pData[iOffset];
5476
0
                        nSum += nValue;
5477
0
                        nSumSquare += nValue * nValue;
5478
0
                    }
5479
0
                }
5480
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5481
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5482
0
            }
5483
0
        }
5484
0
        else
5485
0
        {
5486
0
            for (int iY = 0; iY < nYCheck; iY++)
5487
0
            {
5488
0
                int iX;
5489
0
                for (iX = 0; iX + 1 < nXCheck; iX += 2)
5490
0
                {
5491
0
                    const GPtrDiff_t iOffset =
5492
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5493
0
                    const GUInt32 nValue = pData[iOffset];
5494
0
                    const GUInt32 nValue2 = pData[iOffset + 1];
5495
0
                    if (nValue < nValue2)
5496
0
                    {
5497
0
                        if (nValue < nMin)
5498
0
                            nMin = nValue;
5499
0
                        if (nValue2 > nMax)
5500
0
                            nMax = nValue2;
5501
0
                    }
5502
0
                    else
5503
0
                    {
5504
0
                        if (nValue2 < nMin)
5505
0
                            nMin = nValue2;
5506
0
                        if (nValue > nMax)
5507
0
                            nMax = nValue;
5508
0
                    }
5509
                    if constexpr (COMPUTE_OTHER_STATS)
5510
0
                    {
5511
0
                        nSum += nValue;
5512
0
                        nSumSquare +=
5513
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5514
0
                            nValue;
5515
0
                        nSum += nValue2;
5516
0
                        nSumSquare +=
5517
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5518
0
                            nValue2;
5519
0
                    }
5520
0
                }
5521
0
                if (iX < nXCheck)
5522
0
                {
5523
0
                    const GPtrDiff_t iOffset =
5524
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5525
0
                    const GUInt32 nValue = pData[iOffset];
5526
0
                    if (nValue < nMin)
5527
0
                        nMin = nValue;
5528
0
                    if (nValue > nMax)
5529
0
                        nMax = nValue;
5530
0
                    if (COMPUTE_OTHER_STATS)
5531
0
                    {
5532
0
                        nSum += nValue;
5533
0
                        nSumSquare +=
5534
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5535
0
                            nValue;
5536
0
                    }
5537
0
                }
5538
0
            }
5539
            if constexpr (COMPUTE_OTHER_STATS)
5540
0
            {
5541
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5542
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5543
0
            }
5544
0
        }
5545
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&)
5546
};
5547
5548
// Specialization for Byte that is mostly 32 bit friendly as it avoids
5549
// using 64bit accumulators in internal loops. This also slightly helps in
5550
// 64bit mode.
5551
template <bool COMPUTE_OTHER_STATS>
5552
struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5553
{
5554
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5555
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5556
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5557
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5558
0
    {
5559
0
        int nOuterLoops = nXCheck / 65536;
5560
0
        if (nXCheck % 65536)
5561
0
            nOuterLoops++;
5562
5563
0
        if (bHasNoData)
5564
0
        {
5565
            // General case
5566
0
            for (int iY = 0; iY < nYCheck; iY++)
5567
0
            {
5568
0
                int iX = 0;
5569
0
                for (int k = 0; k < nOuterLoops; k++)
5570
0
                {
5571
0
                    int iMax = iX + 65536;
5572
0
                    if (iMax > nXCheck)
5573
0
                        iMax = nXCheck;
5574
0
                    GUInt32 nSum32bit = 0;
5575
0
                    GUInt32 nSumSquare32bit = 0;
5576
0
                    GUInt32 nValidCount32bit = 0;
5577
0
                    GUInt32 nSampleCount32bit = 0;
5578
0
                    for (; iX < iMax; iX++)
5579
0
                    {
5580
0
                        const GPtrDiff_t iOffset =
5581
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5582
0
                        const GUInt32 nValue = pData[iOffset];
5583
5584
0
                        nSampleCount32bit++;
5585
0
                        if (nValue == nNoDataValue)
5586
0
                            continue;
5587
0
                        if (nValue < nMin)
5588
0
                            nMin = nValue;
5589
0
                        if (nValue > nMax)
5590
0
                            nMax = nValue;
5591
                        if constexpr (COMPUTE_OTHER_STATS)
5592
0
                        {
5593
0
                            nValidCount32bit++;
5594
0
                            nSum32bit += nValue;
5595
0
                            nSumSquare32bit += nValue * nValue;
5596
0
                        }
5597
0
                    }
5598
                    if constexpr (COMPUTE_OTHER_STATS)
5599
0
                    {
5600
0
                        nSampleCount += nSampleCount32bit;
5601
0
                        nValidCount += nValidCount32bit;
5602
0
                        nSum += nSum32bit;
5603
0
                        nSumSquare += nSumSquare32bit;
5604
0
                    }
5605
0
                }
5606
0
            }
5607
0
        }
5608
0
        else if (nMin == 0 && nMax == 255)
5609
0
        {
5610
            if constexpr (COMPUTE_OTHER_STATS)
5611
0
            {
5612
                // Optimization when there is no nodata and we know we have already
5613
                // reached the min and max
5614
0
                for (int iY = 0; iY < nYCheck; iY++)
5615
0
                {
5616
0
                    int iX = 0;
5617
0
                    for (int k = 0; k < nOuterLoops; k++)
5618
0
                    {
5619
0
                        int iMax = iX + 65536;
5620
0
                        if (iMax > nXCheck)
5621
0
                            iMax = nXCheck;
5622
0
                        GUInt32 nSum32bit = 0;
5623
0
                        GUInt32 nSumSquare32bit = 0;
5624
0
                        for (; iX + 3 < iMax; iX += 4)
5625
0
                        {
5626
0
                            const GPtrDiff_t iOffset =
5627
0
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5628
0
                            const GUInt32 nValue = pData[iOffset];
5629
0
                            const GUInt32 nValue2 = pData[iOffset + 1];
5630
0
                            const GUInt32 nValue3 = pData[iOffset + 2];
5631
0
                            const GUInt32 nValue4 = pData[iOffset + 3];
5632
0
                            nSum32bit += nValue;
5633
0
                            nSumSquare32bit += nValue * nValue;
5634
0
                            nSum32bit += nValue2;
5635
0
                            nSumSquare32bit += nValue2 * nValue2;
5636
0
                            nSum32bit += nValue3;
5637
0
                            nSumSquare32bit += nValue3 * nValue3;
5638
0
                            nSum32bit += nValue4;
5639
0
                            nSumSquare32bit += nValue4 * nValue4;
5640
0
                        }
5641
0
                        nSum += nSum32bit;
5642
0
                        nSumSquare += nSumSquare32bit;
5643
0
                    }
5644
0
                    for (; iX < nXCheck; ++iX)
5645
0
                    {
5646
0
                        const GPtrDiff_t iOffset =
5647
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5648
0
                        const GUIntBig nValue = pData[iOffset];
5649
0
                        nSum += nValue;
5650
0
                        nSumSquare += nValue * nValue;
5651
0
                    }
5652
0
                }
5653
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5654
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5655
0
            }
5656
0
        }
5657
0
        else
5658
0
        {
5659
0
            for (int iY = 0; iY < nYCheck; iY++)
5660
0
            {
5661
0
                int iX = 0;
5662
0
                for (int k = 0; k < nOuterLoops; k++)
5663
0
                {
5664
0
                    int iMax = iX + 65536;
5665
0
                    if (iMax > nXCheck)
5666
0
                        iMax = nXCheck;
5667
0
                    GUInt32 nSum32bit = 0;
5668
0
                    GUInt32 nSumSquare32bit = 0;
5669
0
                    for (; iX + 1 < iMax; iX += 2)
5670
0
                    {
5671
0
                        const GPtrDiff_t iOffset =
5672
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5673
0
                        const GUInt32 nValue = pData[iOffset];
5674
0
                        const GUInt32 nValue2 = pData[iOffset + 1];
5675
0
                        if (nValue < nValue2)
5676
0
                        {
5677
0
                            if (nValue < nMin)
5678
0
                                nMin = nValue;
5679
0
                            if (nValue2 > nMax)
5680
0
                                nMax = nValue2;
5681
0
                        }
5682
0
                        else
5683
0
                        {
5684
0
                            if (nValue2 < nMin)
5685
0
                                nMin = nValue2;
5686
0
                            if (nValue > nMax)
5687
0
                                nMax = nValue;
5688
0
                        }
5689
                        if constexpr (COMPUTE_OTHER_STATS)
5690
0
                        {
5691
0
                            nSum32bit += nValue;
5692
0
                            nSumSquare32bit += nValue * nValue;
5693
0
                            nSum32bit += nValue2;
5694
0
                            nSumSquare32bit += nValue2 * nValue2;
5695
0
                        }
5696
0
                    }
5697
                    if constexpr (COMPUTE_OTHER_STATS)
5698
0
                    {
5699
0
                        nSum += nSum32bit;
5700
0
                        nSumSquare += nSumSquare32bit;
5701
0
                    }
5702
0
                }
5703
0
                if (iX < nXCheck)
5704
0
                {
5705
0
                    const GPtrDiff_t iOffset =
5706
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5707
0
                    const GUInt32 nValue = pData[iOffset];
5708
0
                    if (nValue < nMin)
5709
0
                        nMin = nValue;
5710
0
                    if (nValue > nMax)
5711
0
                        nMax = nValue;
5712
                    if constexpr (COMPUTE_OTHER_STATS)
5713
0
                    {
5714
0
                        nSum += nValue;
5715
0
                        nSumSquare +=
5716
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5717
0
                            nValue;
5718
0
                    }
5719
0
                }
5720
0
            }
5721
            if constexpr (COMPUTE_OTHER_STATS)
5722
0
            {
5723
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5724
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5725
0
            }
5726
0
        }
5727
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&)
5728
};
5729
5730
template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5731
{
5732
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5733
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5734
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5735
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5736
    {
5737
        ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5738
            nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5739
            nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5740
    }
5741
};
5742
5743
#if (defined(__x86_64__) || defined(_M_X64)) &&                                \
5744
    (defined(__GNUC__) || defined(_MSC_VER))
5745
5746
#include "gdal_avx2_emulation.hpp"
5747
5748
0
#define ZERO256 GDALmm256_setzero_si256()
5749
5750
template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5751
static void
5752
ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5753
                              // assumed to be aligned on 256 bits
5754
                              const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5755
                              GUIntBig &nSum, GUIntBig &nSumSquare,
5756
                              GUIntBig &nSampleCount, GUIntBig &nValidCount)
5757
0
{
5758
    // 32-byte alignment may not be enforced by linker, so do it at hand
5759
0
    GByte
5760
0
        aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5761
0
    GByte *paby32ByteAligned =
5762
0
        aby32ByteUnaligned +
5763
0
        (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5764
0
    GByte *pabyMin = paby32ByteAligned;
5765
0
    GByte *pabyMax = paby32ByteAligned + 32;
5766
0
    GUInt32 *panSum =
5767
0
        COMPUTE_OTHER_STATS
5768
0
            ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5769
0
            : nullptr;
5770
0
    GUInt32 *panSumSquare =
5771
0
        COMPUTE_OTHER_STATS
5772
0
            ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5773
0
            : nullptr;
5774
5775
0
    CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5776
5777
0
    GPtrDiff_t i = 0;
5778
    // Make sure that sumSquare can fit on uint32
5779
    // * 8 since we can hold 8 sums per vector register
5780
0
    const int nMaxIterationsPerInnerLoop =
5781
0
        8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5782
0
    GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5783
0
    if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5784
0
        nOuterLoops++;
5785
5786
0
    GDALm256i ymm_min =
5787
0
        GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5788
0
    GDALm256i ymm_max = ymm_min;
5789
0
    [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5790
5791
0
    for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5792
0
    {
5793
0
        const auto iMax =
5794
0
            std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5795
5796
        // holds 4 uint32 sums in [0], [2], [4] and [6]
5797
0
        [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5798
0
        [[maybe_unused]] GDALm256i ymm_sumsquare =
5799
0
            ZERO256;  // holds 8 uint32 sums
5800
0
        for (; i + 31 < iMax; i += 32)
5801
0
        {
5802
0
            const GDALm256i ymm = GDALmm256_load_si256(
5803
0
                reinterpret_cast<const GDALm256i *>(pData + i));
5804
0
            if (COMPUTE_MIN)
5805
0
            {
5806
0
                ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5807
0
            }
5808
0
            if (COMPUTE_MAX)
5809
0
            {
5810
0
                ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5811
0
            }
5812
5813
            if constexpr (COMPUTE_OTHER_STATS)
5814
0
            {
5815
                // Extract even-8bit values
5816
0
                const GDALm256i ymm_even =
5817
0
                    GDALmm256_and_si256(ymm, ymm_mask_8bits);
5818
                // Compute square of those 16 values as 32 bit result
5819
                // and add adjacent pairs
5820
0
                const GDALm256i ymm_even_square =
5821
0
                    GDALmm256_madd_epi16(ymm_even, ymm_even);
5822
                // Add to the sumsquare accumulator
5823
0
                ymm_sumsquare =
5824
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5825
5826
                // Extract odd-8bit values
5827
0
                const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5828
0
                const GDALm256i ymm_odd_square =
5829
0
                    GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5830
0
                ymm_sumsquare =
5831
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5832
5833
                // Now compute the sums
5834
0
                ymm_sum = GDALmm256_add_epi32(ymm_sum,
5835
0
                                              GDALmm256_sad_epu8(ymm, ZERO256));
5836
0
            }
5837
0
        }
5838
5839
        if constexpr (COMPUTE_OTHER_STATS)
5840
0
        {
5841
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5842
0
                                  ymm_sum);
5843
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5844
0
                                  ymm_sumsquare);
5845
5846
0
            nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5847
0
            nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5848
0
                          panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5849
0
                          panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5850
0
                          panSumSquare[7];
5851
0
        }
5852
0
    }
5853
5854
    if constexpr (COMPUTE_MIN)
5855
0
    {
5856
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5857
0
    }
5858
    if constexpr (COMPUTE_MAX)
5859
0
    {
5860
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5861
0
    }
5862
    if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5863
0
    {
5864
0
        for (int j = 0; j < 32; j++)
5865
0
        {
5866
            if constexpr (COMPUTE_MIN)
5867
0
            {
5868
0
                if (pabyMin[j] < nMin)
5869
0
                    nMin = pabyMin[j];
5870
0
            }
5871
            if constexpr (COMPUTE_MAX)
5872
0
            {
5873
0
                if (pabyMax[j] > nMax)
5874
0
                    nMax = pabyMax[j];
5875
0
            }
5876
0
        }
5877
0
    }
5878
5879
0
    for (; i < nBlockPixels; i++)
5880
0
    {
5881
0
        const GUInt32 nValue = pData[i];
5882
        if constexpr (COMPUTE_MIN)
5883
0
        {
5884
0
            if (nValue < nMin)
5885
0
                nMin = nValue;
5886
0
        }
5887
        if constexpr (COMPUTE_MAX)
5888
0
        {
5889
0
            if (nValue > nMax)
5890
0
                nMax = nValue;
5891
0
        }
5892
        if constexpr (COMPUTE_OTHER_STATS)
5893
0
        {
5894
0
            nSum += nValue;
5895
0
            nSumSquare +=
5896
0
                static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5897
0
        }
5898
0
    }
5899
5900
    if constexpr (COMPUTE_OTHER_STATS)
5901
0
    {
5902
0
        nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5903
0
        nValidCount += static_cast<GUIntBig>(nBlockPixels);
5904
0
    }
5905
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&)
5906
5907
// SSE2/AVX2 optimization for GByte case
5908
// In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5909
// penaly in using the emulation, because, given the mm256 intrinsics used here,
5910
// there are strictly equivalent to 2 parallel SSE2 streams.
5911
template <bool COMPUTE_OTHER_STATS>
5912
struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5913
{
5914
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
5915
                  // assumed to be aligned on 256 bits
5916
                  const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5917
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5918
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5919
                  GUIntBig &nValidCount)
5920
0
    {
5921
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5922
0
        if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5923
0
            nMin <= nMax)
5924
0
        {
5925
            // 32-byte alignment may not be enforced by linker, so do it at hand
5926
0
            GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5927
0
            GByte *paby32ByteAligned =
5928
0
                aby32ByteUnaligned +
5929
0
                (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5930
0
            GByte *pabyMin = paby32ByteAligned;
5931
0
            GByte *pabyMax = paby32ByteAligned + 32;
5932
0
            GUInt32 *panSum =
5933
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5934
0
            GUInt32 *panSumSquare =
5935
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5936
5937
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5938
5939
0
            GPtrDiff_t i = 0;
5940
            // Make sure that sumSquare can fit on uint32
5941
            // * 8 since we can hold 8 sums per vector register
5942
0
            const int nMaxIterationsPerInnerLoop =
5943
0
                8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5944
0
            auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5945
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5946
0
                nOuterLoops++;
5947
5948
0
            const GDALm256i ymm_nodata =
5949
0
                GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5950
            // any non noData value in [min,max] would do.
5951
0
            const GDALm256i ymm_neutral =
5952
0
                GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5953
0
            GDALm256i ymm_min = ymm_neutral;
5954
0
            GDALm256i ymm_max = ymm_neutral;
5955
0
            [[maybe_unused]] const auto ymm_mask_8bits =
5956
0
                GDALmm256_set1_epi16(0xFF);
5957
5958
0
            const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5959
0
            const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5960
0
            const bool bComputeMinMax =
5961
0
                nMin > nMinThreshold || nMax < nMaxThreshold;
5962
5963
0
            for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5964
0
            {
5965
0
                const auto iMax =
5966
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5967
5968
                // holds 4 uint32 sums in [0], [2], [4] and [6]
5969
0
                [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5970
                // holds 8 uint32 sums
5971
0
                [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5972
                // holds 4 uint32 sums in [0], [2], [4] and [6]
5973
0
                [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5974
0
                const auto iInit = i;
5975
0
                for (; i + 31 < iMax; i += 32)
5976
0
                {
5977
0
                    const GDALm256i ymm = GDALmm256_load_si256(
5978
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
5979
5980
                    // Check which values are nodata
5981
0
                    const GDALm256i ymm_eq_nodata =
5982
0
                        GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5983
                    if constexpr (COMPUTE_OTHER_STATS)
5984
0
                    {
5985
                        // Count how many values are nodata (due to cmpeq
5986
                        // putting 255 when condition is met, this will actually
5987
                        // be 255 times the number of nodata value, spread in 4
5988
                        // 64 bits words). We can use add_epi32 as the counter
5989
                        // will not overflow uint32
5990
0
                        ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5991
0
                            ymm_count_nodata_mul_255,
5992
0
                            GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5993
0
                    }
5994
                    // Replace all nodata values by zero for the purpose of sum
5995
                    // and sumquare.
5996
0
                    const GDALm256i ymm_nodata_by_zero =
5997
0
                        GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5998
0
                    if (bComputeMinMax)
5999
0
                    {
6000
                        // Replace all nodata values by a neutral value for the
6001
                        // purpose of min and max.
6002
0
                        const GDALm256i ymm_nodata_by_neutral =
6003
0
                            GDALmm256_or_si256(
6004
0
                                GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
6005
0
                                ymm_nodata_by_zero);
6006
6007
0
                        ymm_min =
6008
0
                            GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
6009
0
                        ymm_max =
6010
0
                            GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6011
0
                    }
6012
6013
                    if constexpr (COMPUTE_OTHER_STATS)
6014
0
                    {
6015
                        // Extract even-8bit values
6016
0
                        const GDALm256i ymm_even = GDALmm256_and_si256(
6017
0
                            ymm_nodata_by_zero, ymm_mask_8bits);
6018
                        // Compute square of those 16 values as 32 bit result
6019
                        // and add adjacent pairs
6020
0
                        const GDALm256i ymm_even_square =
6021
0
                            GDALmm256_madd_epi16(ymm_even, ymm_even);
6022
                        // Add to the sumsquare accumulator
6023
0
                        ymm_sumsquare =
6024
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6025
6026
                        // Extract odd-8bit values
6027
0
                        const GDALm256i ymm_odd =
6028
0
                            GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6029
0
                        const GDALm256i ymm_odd_square =
6030
0
                            GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6031
0
                        ymm_sumsquare =
6032
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6033
6034
                        // Now compute the sums
6035
0
                        ymm_sum = GDALmm256_add_epi32(
6036
0
                            ymm_sum,
6037
0
                            GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6038
0
                    }
6039
0
                }
6040
6041
                if constexpr (COMPUTE_OTHER_STATS)
6042
0
                {
6043
0
                    GUInt32 *panCoutNoDataMul255 = panSum;
6044
0
                    GDALmm256_store_si256(
6045
0
                        reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6046
0
                        ymm_count_nodata_mul_255);
6047
6048
0
                    nSampleCount += (i - iInit);
6049
6050
0
                    nValidCount +=
6051
0
                        (i - iInit) -
6052
0
                        (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6053
0
                         panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6054
0
                            255;
6055
6056
0
                    GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6057
0
                                          ymm_sum);
6058
0
                    GDALmm256_store_si256(
6059
0
                        reinterpret_cast<GDALm256i *>(panSumSquare),
6060
0
                        ymm_sumsquare);
6061
0
                    nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6062
0
                    nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6063
0
                                  panSumSquare[1] + panSumSquare[2] +
6064
0
                                  panSumSquare[3] + panSumSquare[4] +
6065
0
                                  panSumSquare[5] + panSumSquare[6] +
6066
0
                                  panSumSquare[7];
6067
0
                }
6068
0
            }
6069
6070
0
            if (bComputeMinMax)
6071
0
            {
6072
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6073
0
                                      ymm_min);
6074
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6075
0
                                      ymm_max);
6076
0
                for (int j = 0; j < 32; j++)
6077
0
                {
6078
0
                    if (pabyMin[j] < nMin)
6079
0
                        nMin = pabyMin[j];
6080
0
                    if (pabyMax[j] > nMax)
6081
0
                        nMax = pabyMax[j];
6082
0
                }
6083
0
            }
6084
6085
            if constexpr (COMPUTE_OTHER_STATS)
6086
0
            {
6087
0
                nSampleCount += nBlockPixels - i;
6088
0
            }
6089
0
            for (; i < nBlockPixels; i++)
6090
0
            {
6091
0
                const GUInt32 nValue = pData[i];
6092
0
                if (nValue == nNoDataValue)
6093
0
                    continue;
6094
0
                if (nValue < nMin)
6095
0
                    nMin = nValue;
6096
0
                if (nValue > nMax)
6097
0
                    nMax = nValue;
6098
                if constexpr (COMPUTE_OTHER_STATS)
6099
0
                {
6100
0
                    nValidCount++;
6101
0
                    nSum += nValue;
6102
0
                    nSumSquare +=
6103
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6104
0
                        nValue;
6105
0
                }
6106
0
            }
6107
0
        }
6108
0
        else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6109
0
        {
6110
0
            if (nMin > 0)
6111
0
            {
6112
0
                if (nMax < 255)
6113
0
                {
6114
0
                    ComputeStatisticsByteNoNodata<true, true,
6115
0
                                                  COMPUTE_OTHER_STATS>(
6116
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6117
0
                        nSampleCount, nValidCount);
6118
0
                }
6119
0
                else
6120
0
                {
6121
0
                    ComputeStatisticsByteNoNodata<true, false,
6122
0
                                                  COMPUTE_OTHER_STATS>(
6123
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6124
0
                        nSampleCount, nValidCount);
6125
0
                }
6126
0
            }
6127
0
            else
6128
0
            {
6129
0
                if (nMax < 255)
6130
0
                {
6131
0
                    ComputeStatisticsByteNoNodata<false, true,
6132
0
                                                  COMPUTE_OTHER_STATS>(
6133
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6134
0
                        nSampleCount, nValidCount);
6135
0
                }
6136
0
                else
6137
0
                {
6138
0
                    ComputeStatisticsByteNoNodata<false, false,
6139
0
                                                  COMPUTE_OTHER_STATS>(
6140
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6141
0
                        nSampleCount, nValidCount);
6142
0
                }
6143
0
            }
6144
0
        }
6145
0
        else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6146
0
                 (nBlockXSize % 32) == 0)
6147
0
        {
6148
0
            for (int iY = 0; iY < nYCheck; iY++)
6149
0
            {
6150
0
                ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6151
0
                    nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6152
0
                    nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6153
0
            }
6154
0
        }
6155
0
        else
6156
0
        {
6157
0
            ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6158
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6159
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6160
0
        }
6161
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&)
6162
};
6163
6164
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6165
static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6166
                             GUIntBig i)
6167
0
{
6168
0
    nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6169
0
}
6170
6171
// AVX2/SSE2 optimization for GUInt16 case
6172
template <bool COMPUTE_OTHER_STATS>
6173
struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6174
{
6175
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
6176
                  // assumed to be aligned on 128 bits
6177
                  const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6178
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6179
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6180
                  GUIntBig &nValidCount)
6181
0
    {
6182
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6183
0
        if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6184
0
        {
6185
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6186
6187
0
            GPtrDiff_t i = 0;
6188
            // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6189
            // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6190
            // Furthermore the shift is also needed to use madd_epi16
6191
0
            const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6192
0
            GDALm256i ymm_min = GDALmm256_load_si256(
6193
0
                reinterpret_cast<const GDALm256i *>(pData + i));
6194
0
            ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6195
0
            GDALm256i ymm_max = ymm_min;
6196
0
            [[maybe_unused]] GDALm256i ymm_sumsquare =
6197
0
                ZERO256;  // holds 4 uint64 sums
6198
6199
            // Make sure that sum can fit on uint32
6200
            // * 8 since we can hold 8 sums per vector register
6201
0
            const int nMaxIterationsPerInnerLoop =
6202
0
                8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6203
0
            GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6204
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6205
0
                nOuterLoops++;
6206
6207
0
            const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6208
0
            [[maybe_unused]] const auto ymm_mask_16bits =
6209
0
                GDALmm256_set1_epi32(0xFFFF);
6210
0
            [[maybe_unused]] const auto ymm_mask_32bits =
6211
0
                GDALmm256_set1_epi64x(0xFFFFFFFF);
6212
6213
0
            GUIntBig nSumThis = 0;
6214
0
            for (int k = 0; k < nOuterLoops; k++)
6215
0
            {
6216
0
                const auto iMax =
6217
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6218
6219
0
                [[maybe_unused]] GDALm256i ymm_sum =
6220
0
                    ZERO256;  // holds 8 uint32 sums
6221
0
                for (; i + 15 < iMax; i += 16)
6222
0
                {
6223
0
                    const GDALm256i ymm = GDALmm256_load_si256(
6224
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
6225
0
                    const GDALm256i ymm_shifted =
6226
0
                        GDALmm256_add_epi16(ymm, ymm_m32768);
6227
0
                    if (bComputeMinMax)
6228
0
                    {
6229
0
                        ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6230
0
                        ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6231
0
                    }
6232
6233
                    if constexpr (COMPUTE_OTHER_STATS)
6234
0
                    {
6235
                        // Note: the int32 range can overflow for (0-32768)^2 +
6236
                        // (0-32768)^2 = 0x80000000, but as we know the result
6237
                        // is positive, this is OK as we interpret is a uint32.
6238
0
                        const GDALm256i ymm_square =
6239
0
                            GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6240
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6241
0
                            ymm_sumsquare,
6242
0
                            GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6243
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6244
0
                            ymm_sumsquare,
6245
0
                            GDALmm256_srli_epi64(ymm_square, 32));
6246
6247
                        // Now compute the sums
6248
0
                        ymm_sum = GDALmm256_add_epi32(
6249
0
                            ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6250
0
                        ymm_sum = GDALmm256_add_epi32(
6251
0
                            ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6252
0
                    }
6253
0
                }
6254
6255
                if constexpr (COMPUTE_OTHER_STATS)
6256
0
                {
6257
0
                    GUInt32 anSum[8];
6258
0
                    GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6259
0
                                           ymm_sum);
6260
0
                    nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6261
0
                                anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6262
0
                                anSum[6] + anSum[7];
6263
0
                }
6264
0
            }
6265
6266
0
            if (bComputeMinMax)
6267
0
            {
6268
0
                GUInt16 anMin[16];
6269
0
                GUInt16 anMax[16];
6270
6271
                // Unshift the result
6272
0
                ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6273
0
                ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6274
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6275
0
                                       ymm_min);
6276
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6277
0
                                       ymm_max);
6278
0
                for (int j = 0; j < 16; j++)
6279
0
                {
6280
0
                    if (anMin[j] < nMin)
6281
0
                        nMin = anMin[j];
6282
0
                    if (anMax[j] > nMax)
6283
0
                        nMax = anMax[j];
6284
0
                }
6285
0
            }
6286
6287
            if constexpr (COMPUTE_OTHER_STATS)
6288
0
            {
6289
0
                GUIntBig anSumSquare[4];
6290
0
                GDALmm256_storeu_si256(
6291
0
                    reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6292
0
                nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6293
0
                              anSumSquare[3];
6294
6295
                // Unshift the sum of squares
6296
0
                UnshiftSumSquare(nSumSquare, nSumThis,
6297
0
                                 static_cast<GUIntBig>(i));
6298
6299
0
                nSum += nSumThis;
6300
6301
0
                for (; i < nBlockPixels; i++)
6302
0
                {
6303
0
                    const GUInt32 nValue = pData[i];
6304
0
                    if (nValue < nMin)
6305
0
                        nMin = nValue;
6306
0
                    if (nValue > nMax)
6307
0
                        nMax = nValue;
6308
0
                    nSum += nValue;
6309
0
                    nSumSquare +=
6310
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6311
0
                        nValue;
6312
0
                }
6313
6314
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6315
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6316
0
            }
6317
0
        }
6318
0
        else
6319
0
        {
6320
0
            ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6321
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6322
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6323
0
        }
6324
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&)
6325
};
6326
6327
#endif
6328
// (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6329
// defined(_MSC_VER))
6330
6331
/************************************************************************/
6332
/*                          GetPixelValue()                             */
6333
/************************************************************************/
6334
6335
static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6336
                                   const void *pData, GPtrDiff_t iOffset,
6337
                                   const GDALNoDataValues &sNoDataValues,
6338
                                   bool &bValid)
6339
0
{
6340
0
    bValid = true;
6341
0
    double dfValue = 0;
6342
0
    switch (eDataType)
6343
0
    {
6344
0
        case GDT_Byte:
6345
0
        {
6346
0
            if (bSignedByte)
6347
0
                dfValue = static_cast<const signed char *>(pData)[iOffset];
6348
0
            else
6349
0
                dfValue = static_cast<const GByte *>(pData)[iOffset];
6350
0
            break;
6351
0
        }
6352
0
        case GDT_Int8:
6353
0
            dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6354
0
            break;
6355
0
        case GDT_UInt16:
6356
0
            dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6357
0
            break;
6358
0
        case GDT_Int16:
6359
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6360
0
            break;
6361
0
        case GDT_UInt32:
6362
0
            dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6363
0
            break;
6364
0
        case GDT_Int32:
6365
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6366
0
            break;
6367
0
        case GDT_UInt64:
6368
0
            dfValue = static_cast<double>(
6369
0
                static_cast<const std::uint64_t *>(pData)[iOffset]);
6370
0
            break;
6371
0
        case GDT_Int64:
6372
0
            dfValue = static_cast<double>(
6373
0
                static_cast<const std::int64_t *>(pData)[iOffset]);
6374
0
            break;
6375
0
        case GDT_Float16:
6376
0
        {
6377
0
            using namespace std;
6378
0
            const GFloat16 hfValue =
6379
0
                static_cast<const GFloat16 *>(pData)[iOffset];
6380
0
            if (isnan(hfValue) ||
6381
0
                (sNoDataValues.bGotFloat16NoDataValue &&
6382
0
                 ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6383
0
            {
6384
0
                bValid = false;
6385
0
                return 0.0;
6386
0
            }
6387
0
            dfValue = hfValue;
6388
0
            return dfValue;
6389
0
        }
6390
0
        case GDT_Float32:
6391
0
        {
6392
0
            const float fValue = static_cast<const float *>(pData)[iOffset];
6393
0
            if (std::isnan(fValue) ||
6394
0
                (sNoDataValues.bGotFloatNoDataValue &&
6395
0
                 ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6396
0
            {
6397
0
                bValid = false;
6398
0
                return 0.0;
6399
0
            }
6400
0
            dfValue = double(fValue);
6401
0
            return dfValue;
6402
0
        }
6403
0
        case GDT_Float64:
6404
0
            dfValue = static_cast<const double *>(pData)[iOffset];
6405
0
            if (std::isnan(dfValue))
6406
0
            {
6407
0
                bValid = false;
6408
0
                return 0.0;
6409
0
            }
6410
0
            break;
6411
0
        case GDT_CInt16:
6412
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6413
0
            break;
6414
0
        case GDT_CInt32:
6415
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6416
0
            break;
6417
0
        case GDT_CFloat16:
6418
0
            dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6419
0
            if (std::isnan(dfValue))
6420
0
            {
6421
0
                bValid = false;
6422
0
                return 0.0;
6423
0
            }
6424
0
            break;
6425
0
        case GDT_CFloat32:
6426
0
            dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6427
0
            if (std::isnan(dfValue))
6428
0
            {
6429
0
                bValid = false;
6430
0
                return 0.0;
6431
0
            }
6432
0
            break;
6433
0
        case GDT_CFloat64:
6434
0
            dfValue = static_cast<const double *>(pData)[iOffset * 2];
6435
0
            if (std::isnan(dfValue))
6436
0
            {
6437
0
                bValid = false;
6438
0
                return 0.0;
6439
0
            }
6440
0
            break;
6441
0
        case GDT_Unknown:
6442
0
        case GDT_TypeCount:
6443
0
            CPLAssert(false);
6444
0
            break;
6445
0
    }
6446
6447
0
    if (sNoDataValues.bGotNoDataValue &&
6448
0
        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6449
0
    {
6450
0
        bValid = false;
6451
0
        return 0.0;
6452
0
    }
6453
0
    return dfValue;
6454
0
}
6455
6456
/************************************************************************/
6457
/*                         SetValidPercent()                            */
6458
/************************************************************************/
6459
6460
//! @cond Doxygen_Suppress
6461
/**
6462
 * \brief Set percentage of valid (not nodata) pixels.
6463
 *
6464
 * Stores the percentage of valid pixels in the metadata item
6465
 * STATISTICS_VALID_PERCENT
6466
 *
6467
 * @param nSampleCount Number of sampled pixels.
6468
 *
6469
 * @param nValidCount Number of valid pixels.
6470
 */
6471
6472
void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6473
                                     GUIntBig nValidCount)
6474
0
{
6475
0
    if (nValidCount == 0)
6476
0
    {
6477
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6478
0
    }
6479
0
    else if (nValidCount == nSampleCount)
6480
0
    {
6481
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6482
0
    }
6483
0
    else /* nValidCount < nSampleCount */
6484
0
    {
6485
0
        char szValue[128] = {0};
6486
6487
        /* percentage is only an indicator: limit precision */
6488
0
        CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6489
0
                    100. * static_cast<double>(nValidCount) / nSampleCount);
6490
6491
0
        if (EQUAL(szValue, "100"))
6492
0
        {
6493
            /* don't set 100 percent valid
6494
             * because some of the sampled pixels were nodata */
6495
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6496
0
        }
6497
0
        else
6498
0
        {
6499
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6500
0
        }
6501
0
    }
6502
0
}
6503
6504
//! @endcond
6505
6506
#if (defined(__x86_64__) || defined(_M_X64))
6507
6508
#ifdef __AVX2__
6509
6510
#define setzero_si _mm256_setzero_si256
6511
#define setzero_ps _mm256_setzero_ps
6512
#define set1_ps _mm256_set1_ps
6513
#define set1_epi32 _mm256_set1_epi32
6514
#define add_epi32 _mm256_add_epi32
6515
#define loadu_ps _mm256_loadu_ps
6516
#define or_ps _mm256_or_ps
6517
#define min_ps _mm256_min_ps
6518
#define max_ps _mm256_max_ps
6519
#define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
6520
#define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
6521
#define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
6522
#define movemask_ps _mm256_movemask_ps
6523
#define add_ps _mm256_add_ps
6524
#define sub_ps _mm256_sub_ps
6525
#define mul_ps _mm256_mul_ps
6526
#define div_ps _mm256_div_ps
6527
#define storeu_ps _mm256_storeu_ps
6528
#define cvtepi32_ps _mm256_cvtepi32_ps
6529
#define cvtsi_si32(x) _mm256_extract_epi32((x), 0)
6530
#define blendv_ps _mm256_blendv_ps
6531
#ifdef __FMA__
6532
#define fmadd_ps _mm256_fmadd_ps
6533
#else
6534
#define fmadd_ps(a, b, c) add_ps(mul_ps((a), (b)), (c))
6535
#endif
6536
6537
#else
6538
6539
0
#define setzero_si _mm_setzero_si128
6540
0
#define setzero_ps _mm_setzero_ps
6541
0
#define set1_ps _mm_set1_ps
6542
0
#define set1_epi32 _mm_set1_epi32
6543
0
#define add_epi32 _mm_add_epi32
6544
0
#define loadu_ps _mm_loadu_ps
6545
0
#define or_ps _mm_or_ps
6546
0
#define min_ps _mm_min_ps
6547
0
#define max_ps _mm_max_ps
6548
0
#define cmpeq_ps _mm_cmpeq_ps
6549
0
#define cmpneq_ps _mm_cmpneq_ps
6550
0
#define cmpunord_ps _mm_cmpunord_ps
6551
0
#define movemask_ps _mm_movemask_ps
6552
0
#define add_ps _mm_add_ps
6553
0
#define sub_ps _mm_sub_ps
6554
0
#define mul_ps _mm_mul_ps
6555
0
#define div_ps _mm_div_ps
6556
0
#define storeu_ps _mm_storeu_ps
6557
0
#define cvtepi32_ps _mm_cvtepi32_ps
6558
0
#define cvtsi_si32 _mm_cvtsi128_si32
6559
#ifdef __FMA__
6560
#define fmadd_ps _mm_fmadd_ps
6561
#else
6562
0
#define fmadd_ps(a, b, c) add_ps(mul_ps((a), (b)), (c))
6563
#endif
6564
6565
inline __m128 blendv_ps(__m128 a, __m128 b, __m128 mask)
6566
0
{
6567
#if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6568
    return _mm_blendv_ps(a, b, mask);
6569
#else
6570
0
    return _mm_or_ps(_mm_andnot_ps(mask, a), _mm_and_ps(mask, b));
6571
0
#endif
6572
0
}
6573
#endif
6574
6575
template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6576
#if defined(__GNUC__)
6577
__attribute__((noinline))
6578
#endif
6579
static int
6580
ComputeStatisticsFloat32_SSE2(const float *pafData,
6581
                              [[maybe_unused]] float fNoDataValue, int iX,
6582
                              int nCount, float &fMin, float &fMax,
6583
                              float &fBlockMean, float &fBlockM2,
6584
                              int &nBlockValidCount)
6585
0
{
6586
0
    auto vValidCount = setzero_si();
6587
0
    const auto vOne = set1_epi32(1);
6588
0
    [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
6589
6590
0
    auto vMin_lo = set1_ps(fMin);
6591
0
    auto vMax_lo = set1_ps(fMax);
6592
0
    auto vMean_lo = setzero_ps();
6593
0
    auto vM2_lo = setzero_ps();
6594
6595
0
    auto vMin_hi = vMin_lo;
6596
0
    auto vMax_hi = vMax_lo;
6597
0
    auto vMean_hi = setzero_ps();
6598
0
    auto vM2_hi = setzero_ps();
6599
6600
0
    constexpr int VALS_PER_LOOP =
6601
0
        2 * static_cast<int>(sizeof(vOne) / sizeof(float));
6602
0
    for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6603
0
    {
6604
0
        const auto vValues_lo = loadu_ps(pafData + iX);
6605
0
        const auto vValues_hi = loadu_ps(pafData + iX + VALS_PER_LOOP / 2);
6606
        // Check if there's at least one NaN in both vectors
6607
0
        auto isNaNOrNoData = cmpunord_ps(vValues_lo, vValues_hi);
6608
        if constexpr (HAS_NODATA)
6609
0
        {
6610
0
            isNaNOrNoData =
6611
0
                or_ps(isNaNOrNoData, or_ps(cmpeq_ps(vValues_lo, vNoData),
6612
0
                                           cmpeq_ps(vValues_hi, vNoData)));
6613
0
        }
6614
0
        if (movemask_ps(isNaNOrNoData))
6615
0
        {
6616
0
            break;
6617
0
        }
6618
6619
0
        vValidCount = add_epi32(vValidCount, vOne);
6620
0
        const auto vValidCountFloat32 = cvtepi32_ps(vValidCount);
6621
6622
0
        vMin_lo = min_ps(vMin_lo, vValues_lo);
6623
0
        vMax_lo = max_ps(vMax_lo, vValues_lo);
6624
0
        const auto vDelta_lo = sub_ps(vValues_lo, vMean_lo);
6625
0
        const auto vNewMean_lo =
6626
0
            add_ps(vMean_lo, div_ps(vDelta_lo, vValidCountFloat32));
6627
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6628
0
        {
6629
0
            const auto vMinNotSameAsMax_lo = cmpneq_ps(vMin_lo, vMax_lo);
6630
0
            vMean_lo = blendv_ps(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6631
0
            const auto vNewM2_lo =
6632
0
                fmadd_ps(vDelta_lo, sub_ps(vValues_lo, vMean_lo), vM2_lo);
6633
0
            vM2_lo = blendv_ps(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6634
        }
6635
        else
6636
0
        {
6637
0
            vMean_lo = vNewMean_lo;
6638
0
            vM2_lo = fmadd_ps(vDelta_lo, sub_ps(vValues_lo, vMean_lo), vM2_lo);
6639
0
        }
6640
6641
0
        vMin_hi = min_ps(vMin_hi, vValues_hi);
6642
0
        vMax_hi = max_ps(vMax_hi, vValues_hi);
6643
0
        const auto vDelta_hi = sub_ps(vValues_hi, vMean_hi);
6644
0
        const auto vNewMean_hi =
6645
0
            add_ps(vMean_hi, div_ps(vDelta_hi, vValidCountFloat32));
6646
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6647
0
        {
6648
0
            const auto vMinNotSameAsMax_hi = cmpneq_ps(vMin_hi, vMax_hi);
6649
0
            vMean_hi = blendv_ps(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6650
0
            const auto vNewM2_hi =
6651
0
                fmadd_ps(vDelta_hi, sub_ps(vValues_hi, vMean_hi), vM2_hi);
6652
0
            vM2_hi = blendv_ps(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6653
        }
6654
        else
6655
0
        {
6656
0
            vMean_hi = vNewMean_hi;
6657
0
            vM2_hi = fmadd_ps(vDelta_hi, sub_ps(vValues_hi, vMean_hi), vM2_hi);
6658
0
        }
6659
0
    }
6660
0
    const int nValidVectorCount = cvtsi_si32(vValidCount);
6661
0
    if (nValidVectorCount)
6662
0
    {
6663
0
        float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP], afMean[VALS_PER_LOOP],
6664
0
            afM2[VALS_PER_LOOP];
6665
0
        storeu_ps(afMin, vMin_lo);
6666
0
        storeu_ps(afMax, vMax_lo);
6667
0
        storeu_ps(afMean, vMean_lo);
6668
0
        storeu_ps(afM2, vM2_lo);
6669
0
        storeu_ps(afMin + VALS_PER_LOOP / 2, vMin_hi);
6670
0
        storeu_ps(afMax + VALS_PER_LOOP / 2, vMax_hi);
6671
0
        storeu_ps(afMean + VALS_PER_LOOP / 2, vMean_hi);
6672
0
        storeu_ps(afM2 + VALS_PER_LOOP / 2, vM2_hi);
6673
6674
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6675
0
        {
6676
0
            fMin = std::min(fMin, afMin[i]);
6677
0
            fMax = std::max(fMax, afMax[i]);
6678
0
            const auto nNewValidCount = nBlockValidCount + nValidVectorCount;
6679
0
            if (afMean[i] != fBlockMean)
6680
0
            {
6681
0
                const float fDelta = afMean[i] - fBlockMean;
6682
0
                fBlockMean += fDelta * nValidVectorCount / nNewValidCount;
6683
0
                fBlockM2 += afM2[i] + fDelta * fDelta * nBlockValidCount *
6684
0
                                          nValidVectorCount / nNewValidCount;
6685
0
            }
6686
0
            nBlockValidCount = nNewValidCount;
6687
0
        }
6688
0
    }
6689
6690
0
    return iX;
6691
0
}
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<false, true>(float const*, float, int, int, float&, float&, float&, float&, int&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<false, false>(float const*, float, int, int, float&, float&, float&, float&, int&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<true, true>(float const*, float, int, int, float&, float&, float&, float&, int&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<true, false>(float const*, float, int, int, float&, float&, float&, float&, int&)
6692
6693
#ifdef __AVX2__
6694
6695
#define setzero_pd _mm256_setzero_pd
6696
#define set1_pd _mm256_set1_pd
6697
#define loadu_pd _mm256_loadu_pd
6698
#define or_pd _mm256_or_pd
6699
#define min_pd _mm256_min_pd
6700
#define max_pd _mm256_max_pd
6701
#define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
6702
#define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
6703
#define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
6704
#define movemask_pd _mm256_movemask_pd
6705
#define add_pd _mm256_add_pd
6706
#define sub_pd _mm256_sub_pd
6707
#define mul_pd _mm256_mul_pd
6708
#define div_pd _mm256_div_pd
6709
#define storeu_pd _mm256_storeu_pd
6710
#define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
6711
#define blendv_pd _mm256_blendv_pd
6712
#ifdef __FMA__
6713
#define fmadd_pd _mm256_fmadd_pd
6714
#else
6715
#define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6716
#endif
6717
6718
#else
6719
6720
0
#define setzero_pd _mm_setzero_pd
6721
0
#define set1_pd _mm_set1_pd
6722
0
#define loadu_pd _mm_loadu_pd
6723
0
#define or_pd _mm_or_pd
6724
0
#define min_pd _mm_min_pd
6725
0
#define max_pd _mm_max_pd
6726
0
#define cmpeq_pd _mm_cmpeq_pd
6727
0
#define cmpneq_pd _mm_cmpneq_pd
6728
0
#define cmpunord_pd _mm_cmpunord_pd
6729
0
#define movemask_pd _mm_movemask_pd
6730
0
#define add_pd _mm_add_pd
6731
0
#define sub_pd _mm_sub_pd
6732
0
#define mul_pd _mm_mul_pd
6733
0
#define div_pd _mm_div_pd
6734
0
#define storeu_pd _mm_storeu_pd
6735
0
#define cvtsd_f64 _mm_cvtsd_f64
6736
#ifdef __FMA__
6737
#define fmadd_pd _mm_fmadd_pd
6738
#else
6739
0
#define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6740
#endif
6741
6742
inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
6743
0
{
6744
#if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6745
    return _mm_blendv_pd(a, b, mask);
6746
#else
6747
0
    return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
6748
0
#endif
6749
0
}
6750
#endif
6751
6752
template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6753
#if defined(__GNUC__)
6754
__attribute__((noinline))
6755
#endif
6756
static int
6757
ComputeStatisticsFloat64_SSE2(const double *padfData,
6758
                              [[maybe_unused]] double dfNoDataValue, int iX,
6759
                              int nCount, double &dfMin, double &dfMax,
6760
                              double &dfBlockMean, double &dfBlockM2,
6761
                              double &dfBlockValidCount)
6762
0
{
6763
0
    auto vValidCount = setzero_pd();
6764
0
    const auto vOne = set1_pd(1);
6765
0
    [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
6766
6767
0
    auto vMin_lo = set1_pd(dfMin);
6768
0
    auto vMax_lo = set1_pd(dfMax);
6769
0
    auto vMean_lo = setzero_pd();
6770
0
    auto vM2_lo = setzero_pd();
6771
6772
0
    auto vMin_hi = vMin_lo;
6773
0
    auto vMax_hi = vMax_lo;
6774
0
    auto vMean_hi = setzero_pd();
6775
0
    auto vM2_hi = setzero_pd();
6776
6777
0
    constexpr int VALS_PER_LOOP =
6778
0
        2 * static_cast<int>(sizeof(vOne) / sizeof(double));
6779
0
    for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6780
0
    {
6781
0
        const auto vValues_lo = loadu_pd(padfData + iX);
6782
0
        const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
6783
        // Check if there's at least one NaN in both vectors
6784
0
        auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
6785
        if constexpr (HAS_NODATA)
6786
0
        {
6787
0
            isNaNOrNoData =
6788
0
                or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
6789
0
                                           cmpeq_pd(vValues_hi, vNoData)));
6790
0
        }
6791
0
        if (movemask_pd(isNaNOrNoData))
6792
0
        {
6793
0
            break;
6794
0
        }
6795
6796
0
        vValidCount = add_pd(vValidCount, vOne);
6797
0
        const auto vInvValidCount = div_pd(vOne, vValidCount);
6798
6799
0
        vMin_lo = min_pd(vMin_lo, vValues_lo);
6800
0
        vMax_lo = max_pd(vMax_lo, vValues_lo);
6801
0
        const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6802
0
        const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6803
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6804
0
        {
6805
0
            const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
6806
0
            vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6807
0
            const auto vNewM2_lo =
6808
0
                fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6809
0
            vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6810
        }
6811
        else
6812
0
        {
6813
0
            vMean_lo = vNewMean_lo;
6814
0
            vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6815
0
        }
6816
6817
0
        vMin_hi = min_pd(vMin_hi, vValues_hi);
6818
0
        vMax_hi = max_pd(vMax_hi, vValues_hi);
6819
0
        const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6820
0
        const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6821
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6822
0
        {
6823
0
            const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
6824
0
            vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6825
0
            const auto vNewM2_hi =
6826
0
                fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6827
0
            vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6828
        }
6829
        else
6830
0
        {
6831
0
            vMean_hi = vNewMean_hi;
6832
0
            vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6833
0
        }
6834
0
    }
6835
0
    const double dfValidVectorCount = cvtsd_f64(vValidCount);
6836
0
    if (dfValidVectorCount > 0)
6837
0
    {
6838
0
        double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
6839
0
            adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6840
0
        storeu_pd(adfMin, vMin_lo);
6841
0
        storeu_pd(adfMax, vMax_lo);
6842
0
        storeu_pd(adfMean, vMean_lo);
6843
0
        storeu_pd(adfM2, vM2_lo);
6844
0
        storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
6845
0
        storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
6846
0
        storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6847
0
        storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6848
6849
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6850
0
        {
6851
0
            dfMin = std::min(dfMin, adfMin[i]);
6852
0
            dfMax = std::max(dfMax, adfMax[i]);
6853
0
            const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6854
0
            if (adfMean[i] != dfBlockMean)
6855
0
            {
6856
0
                const double dfDelta = adfMean[i] - dfBlockMean;
6857
0
                dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6858
0
                dfBlockM2 += adfM2[i] + dfDelta * dfDelta * dfBlockValidCount *
6859
0
                                            dfValidVectorCount /
6860
0
                                            dfNewValidCount;
6861
0
            }
6862
0
            dfBlockValidCount = dfNewValidCount;
6863
0
        }
6864
0
    }
6865
6866
0
    return iX;
6867
0
}
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat64_SSE2<false, true>(double const*, double, int, int, double&, double&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat64_SSE2<false, false>(double const*, double, int, int, double&, double&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat64_SSE2<true, true>(double const*, double, int, int, double&, double&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat64_SSE2<true, false>(double const*, double, int, int, double&, double&, double&, double&, double&)
6868
6869
#endif
6870
6871
/************************************************************************/
6872
/*                         ComputeStatistics()                          */
6873
/************************************************************************/
6874
6875
/**
6876
 * \brief Compute image statistics.
6877
 *
6878
 * Returns the minimum, maximum, mean and standard deviation of all
6879
 * pixel values in this band.  If approximate statistics are sufficient,
6880
 * the bApproxOK flag can be set to true in which case overviews, or a
6881
 * subset of image tiles may be used in computing the statistics.
6882
 *
6883
 * Once computed, the statistics will generally be "set" back on the
6884
 * raster band using SetStatistics().
6885
 *
6886
 * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6887
 *
6888
 * This method is the same as the C function GDALComputeRasterStatistics().
6889
 *
6890
 * @param bApproxOK If TRUE statistics may be computed based on overviews
6891
 * or a subset of all tiles.
6892
 *
6893
 * @param pdfMin Location into which to load image minimum (may be NULL).
6894
 *
6895
 * @param pdfMax Location into which to load image maximum (may be NULL).-
6896
 *
6897
 * @param pdfMean Location into which to load image mean (may be NULL).
6898
 *
6899
 * @param pdfStdDev Location into which to load image standard deviation
6900
 * (may be NULL).
6901
 *
6902
 * @param pfnProgress a function to call to report progress, or NULL.
6903
 *
6904
 * @param pProgressData application data to pass to the progress function.
6905
 *
6906
 * @return CE_None on success, or CE_Failure if an error occurs or processing
6907
 * is terminated by the user.
6908
 */
6909
6910
CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6911
                                         double *pdfMax, double *pdfMean,
6912
                                         double *pdfStdDev,
6913
                                         GDALProgressFunc pfnProgress,
6914
                                         void *pProgressData)
6915
6916
0
{
6917
0
    if (pfnProgress == nullptr)
6918
0
        pfnProgress = GDALDummyProgress;
6919
6920
    /* -------------------------------------------------------------------- */
6921
    /*      If we have overview bands, use them for statistics.             */
6922
    /* -------------------------------------------------------------------- */
6923
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6924
0
    {
6925
0
        GDALRasterBand *poBand =
6926
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6927
6928
0
        if (poBand != this)
6929
0
        {
6930
0
            CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6931
0
                                                    pdfMean, pdfStdDev,
6932
0
                                                    pfnProgress, pProgressData);
6933
0
            if (eErr == CE_None)
6934
0
            {
6935
0
                if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6936
0
                {
6937
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6938
0
                    SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6939
0
                }
6940
6941
                /* transfer metadata from overview band to this */
6942
0
                const char *pszPercentValid =
6943
0
                    poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6944
6945
0
                if (pszPercentValid != nullptr)
6946
0
                {
6947
0
                    SetMetadataItem("STATISTICS_VALID_PERCENT",
6948
0
                                    pszPercentValid);
6949
0
                }
6950
0
            }
6951
0
            return eErr;
6952
0
        }
6953
0
    }
6954
6955
0
    if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6956
0
    {
6957
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6958
0
        return CE_Failure;
6959
0
    }
6960
6961
    /* -------------------------------------------------------------------- */
6962
    /*      Read actual data and compute statistics.                        */
6963
    /* -------------------------------------------------------------------- */
6964
    // Using Welford algorithm:
6965
    // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6966
    // to compute standard deviation in a more numerically robust way than
6967
    // the difference of the sum of square values with the square of the sum.
6968
    // dfMean and dfM2 are updated at each sample.
6969
    // dfM2 is the sum of square of differences to the current mean.
6970
0
    double dfMin = std::numeric_limits<double>::infinity();
6971
0
    double dfMax = -std::numeric_limits<double>::infinity();
6972
0
    double dfMean = 0.0;
6973
0
    double dfM2 = 0.0;
6974
6975
0
    GDALRasterIOExtraArg sExtraArg;
6976
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6977
6978
0
    GDALNoDataValues sNoDataValues(this, eDataType);
6979
0
    GDALRasterBand *poMaskBand = nullptr;
6980
0
    if (!sNoDataValues.bGotNoDataValue)
6981
0
    {
6982
0
        const int l_nMaskFlags = GetMaskFlags();
6983
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
6984
0
            GetColorInterpretation() != GCI_AlphaBand)
6985
0
        {
6986
0
            poMaskBand = GetMaskBand();
6987
0
        }
6988
0
    }
6989
6990
0
    bool bSignedByte = false;
6991
0
    if (eDataType == GDT_Byte)
6992
0
    {
6993
0
        EnablePixelTypeSignedByteWarning(false);
6994
0
        const char *pszPixelType =
6995
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6996
0
        EnablePixelTypeSignedByteWarning(true);
6997
0
        bSignedByte =
6998
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6999
0
    }
7000
7001
0
    GUIntBig nSampleCount = 0;
7002
0
    GUIntBig nValidCount = 0;
7003
7004
0
    if (bApproxOK && HasArbitraryOverviews())
7005
0
    {
7006
        /* --------------------------------------------------------------------
7007
         */
7008
        /*      Figure out how much the image should be reduced to get an */
7009
        /*      approximate value. */
7010
        /* --------------------------------------------------------------------
7011
         */
7012
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7013
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7014
7015
0
        int nXReduced = nRasterXSize;
7016
0
        int nYReduced = nRasterYSize;
7017
0
        if (dfReduction > 1.0)
7018
0
        {
7019
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7020
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7021
7022
            // Catch the case of huge resizing ratios here
7023
0
            if (nXReduced == 0)
7024
0
                nXReduced = 1;
7025
0
            if (nYReduced == 0)
7026
0
                nYReduced = 1;
7027
0
        }
7028
7029
0
        void *pData = CPLMalloc(cpl::fits_on<int>(
7030
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7031
7032
0
        const CPLErr eErr =
7033
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7034
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7035
0
        if (eErr != CE_None)
7036
0
        {
7037
0
            CPLFree(pData);
7038
0
            return eErr;
7039
0
        }
7040
7041
0
        GByte *pabyMaskData = nullptr;
7042
0
        if (poMaskBand)
7043
0
        {
7044
0
            pabyMaskData =
7045
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7046
0
            if (!pabyMaskData)
7047
0
            {
7048
0
                CPLFree(pData);
7049
0
                return CE_Failure;
7050
0
            }
7051
7052
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7053
0
                                     pabyMaskData, nXReduced, nYReduced,
7054
0
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
7055
0
            {
7056
0
                CPLFree(pData);
7057
0
                CPLFree(pabyMaskData);
7058
0
                return CE_Failure;
7059
0
            }
7060
0
        }
7061
7062
        /* this isn't the fastest way to do this, but is easier for now */
7063
0
        for (int iY = 0; iY < nYReduced; iY++)
7064
0
        {
7065
0
            for (int iX = 0; iX < nXReduced; iX++)
7066
0
            {
7067
0
                const int iOffset = iX + iY * nXReduced;
7068
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
7069
0
                    continue;
7070
7071
0
                bool bValid = true;
7072
0
                double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7073
0
                                               iOffset, sNoDataValues, bValid);
7074
0
                if (!bValid)
7075
0
                    continue;
7076
7077
0
                dfMin = std::min(dfMin, dfValue);
7078
0
                dfMax = std::max(dfMax, dfValue);
7079
7080
0
                nValidCount++;
7081
0
                if (dfMin == dfMax)
7082
0
                {
7083
0
                    if (nValidCount == 1)
7084
0
                        dfMean = dfMin;
7085
0
                }
7086
0
                else
7087
0
                {
7088
0
                    const double dfDelta = dfValue - dfMean;
7089
0
                    dfMean += dfDelta / nValidCount;
7090
0
                    dfM2 += dfDelta * (dfValue - dfMean);
7091
0
                }
7092
0
            }
7093
0
        }
7094
7095
0
        nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
7096
7097
0
        CPLFree(pData);
7098
0
        CPLFree(pabyMaskData);
7099
0
    }
7100
7101
0
    else  // No arbitrary overviews.
7102
0
    {
7103
0
        if (!InitBlockInfo())
7104
0
            return CE_Failure;
7105
7106
        /* --------------------------------------------------------------------
7107
         */
7108
        /*      Figure out the ratio of blocks we will read to get an */
7109
        /*      approximate value. */
7110
        /* --------------------------------------------------------------------
7111
         */
7112
0
        int nSampleRate = 1;
7113
0
        if (bApproxOK)
7114
0
        {
7115
0
            nSampleRate = static_cast<int>(std::max(
7116
0
                1.0,
7117
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7118
            // We want to avoid probing only the first column of blocks for
7119
            // a square shaped raster, because it is not unlikely that it may
7120
            // be padding only (#6378)
7121
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7122
0
                nSampleRate += 1;
7123
0
        }
7124
0
        if (nSampleRate == 1)
7125
0
            bApproxOK = false;
7126
7127
        // Particular case for GDT_Byte and GUInt16 that only use integral types
7128
        // for each block, and possibly for the whole raster.
7129
0
        if (!poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7130
0
                            eDataType == GDT_UInt16))
7131
0
        {
7132
            // We can do integer computation on the whole raster in the Byte case
7133
            // only if the number of pixels explored is lower than
7134
            // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
7135
            // Should be 99.99999% of cases.
7136
            // For GUInt16, this limits to raster of 4 giga pixels
7137
7138
0
            const bool bIntegerStats =
7139
0
                ((eDataType == GDT_Byte &&
7140
0
                  static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7141
0
                          nSampleRate <
7142
0
                      GUINTBIG_MAX / (255U * 255U) /
7143
0
                          (static_cast<GUInt64>(nBlockXSize) *
7144
0
                           static_cast<GUInt64>(nBlockYSize))) ||
7145
0
                 (eDataType == GDT_UInt16 &&
7146
0
                  static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7147
0
                          nSampleRate <
7148
0
                      GUINTBIG_MAX / (65535U * 65535U) /
7149
0
                          (static_cast<GUInt64>(nBlockXSize) *
7150
0
                           static_cast<GUInt64>(nBlockYSize)))) &&
7151
                // Can be set to NO for easier debugging of the !bIntegerStats
7152
                // case which requires huge rasters to trigger
7153
0
                CPLTestBool(
7154
0
                    CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7155
7156
0
            const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
7157
0
            GUInt32 nMin = nMaxValueType;
7158
0
            GUInt32 nMax = 0;
7159
0
            GUIntBig nSum = 0;
7160
0
            GUIntBig nSumSquare = 0;
7161
            // If no valid nodata, map to invalid value (256 for Byte)
7162
0
            const GUInt32 nNoDataValue =
7163
0
                (sNoDataValues.bGotNoDataValue &&
7164
0
                 sNoDataValues.dfNoDataValue >= 0 &&
7165
0
                 sNoDataValues.dfNoDataValue <= nMaxValueType &&
7166
0
                 fabs(sNoDataValues.dfNoDataValue -
7167
0
                      static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7168
0
                                           1e-10)) < 1e-10)
7169
0
                    ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7170
0
                    : nMaxValueType + 1;
7171
7172
0
            for (GIntBig iSampleBlock = 0;
7173
0
                 iSampleBlock <
7174
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7175
0
                 iSampleBlock += nSampleRate)
7176
0
            {
7177
0
                const int iYBlock =
7178
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
7179
0
                const int iXBlock =
7180
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
7181
7182
0
                GDALRasterBlock *const poBlock =
7183
0
                    GetLockedBlockRef(iXBlock, iYBlock);
7184
0
                if (poBlock == nullptr)
7185
0
                    return CE_Failure;
7186
7187
0
                void *const pData = poBlock->GetDataRef();
7188
7189
0
                int nXCheck = 0, nYCheck = 0;
7190
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7191
7192
0
                GUIntBig nBlockSum = 0;
7193
0
                GUIntBig nBlockSumSquare = 0;
7194
0
                GUIntBig nBlockSampleCount = 0;
7195
0
                GUIntBig nBlockValidCount = 0;
7196
0
                GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7197
0
                GUIntBig &nBlockSumSquareRef =
7198
0
                    bIntegerStats ? nSumSquare : nBlockSumSquare;
7199
0
                GUIntBig &nBlockSampleCountRef =
7200
0
                    bIntegerStats ? nSampleCount : nBlockSampleCount;
7201
0
                GUIntBig &nBlockValidCountRef =
7202
0
                    bIntegerStats ? nValidCount : nBlockValidCount;
7203
7204
0
                if (eDataType == GDT_Byte)
7205
0
                {
7206
0
                    ComputeStatisticsInternal<
7207
0
                        GByte, /* COMPUTE_OTHER_STATS = */ true>::
7208
0
                        f(nXCheck, nBlockXSize, nYCheck,
7209
0
                          static_cast<const GByte *>(pData),
7210
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7211
0
                          nMax, nBlockSumRef, nBlockSumSquareRef,
7212
0
                          nBlockSampleCountRef, nBlockValidCountRef);
7213
0
                }
7214
0
                else
7215
0
                {
7216
0
                    ComputeStatisticsInternal<
7217
0
                        GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7218
0
                        f(nXCheck, nBlockXSize, nYCheck,
7219
0
                          static_cast<const GUInt16 *>(pData),
7220
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7221
0
                          nMax, nBlockSumRef, nBlockSumSquareRef,
7222
0
                          nBlockSampleCountRef, nBlockValidCountRef);
7223
0
                }
7224
7225
0
                poBlock->DropLock();
7226
7227
0
                if (!bIntegerStats)
7228
0
                {
7229
0
                    nSampleCount += nBlockSampleCount;
7230
0
                    if (nBlockValidCount)
7231
0
                    {
7232
                        // Update the global mean and M2 (the difference of the
7233
                        // square to the mean) from the values of the block
7234
                        // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7235
0
                        const double dfBlockValidCount =
7236
0
                            static_cast<double>(nBlockValidCount);
7237
0
                        const double dfBlockMean =
7238
0
                            static_cast<double>(nBlockSum) / dfBlockValidCount;
7239
0
                        const double dfBlockM2 =
7240
0
                            static_cast<double>(
7241
0
                                GDALUInt128::Mul(nBlockSumSquare,
7242
0
                                                 nBlockValidCount) -
7243
0
                                GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7244
0
                            dfBlockValidCount;
7245
0
                        const double dfDelta = dfBlockMean - dfMean;
7246
0
                        const auto nNewValidCount =
7247
0
                            nValidCount + nBlockValidCount;
7248
0
                        const double dfNewValidCount =
7249
0
                            static_cast<double>(nNewValidCount);
7250
0
                        dfMean +=
7251
0
                            dfDelta * (dfBlockValidCount / dfNewValidCount);
7252
0
                        dfM2 +=
7253
0
                            dfBlockM2 + dfDelta * dfDelta *
7254
0
                                            static_cast<double>(nValidCount) *
7255
0
                                            dfBlockValidCount / dfNewValidCount;
7256
0
                        nValidCount = nNewValidCount;
7257
0
                    }
7258
0
                }
7259
7260
0
                if (!pfnProgress(static_cast<double>(iSampleBlock) /
7261
0
                                     (static_cast<double>(nBlocksPerRow) *
7262
0
                                      nBlocksPerColumn),
7263
0
                                 "Compute Statistics", pProgressData))
7264
0
                {
7265
0
                    ReportError(CE_Failure, CPLE_UserInterrupt,
7266
0
                                "User terminated");
7267
0
                    return CE_Failure;
7268
0
                }
7269
0
            }
7270
7271
0
            if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7272
0
            {
7273
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7274
0
                return CE_Failure;
7275
0
            }
7276
7277
0
            double dfStdDev = 0;
7278
0
            if (bIntegerStats)
7279
0
            {
7280
0
                if (nValidCount)
7281
0
                    dfMean = static_cast<double>(nSum) / nValidCount;
7282
7283
                // To avoid potential precision issues when doing the difference,
7284
                // we need to do that computation on 128 bit rather than casting
7285
                // to double
7286
0
                const GDALUInt128 nTmpForStdDev(
7287
0
                    GDALUInt128::Mul(nSumSquare, nValidCount) -
7288
0
                    GDALUInt128::Mul(nSum, nSum));
7289
0
                dfStdDev =
7290
0
                    nValidCount > 0
7291
0
                        ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7292
0
                        : 0.0;
7293
0
            }
7294
0
            else if (nValidCount > 0)
7295
0
            {
7296
0
                dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7297
0
            }
7298
7299
            /// Save computed information
7300
0
            if (nValidCount > 0)
7301
0
            {
7302
0
                if (bApproxOK)
7303
0
                {
7304
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7305
0
                }
7306
0
                else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7307
0
                {
7308
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7309
0
                }
7310
0
                SetStatistics(nMin, nMax, dfMean, dfStdDev);
7311
0
            }
7312
7313
0
            SetValidPercent(nSampleCount, nValidCount);
7314
7315
            /* --------------------------------------------------------------------
7316
             */
7317
            /*      Record results. */
7318
            /* --------------------------------------------------------------------
7319
             */
7320
0
            if (pdfMin != nullptr)
7321
0
                *pdfMin = nValidCount ? nMin : 0;
7322
0
            if (pdfMax != nullptr)
7323
0
                *pdfMax = nValidCount ? nMax : 0;
7324
7325
0
            if (pdfMean != nullptr)
7326
0
                *pdfMean = dfMean;
7327
7328
0
            if (pdfStdDev != nullptr)
7329
0
                *pdfStdDev = dfStdDev;
7330
7331
0
            if (nValidCount > 0)
7332
0
                return CE_None;
7333
7334
0
            ReportError(CE_Failure, CPLE_AppDefined,
7335
0
                        "Failed to compute statistics, no valid pixels found "
7336
0
                        "in sampling.");
7337
0
            return CE_Failure;
7338
0
        }
7339
7340
0
        GByte *pabyMaskData = nullptr;
7341
0
        if (poMaskBand)
7342
0
        {
7343
0
            pabyMaskData = static_cast<GByte *>(
7344
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7345
0
            if (!pabyMaskData)
7346
0
            {
7347
0
                return CE_Failure;
7348
0
            }
7349
0
        }
7350
7351
0
        float fMin = std::numeric_limits<float>::infinity();
7352
0
        float fMax = -std::numeric_limits<float>::infinity();
7353
0
        const bool bFloat32Optim =
7354
0
            eDataType == GDT_Float32 && !pabyMaskData &&
7355
0
            nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7356
0
            CPLTestBool(
7357
0
                CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7358
7359
0
#if (defined(__x86_64__) || defined(_M_X64))
7360
0
        const bool bFloat64Optim =
7361
0
            eDataType == GDT_Float64 && !pabyMaskData &&
7362
0
            nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7363
0
            CPLTestBool(
7364
0
                CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7365
0
#endif
7366
7367
0
        for (GIntBig iSampleBlock = 0;
7368
0
             iSampleBlock <
7369
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7370
0
             iSampleBlock += nSampleRate)
7371
0
        {
7372
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7373
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7374
7375
0
            int nXCheck = 0, nYCheck = 0;
7376
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7377
7378
0
            if (poMaskBand &&
7379
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7380
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
7381
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_Byte,
7382
0
                                     0, nBlockXSize, nullptr) != CE_None)
7383
0
            {
7384
0
                CPLFree(pabyMaskData);
7385
0
                return CE_Failure;
7386
0
            }
7387
7388
0
            GDALRasterBlock *const poBlock =
7389
0
                GetLockedBlockRef(iXBlock, iYBlock);
7390
0
            if (poBlock == nullptr)
7391
0
            {
7392
0
                CPLFree(pabyMaskData);
7393
0
                return CE_Failure;
7394
0
            }
7395
7396
0
            const void *const pData = poBlock->GetDataRef();
7397
7398
0
            if (bFloat32Optim)
7399
0
            {
7400
0
                const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7401
0
                                        !std::isnan(sNoDataValues.fNoDataValue);
7402
0
                float fBlockMean = 0.0f;
7403
0
                float fBlockM2 = 0.0f;
7404
0
                int nBlockValidCount = 0;
7405
0
                for (int iY = 0; iY < nYCheck; iY++)
7406
0
                {
7407
0
                    const int iOffset = iY * nBlockXSize;
7408
0
                    if (nBlockValidCount && fMin != fMax)
7409
0
                    {
7410
0
                        int iX = 0;
7411
0
#if (defined(__x86_64__) || defined(_M_X64))
7412
0
                        if (bHasNoData)
7413
0
                        {
7414
0
                            iX = ComputeStatisticsFloat32_SSE2<
7415
0
                                /* bCheckMinEqMax = */ false,
7416
0
                                /* bHasNoData = */ true>(
7417
0
                                static_cast<const float *>(pData) + iOffset,
7418
0
                                sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7419
0
                                fMax, fBlockMean, fBlockM2, nBlockValidCount);
7420
0
                        }
7421
0
                        else
7422
0
                        {
7423
0
                            iX = ComputeStatisticsFloat32_SSE2<
7424
0
                                /* bCheckMinEqMax = */ false,
7425
0
                                /* bHasNoData = */ false>(
7426
0
                                static_cast<const float *>(pData) + iOffset,
7427
0
                                sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7428
0
                                fMax, fBlockMean, fBlockM2, nBlockValidCount);
7429
0
                        }
7430
0
#endif
7431
0
                        for (; iX < nXCheck; iX++)
7432
0
                        {
7433
0
                            const float fValue =
7434
0
                                static_cast<const float *>(pData)[iOffset + iX];
7435
0
                            if (std::isnan(fValue) ||
7436
0
                                (bHasNoData &&
7437
0
                                 fValue == sNoDataValues.fNoDataValue))
7438
0
                                continue;
7439
0
                            fMin = std::min(fMin, fValue);
7440
0
                            fMax = std::max(fMax, fValue);
7441
0
                            ++nBlockValidCount;
7442
0
                            const float fDelta = fValue - fBlockMean;
7443
0
                            fBlockMean +=
7444
0
                                fDelta / static_cast<float>(nBlockValidCount);
7445
0
                            fBlockM2 += fDelta * (fValue - fBlockMean);
7446
0
                        }
7447
0
                    }
7448
0
                    else
7449
0
                    {
7450
0
                        int iX = 0;
7451
0
                        if (nBlockValidCount == 0)
7452
0
                        {
7453
0
                            for (; iX < nXCheck; iX++)
7454
0
                            {
7455
0
                                const float fValue = static_cast<const float *>(
7456
0
                                    pData)[iOffset + iX];
7457
0
                                if (std::isnan(fValue) ||
7458
0
                                    (bHasNoData &&
7459
0
                                     fValue == sNoDataValues.fNoDataValue))
7460
0
                                    continue;
7461
0
                                fMin = std::min(fMin, fValue);
7462
0
                                fMax = std::max(fMax, fValue);
7463
0
                                nBlockValidCount = 1;
7464
0
                                fBlockMean = fValue;
7465
0
                                iX++;
7466
0
                                break;
7467
0
                            }
7468
0
                        }
7469
0
#if (defined(__x86_64__) || defined(_M_X64))
7470
0
                        if (bHasNoData)
7471
0
                        {
7472
0
                            iX = ComputeStatisticsFloat32_SSE2<
7473
0
                                /* bCheckMinEqMax = */ true,
7474
0
                                /* bHasNoData = */ true>(
7475
0
                                static_cast<const float *>(pData) + iOffset,
7476
0
                                sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7477
0
                                fMax, fBlockMean, fBlockM2, nBlockValidCount);
7478
0
                        }
7479
0
                        else
7480
0
                        {
7481
0
                            iX = ComputeStatisticsFloat32_SSE2<
7482
0
                                /* bCheckMinEqMax = */ true,
7483
0
                                /* bHasNoData = */ false>(
7484
0
                                static_cast<const float *>(pData) + iOffset,
7485
0
                                sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7486
0
                                fMax, fBlockMean, fBlockM2, nBlockValidCount);
7487
0
                        }
7488
0
#endif
7489
0
                        for (; iX < nXCheck; iX++)
7490
0
                        {
7491
0
                            const float fValue =
7492
0
                                static_cast<const float *>(pData)[iOffset + iX];
7493
0
                            if (std::isnan(fValue) ||
7494
0
                                (bHasNoData &&
7495
0
                                 fValue == sNoDataValues.fNoDataValue))
7496
0
                                continue;
7497
0
                            fMin = std::min(fMin, fValue);
7498
0
                            fMax = std::max(fMax, fValue);
7499
0
                            ++nBlockValidCount;
7500
0
                            if (fMin != fMax)
7501
0
                            {
7502
0
                                const float fDelta = fValue - fBlockMean;
7503
0
                                fBlockMean += fDelta / static_cast<float>(
7504
0
                                                           nBlockValidCount);
7505
0
                                fBlockM2 += fDelta * (fValue - fBlockMean);
7506
0
                            }
7507
0
                        }
7508
0
                    }
7509
0
                }
7510
7511
0
                if (nBlockValidCount)
7512
0
                {
7513
                    // Update the global mean and M2 (the difference of the
7514
                    // square to the mean) from the values of the block
7515
                    // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7516
0
                    const auto nNewValidCount = nValidCount + nBlockValidCount;
7517
0
                    const double dfBlockMean = static_cast<double>(fBlockMean);
7518
0
                    if (dfBlockMean != dfMean)
7519
0
                    {
7520
0
                        const double dfBlockM2 = static_cast<double>(fBlockM2);
7521
0
                        if (nValidCount == 0)
7522
0
                        {
7523
0
                            dfMean = dfBlockMean;
7524
0
                            dfM2 = dfBlockM2;
7525
0
                        }
7526
0
                        else
7527
0
                        {
7528
0
                            const double dfBlockValidCount =
7529
0
                                static_cast<double>(nBlockValidCount);
7530
0
                            const double dfDelta = dfBlockMean - dfMean;
7531
0
                            const double dfNewValidCount =
7532
0
                                static_cast<double>(nNewValidCount);
7533
0
                            dfMean +=
7534
0
                                dfDelta * (dfBlockValidCount / dfNewValidCount);
7535
0
                            dfM2 += dfBlockM2 +
7536
0
                                    dfDelta * dfDelta *
7537
0
                                        static_cast<double>(nValidCount) *
7538
0
                                        dfBlockValidCount / dfNewValidCount;
7539
0
                        }
7540
0
                    }
7541
0
                    nValidCount = nNewValidCount;
7542
0
                }
7543
0
            }
7544
7545
0
#if (defined(__x86_64__) || defined(_M_X64))
7546
0
            else if (bFloat64Optim)
7547
0
            {
7548
0
                const bool bHasNoData =
7549
0
                    sNoDataValues.bGotNoDataValue &&
7550
0
                    !std::isnan(sNoDataValues.dfNoDataValue);
7551
0
                double dfBlockMean = 0;
7552
0
                double dfBlockM2 = 0;
7553
0
                double dfBlockValidCount = 0;
7554
0
                for (int iY = 0; iY < nYCheck; iY++)
7555
0
                {
7556
0
                    const int iOffset = iY * nBlockXSize;
7557
0
                    if (dfBlockValidCount != 0 && dfMin != dfMax)
7558
0
                    {
7559
0
                        int iX = 0;
7560
0
                        if (bHasNoData)
7561
0
                        {
7562
0
                            iX = ComputeStatisticsFloat64_SSE2<
7563
0
                                /* bCheckMinEqMax = */ false,
7564
0
                                /* bHasNoData = */ true>(
7565
0
                                static_cast<const double *>(pData) + iOffset,
7566
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7567
0
                                dfMax, dfBlockMean, dfBlockM2,
7568
0
                                dfBlockValidCount);
7569
0
                        }
7570
0
                        else
7571
0
                        {
7572
0
                            iX = ComputeStatisticsFloat64_SSE2<
7573
0
                                /* bCheckMinEqMax = */ false,
7574
0
                                /* bHasNoData = */ false>(
7575
0
                                static_cast<const double *>(pData) + iOffset,
7576
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7577
0
                                dfMax, dfBlockMean, dfBlockM2,
7578
0
                                dfBlockValidCount);
7579
0
                        }
7580
0
                        for (; iX < nXCheck; iX++)
7581
0
                        {
7582
0
                            const double dfValue = static_cast<const double *>(
7583
0
                                pData)[iOffset + iX];
7584
0
                            if (std::isnan(dfValue) ||
7585
0
                                (bHasNoData &&
7586
0
                                 dfValue == sNoDataValues.dfNoDataValue))
7587
0
                                continue;
7588
0
                            dfMin = std::min(dfMin, dfValue);
7589
0
                            dfMax = std::max(dfMax, dfValue);
7590
0
                            dfBlockValidCount += 1.0;
7591
0
                            const double dfDelta = dfValue - dfBlockMean;
7592
0
                            dfBlockMean += dfDelta / dfBlockValidCount;
7593
0
                            dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7594
0
                        }
7595
0
                    }
7596
0
                    else
7597
0
                    {
7598
0
                        int iX = 0;
7599
0
                        if (dfBlockValidCount == 0)
7600
0
                        {
7601
0
                            for (; iX < nXCheck; iX++)
7602
0
                            {
7603
0
                                const double dfValue =
7604
0
                                    static_cast<const double *>(
7605
0
                                        pData)[iOffset + iX];
7606
0
                                if (std::isnan(dfValue) ||
7607
0
                                    (bHasNoData &&
7608
0
                                     dfValue == sNoDataValues.dfNoDataValue))
7609
0
                                    continue;
7610
0
                                dfMin = std::min(dfMin, dfValue);
7611
0
                                dfMax = std::max(dfMax, dfValue);
7612
0
                                dfBlockValidCount = 1;
7613
0
                                dfBlockMean = dfValue;
7614
0
                                iX++;
7615
0
                                break;
7616
0
                            }
7617
0
                        }
7618
0
                        if (bHasNoData)
7619
0
                        {
7620
0
                            iX = ComputeStatisticsFloat64_SSE2<
7621
0
                                /* bCheckMinEqMax = */ true,
7622
0
                                /* bHasNoData = */ true>(
7623
0
                                static_cast<const double *>(pData) + iOffset,
7624
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7625
0
                                dfMax, dfBlockMean, dfBlockM2,
7626
0
                                dfBlockValidCount);
7627
0
                        }
7628
0
                        else
7629
0
                        {
7630
0
                            iX = ComputeStatisticsFloat64_SSE2<
7631
0
                                /* bCheckMinEqMax = */ true,
7632
0
                                /* bHasNoData = */ false>(
7633
0
                                static_cast<const double *>(pData) + iOffset,
7634
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7635
0
                                dfMax, dfBlockMean, dfBlockM2,
7636
0
                                dfBlockValidCount);
7637
0
                        }
7638
0
                        for (; iX < nXCheck; iX++)
7639
0
                        {
7640
0
                            const double dfValue = static_cast<const double *>(
7641
0
                                pData)[iOffset + iX];
7642
0
                            if (std::isnan(dfValue) ||
7643
0
                                (bHasNoData &&
7644
0
                                 dfValue == sNoDataValues.dfNoDataValue))
7645
0
                                continue;
7646
0
                            dfMin = std::min(dfMin, dfValue);
7647
0
                            dfMax = std::max(dfMax, dfValue);
7648
0
                            dfBlockValidCount += 1.0;
7649
0
                            if (dfMin != dfMax)
7650
0
                            {
7651
0
                                const double dfDelta = dfValue - dfBlockMean;
7652
0
                                dfBlockMean += dfDelta / dfBlockValidCount;
7653
0
                                dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7654
0
                            }
7655
0
                        }
7656
0
                    }
7657
0
                }
7658
7659
0
                if (dfBlockValidCount > 0)
7660
0
                {
7661
                    // Update the global mean and M2 (the difference of the
7662
                    // square to the mean) from the values of the block
7663
                    // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7664
0
                    const auto nNewValidCount =
7665
0
                        nValidCount + static_cast<int>(dfBlockValidCount);
7666
0
                    if (dfBlockMean != dfMean)
7667
0
                    {
7668
0
                        if (nValidCount == 0)
7669
0
                        {
7670
0
                            dfMean = dfBlockMean;
7671
0
                            dfM2 = dfBlockM2;
7672
0
                        }
7673
0
                        else
7674
0
                        {
7675
0
                            const double dfDelta = dfBlockMean - dfMean;
7676
0
                            const double dfNewValidCount =
7677
0
                                static_cast<double>(nNewValidCount);
7678
0
                            dfMean +=
7679
0
                                dfDelta * (dfBlockValidCount / dfNewValidCount);
7680
0
                            dfM2 += dfBlockM2 +
7681
0
                                    dfDelta * dfDelta *
7682
0
                                        static_cast<double>(nValidCount) *
7683
0
                                        dfBlockValidCount / dfNewValidCount;
7684
0
                        }
7685
0
                    }
7686
0
                    nValidCount = nNewValidCount;
7687
0
                }
7688
0
            }
7689
0
#endif  // (defined(__x86_64__) || defined(_M_X64))
7690
7691
0
            else
7692
0
            {
7693
                // This isn't the fastest way to do this, but is easier for now.
7694
0
                for (int iY = 0; iY < nYCheck; iY++)
7695
0
                {
7696
0
                    if (nValidCount && dfMin != dfMax)
7697
0
                    {
7698
0
                        for (int iX = 0; iX < nXCheck; iX++)
7699
0
                        {
7700
0
                            const GPtrDiff_t iOffset =
7701
0
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7702
0
                            if (pabyMaskData && pabyMaskData[iOffset] == 0)
7703
0
                                continue;
7704
7705
0
                            bool bValid = true;
7706
0
                            double dfValue =
7707
0
                                GetPixelValue(eDataType, bSignedByte, pData,
7708
0
                                              iOffset, sNoDataValues, bValid);
7709
7710
0
                            if (!bValid)
7711
0
                                continue;
7712
7713
0
                            dfMin = std::min(dfMin, dfValue);
7714
0
                            dfMax = std::max(dfMax, dfValue);
7715
7716
0
                            nValidCount++;
7717
0
                            const double dfDelta = dfValue - dfMean;
7718
0
                            dfMean += dfDelta / nValidCount;
7719
0
                            dfM2 += dfDelta * (dfValue - dfMean);
7720
0
                        }
7721
0
                    }
7722
0
                    else
7723
0
                    {
7724
0
                        int iX = 0;
7725
0
                        if (nValidCount == 0)
7726
0
                        {
7727
0
                            for (; iX < nXCheck; iX++)
7728
0
                            {
7729
0
                                const GPtrDiff_t iOffset =
7730
0
                                    iX +
7731
0
                                    static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7732
0
                                if (pabyMaskData && pabyMaskData[iOffset] == 0)
7733
0
                                    continue;
7734
7735
0
                                bool bValid = true;
7736
0
                                double dfValue = GetPixelValue(
7737
0
                                    eDataType, bSignedByte, pData, iOffset,
7738
0
                                    sNoDataValues, bValid);
7739
7740
0
                                if (!bValid)
7741
0
                                    continue;
7742
7743
0
                                dfMin = dfValue;
7744
0
                                dfMax = dfValue;
7745
0
                                dfMean = dfValue;
7746
0
                                nValidCount = 1;
7747
0
                                iX++;
7748
0
                                break;
7749
0
                            }
7750
0
                        }
7751
0
                        for (; iX < nXCheck; iX++)
7752
0
                        {
7753
0
                            const GPtrDiff_t iOffset =
7754
0
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7755
0
                            if (pabyMaskData && pabyMaskData[iOffset] == 0)
7756
0
                                continue;
7757
7758
0
                            bool bValid = true;
7759
0
                            double dfValue =
7760
0
                                GetPixelValue(eDataType, bSignedByte, pData,
7761
0
                                              iOffset, sNoDataValues, bValid);
7762
7763
0
                            if (!bValid)
7764
0
                                continue;
7765
7766
0
                            dfMin = std::min(dfMin, dfValue);
7767
0
                            dfMax = std::max(dfMax, dfValue);
7768
7769
0
                            nValidCount++;
7770
0
                            if (dfMin != dfMax)
7771
0
                            {
7772
0
                                const double dfDelta = dfValue - dfMean;
7773
0
                                dfMean += dfDelta / nValidCount;
7774
0
                                dfM2 += dfDelta * (dfValue - dfMean);
7775
0
                            }
7776
0
                        }
7777
0
                    }
7778
0
                }
7779
0
            }
7780
7781
0
            nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
7782
7783
0
            poBlock->DropLock();
7784
7785
0
            if (!pfnProgress(
7786
0
                    static_cast<double>(iSampleBlock) /
7787
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
7788
0
                    "Compute Statistics", pProgressData))
7789
0
            {
7790
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7791
0
                CPLFree(pabyMaskData);
7792
0
                return CE_Failure;
7793
0
            }
7794
0
        }
7795
7796
0
        if (bFloat32Optim)
7797
0
        {
7798
0
            dfMin = static_cast<double>(fMin);
7799
0
            dfMax = static_cast<double>(fMax);
7800
0
        }
7801
0
        CPLFree(pabyMaskData);
7802
0
    }
7803
7804
0
    if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7805
0
    {
7806
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7807
0
        return CE_Failure;
7808
0
    }
7809
7810
    /* -------------------------------------------------------------------- */
7811
    /*      Save computed information.                                      */
7812
    /* -------------------------------------------------------------------- */
7813
0
    const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
7814
7815
0
    if (nValidCount > 0)
7816
0
    {
7817
0
        if (bApproxOK)
7818
0
        {
7819
0
            SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7820
0
        }
7821
0
        else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7822
0
        {
7823
0
            SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7824
0
        }
7825
0
        SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7826
0
    }
7827
0
    else
7828
0
    {
7829
0
        dfMin = 0.0;
7830
0
        dfMax = 0.0;
7831
0
    }
7832
7833
0
    SetValidPercent(nSampleCount, nValidCount);
7834
7835
    /* -------------------------------------------------------------------- */
7836
    /*      Record results.                                                 */
7837
    /* -------------------------------------------------------------------- */
7838
0
    if (pdfMin != nullptr)
7839
0
        *pdfMin = dfMin;
7840
0
    if (pdfMax != nullptr)
7841
0
        *pdfMax = dfMax;
7842
7843
0
    if (pdfMean != nullptr)
7844
0
        *pdfMean = dfMean;
7845
7846
0
    if (pdfStdDev != nullptr)
7847
0
        *pdfStdDev = dfStdDev;
7848
7849
0
    if (nValidCount > 0)
7850
0
        return CE_None;
7851
7852
0
    ReportError(
7853
0
        CE_Failure, CPLE_AppDefined,
7854
0
        "Failed to compute statistics, no valid pixels found in sampling.");
7855
0
    return CE_Failure;
7856
0
}
7857
7858
/************************************************************************/
7859
/*                    GDALComputeRasterStatistics()                     */
7860
/************************************************************************/
7861
7862
/**
7863
 * \brief Compute image statistics.
7864
 *
7865
 * @see GDALRasterBand::ComputeStatistics()
7866
 */
7867
7868
CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7869
                                               int bApproxOK, double *pdfMin,
7870
                                               double *pdfMax, double *pdfMean,
7871
                                               double *pdfStdDev,
7872
                                               GDALProgressFunc pfnProgress,
7873
                                               void *pProgressData)
7874
7875
0
{
7876
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7877
7878
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7879
7880
0
    return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7881
0
                                     pdfStdDev, pfnProgress, pProgressData);
7882
0
}
7883
7884
/************************************************************************/
7885
/*                           SetStatistics()                            */
7886
/************************************************************************/
7887
7888
/**
7889
 * \brief Set statistics on band.
7890
 *
7891
 * This method can be used to store min/max/mean/standard deviation
7892
 * statistics on a raster band.
7893
 *
7894
 * The default implementation stores them as metadata, and will only work
7895
 * on formats that can save arbitrary metadata.  This method cannot detect
7896
 * whether metadata will be properly saved and so may return CE_None even
7897
 * if the statistics will never be saved.
7898
 *
7899
 * This method is the same as the C function GDALSetRasterStatistics().
7900
 *
7901
 * @param dfMin minimum pixel value.
7902
 *
7903
 * @param dfMax maximum pixel value.
7904
 *
7905
 * @param dfMean mean (average) of all pixel values.
7906
 *
7907
 * @param dfStdDev Standard deviation of all pixel values.
7908
 *
7909
 * @return CE_None on success or CE_Failure on failure.
7910
 */
7911
7912
CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7913
                                     double dfStdDev)
7914
7915
0
{
7916
0
    char szValue[128] = {0};
7917
7918
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7919
0
    SetMetadataItem("STATISTICS_MINIMUM", szValue);
7920
7921
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7922
0
    SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7923
7924
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7925
0
    SetMetadataItem("STATISTICS_MEAN", szValue);
7926
7927
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7928
0
    SetMetadataItem("STATISTICS_STDDEV", szValue);
7929
7930
0
    return CE_None;
7931
0
}
7932
7933
/************************************************************************/
7934
/*                      GDALSetRasterStatistics()                       */
7935
/************************************************************************/
7936
7937
/**
7938
 * \brief Set statistics on band.
7939
 *
7940
 * @see GDALRasterBand::SetStatistics()
7941
 */
7942
7943
CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7944
                                           double dfMax, double dfMean,
7945
                                           double dfStdDev)
7946
7947
0
{
7948
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7949
7950
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7951
0
    return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7952
0
}
7953
7954
/************************************************************************/
7955
/*                        ComputeRasterMinMax()                         */
7956
/************************************************************************/
7957
7958
template <class T, bool HAS_NODATA>
7959
static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7960
                          T *pMax)
7961
0
{
7962
0
    T min0 = *pMin;
7963
0
    T max0 = *pMax;
7964
0
    T min1 = *pMin;
7965
0
    T max1 = *pMax;
7966
0
    size_t i;
7967
0
    for (i = 0; i + 1 < nElts; i += 2)
7968
0
    {
7969
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
7970
0
        {
7971
0
            min0 = std::min(min0, buffer[i]);
7972
0
            max0 = std::max(max0, buffer[i]);
7973
0
        }
7974
0
        if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7975
0
        {
7976
0
            min1 = std::min(min1, buffer[i + 1]);
7977
0
            max1 = std::max(max1, buffer[i + 1]);
7978
0
        }
7979
0
    }
7980
0
    T min = std::min(min0, min1);
7981
0
    T max = std::max(max0, max1);
7982
0
    if (i < nElts)
7983
0
    {
7984
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
7985
0
        {
7986
0
            min = std::min(min, buffer[i]);
7987
0
            max = std::max(max, buffer[i]);
7988
0
        }
7989
0
    }
7990
0
    *pMin = min;
7991
0
    *pMax = max;
7992
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*)
7993
7994
template <GDALDataType eDataType, bool bSignedByte>
7995
static void
7996
ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7997
                     int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7998
                     const GByte *pabyMaskData, double &dfMin, double &dfMax)
7999
0
{
8000
0
    double dfLocalMin = dfMin;
8001
0
    double dfLocalMax = dfMax;
8002
8003
0
    for (int iY = 0; iY < nYCheck; iY++)
8004
0
    {
8005
0
        for (int iX = 0; iX < nXCheck; iX++)
8006
0
        {
8007
0
            const GPtrDiff_t iOffset =
8008
0
                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8009
0
            if (pabyMaskData && pabyMaskData[iOffset] == 0)
8010
0
                continue;
8011
0
            bool bValid = true;
8012
0
            double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
8013
0
                                           iOffset, sNoDataValues, bValid);
8014
0
            if (!bValid)
8015
0
                continue;
8016
8017
0
            dfLocalMin = std::min(dfLocalMin, dfValue);
8018
0
            dfLocalMax = std::max(dfLocalMax, dfValue);
8019
0
        }
8020
0
    }
8021
8022
0
    dfMin = dfLocalMin;
8023
0
    dfMax = dfLocalMax;
8024
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&)
8025
8026
static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8027
                                 bool bSignedByte, int nXCheck, int nYCheck,
8028
                                 int nBlockXSize,
8029
                                 const GDALNoDataValues &sNoDataValues,
8030
                                 const GByte *pabyMaskData, double &dfMin,
8031
                                 double &dfMax)
8032
0
{
8033
0
    switch (eDataType)
8034
0
    {
8035
0
        case GDT_Unknown:
8036
0
            CPLAssert(false);
8037
0
            break;
8038
0
        case GDT_Byte:
8039
0
            if (bSignedByte)
8040
0
            {
8041
0
                ComputeMinMaxGeneric<GDT_Byte, true>(
8042
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8043
0
                    pabyMaskData, dfMin, dfMax);
8044
0
            }
8045
0
            else
8046
0
            {
8047
0
                ComputeMinMaxGeneric<GDT_Byte, false>(
8048
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8049
0
                    pabyMaskData, dfMin, dfMax);
8050
0
            }
8051
0
            break;
8052
0
        case GDT_Int8:
8053
0
            ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8054
0
                                                  nBlockXSize, sNoDataValues,
8055
0
                                                  pabyMaskData, dfMin, dfMax);
8056
0
            break;
8057
0
        case GDT_UInt16:
8058
0
            ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8059
0
                                                    nBlockXSize, sNoDataValues,
8060
0
                                                    pabyMaskData, dfMin, dfMax);
8061
0
            break;
8062
0
        case GDT_Int16:
8063
0
            ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8064
0
                                                   nBlockXSize, sNoDataValues,
8065
0
                                                   pabyMaskData, dfMin, dfMax);
8066
0
            break;
8067
0
        case GDT_UInt32:
8068
0
            ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8069
0
                                                    nBlockXSize, sNoDataValues,
8070
0
                                                    pabyMaskData, dfMin, dfMax);
8071
0
            break;
8072
0
        case GDT_Int32:
8073
0
            ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8074
0
                                                   nBlockXSize, sNoDataValues,
8075
0
                                                   pabyMaskData, dfMin, dfMax);
8076
0
            break;
8077
0
        case GDT_UInt64:
8078
0
            ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8079
0
                                                    nBlockXSize, sNoDataValues,
8080
0
                                                    pabyMaskData, dfMin, dfMax);
8081
0
            break;
8082
0
        case GDT_Int64:
8083
0
            ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8084
0
                                                   nBlockXSize, sNoDataValues,
8085
0
                                                   pabyMaskData, dfMin, dfMax);
8086
0
            break;
8087
0
        case GDT_Float16:
8088
0
            ComputeMinMaxGeneric<GDT_Float16, false>(
8089
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8090
0
                pabyMaskData, dfMin, dfMax);
8091
0
            break;
8092
0
        case GDT_Float32:
8093
0
            ComputeMinMaxGeneric<GDT_Float32, false>(
8094
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8095
0
                pabyMaskData, dfMin, dfMax);
8096
0
            break;
8097
0
        case GDT_Float64:
8098
0
            ComputeMinMaxGeneric<GDT_Float64, false>(
8099
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8100
0
                pabyMaskData, dfMin, dfMax);
8101
0
            break;
8102
0
        case GDT_CInt16:
8103
0
            ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8104
0
                                                    nBlockXSize, sNoDataValues,
8105
0
                                                    pabyMaskData, dfMin, dfMax);
8106
0
            break;
8107
0
        case GDT_CInt32:
8108
0
            ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8109
0
                                                    nBlockXSize, sNoDataValues,
8110
0
                                                    pabyMaskData, dfMin, dfMax);
8111
0
            break;
8112
0
        case GDT_CFloat16:
8113
0
            ComputeMinMaxGeneric<GDT_CFloat16, false>(
8114
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8115
0
                pabyMaskData, dfMin, dfMax);
8116
0
            break;
8117
0
        case GDT_CFloat32:
8118
0
            ComputeMinMaxGeneric<GDT_CFloat32, false>(
8119
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8120
0
                pabyMaskData, dfMin, dfMax);
8121
0
            break;
8122
0
        case GDT_CFloat64:
8123
0
            ComputeMinMaxGeneric<GDT_CFloat64, false>(
8124
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8125
0
                pabyMaskData, dfMin, dfMax);
8126
0
            break;
8127
0
        case GDT_TypeCount:
8128
0
            CPLAssert(false);
8129
0
            break;
8130
0
    }
8131
0
}
8132
8133
static bool ComputeMinMaxGenericIterBlocks(
8134
    GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8135
    GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8136
    const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8137
    double &dfMin, double &dfMax)
8138
8139
0
{
8140
0
    GByte *pabyMaskData = nullptr;
8141
0
    int nBlockXSize, nBlockYSize;
8142
0
    poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8143
8144
0
    if (poMaskBand)
8145
0
    {
8146
0
        pabyMaskData =
8147
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8148
0
        if (!pabyMaskData)
8149
0
        {
8150
0
            return false;
8151
0
        }
8152
0
    }
8153
8154
0
    for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8155
0
         iSampleBlock += nSampleRate)
8156
0
    {
8157
0
        const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8158
0
        const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8159
8160
0
        int nXCheck = 0, nYCheck = 0;
8161
0
        poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8162
8163
0
        if (poMaskBand &&
8164
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8165
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
8166
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
8167
0
                                 nBlockXSize, nullptr) != CE_None)
8168
0
        {
8169
0
            CPLFree(pabyMaskData);
8170
0
            return false;
8171
0
        }
8172
8173
0
        GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8174
0
        if (poBlock == nullptr)
8175
0
        {
8176
0
            CPLFree(pabyMaskData);
8177
0
            return false;
8178
0
        }
8179
8180
0
        void *const pData = poBlock->GetDataRef();
8181
8182
0
        ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8183
0
                             nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8184
0
                             dfMax);
8185
8186
0
        poBlock->DropLock();
8187
0
    }
8188
8189
0
    CPLFree(pabyMaskData);
8190
0
    return true;
8191
0
}
8192
8193
/**
8194
 * \brief Compute the min/max values for a band.
8195
 *
8196
 * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8197
 * be trusted.  If it doesn't work, a subsample of blocks will be read to
8198
 * get an approximate min/max.  If the band has a nodata value it will
8199
 * be excluded from the minimum and maximum.
8200
 *
8201
 * If bApprox is FALSE, then all pixels will be read and used to compute
8202
 * an exact range.
8203
 *
8204
 * This method is the same as the C function GDALComputeRasterMinMax().
8205
 *
8206
 * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8207
 * FALSE.
8208
 * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8209
 * maximum (adfMinMax[1]) are returned.
8210
 *
8211
 * @return CE_None on success or CE_Failure on failure.
8212
 */
8213
8214
CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8215
0
{
8216
    /* -------------------------------------------------------------------- */
8217
    /*      Does the driver already know the min/max?                       */
8218
    /* -------------------------------------------------------------------- */
8219
0
    if (bApproxOK)
8220
0
    {
8221
0
        int bSuccessMin = FALSE;
8222
0
        int bSuccessMax = FALSE;
8223
8224
0
        double dfMin = GetMinimum(&bSuccessMin);
8225
0
        double dfMax = GetMaximum(&bSuccessMax);
8226
8227
0
        if (bSuccessMin && bSuccessMax)
8228
0
        {
8229
0
            adfMinMax[0] = dfMin;
8230
0
            adfMinMax[1] = dfMax;
8231
0
            return CE_None;
8232
0
        }
8233
0
    }
8234
8235
    /* -------------------------------------------------------------------- */
8236
    /*      If we have overview bands, use them for min/max.                */
8237
    /* -------------------------------------------------------------------- */
8238
    // cppcheck-suppress knownConditionTrueFalse
8239
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8240
0
    {
8241
0
        GDALRasterBand *poBand =
8242
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8243
8244
0
        if (poBand != this)
8245
0
            return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8246
0
    }
8247
8248
    /* -------------------------------------------------------------------- */
8249
    /*      Read actual data and compute minimum and maximum.               */
8250
    /* -------------------------------------------------------------------- */
8251
0
    GDALNoDataValues sNoDataValues(this, eDataType);
8252
0
    GDALRasterBand *poMaskBand = nullptr;
8253
0
    if (!sNoDataValues.bGotNoDataValue)
8254
0
    {
8255
0
        const int l_nMaskFlags = GetMaskFlags();
8256
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
8257
0
            GetColorInterpretation() != GCI_AlphaBand)
8258
0
        {
8259
0
            poMaskBand = GetMaskBand();
8260
0
        }
8261
0
    }
8262
8263
0
    bool bSignedByte = false;
8264
0
    if (eDataType == GDT_Byte)
8265
0
    {
8266
0
        EnablePixelTypeSignedByteWarning(false);
8267
0
        const char *pszPixelType =
8268
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8269
0
        EnablePixelTypeSignedByteWarning(true);
8270
0
        bSignedByte =
8271
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8272
0
    }
8273
8274
0
    GDALRasterIOExtraArg sExtraArg;
8275
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8276
8277
0
    GUInt32 nMin = (eDataType == GDT_Byte)
8278
0
                       ? 255
8279
0
                       : 65535;  // used for GByte & GUInt16 cases
8280
0
    GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
8281
0
    GInt16 nMinInt16 =
8282
0
        std::numeric_limits<GInt16>::max();  // used for GInt16 case
8283
0
    GInt16 nMaxInt16 =
8284
0
        std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
8285
0
    double dfMin =
8286
0
        std::numeric_limits<double>::infinity();  // used for generic code path
8287
0
    double dfMax =
8288
0
        -std::numeric_limits<double>::infinity();  // used for generic code path
8289
0
    const bool bUseOptimizedPath =
8290
0
        !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
8291
0
                        eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8292
8293
0
    const auto ComputeMinMaxForBlock =
8294
0
        [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8295
0
         &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8296
0
                     int nYCheck)
8297
0
    {
8298
0
        if (eDataType == GDT_Byte && !bSignedByte)
8299
0
        {
8300
0
            const bool bHasNoData =
8301
0
                sNoDataValues.bGotNoDataValue &&
8302
0
                GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8303
0
                static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8304
0
                    sNoDataValues.dfNoDataValue;
8305
0
            const GUInt32 nNoDataValue =
8306
0
                bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8307
0
                           : 0;
8308
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
8309
0
            ComputeStatisticsInternal<GByte,
8310
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
8311
0
                f(nXCheck, nBufferWidth, nYCheck,
8312
0
                  static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8313
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8314
0
        }
8315
0
        else if (eDataType == GDT_UInt16)
8316
0
        {
8317
0
            const bool bHasNoData =
8318
0
                sNoDataValues.bGotNoDataValue &&
8319
0
                GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8320
0
                static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8321
0
                    sNoDataValues.dfNoDataValue;
8322
0
            const GUInt32 nNoDataValue =
8323
0
                bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8324
0
                           : 0;
8325
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
8326
0
            ComputeStatisticsInternal<GUInt16,
8327
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
8328
0
                f(nXCheck, nBufferWidth, nYCheck,
8329
0
                  static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8330
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8331
0
        }
8332
0
        else if (eDataType == GDT_Int16)
8333
0
        {
8334
0
            const bool bHasNoData =
8335
0
                sNoDataValues.bGotNoDataValue &&
8336
0
                GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8337
0
                static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8338
0
                    sNoDataValues.dfNoDataValue;
8339
0
            if (bHasNoData)
8340
0
            {
8341
0
                const int16_t nNoDataValue =
8342
0
                    static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8343
0
                for (int iY = 0; iY < nYCheck; iY++)
8344
0
                {
8345
0
                    ComputeMinMax<int16_t, true>(
8346
0
                        static_cast<const int16_t *>(pData) +
8347
0
                            static_cast<size_t>(iY) * nBufferWidth,
8348
0
                        nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8349
0
                }
8350
0
            }
8351
0
            else
8352
0
            {
8353
0
                for (int iY = 0; iY < nYCheck; iY++)
8354
0
                {
8355
0
                    ComputeMinMax<int16_t, false>(
8356
0
                        static_cast<const int16_t *>(pData) +
8357
0
                            static_cast<size_t>(iY) * nBufferWidth,
8358
0
                        nXCheck, 0, &nMinInt16, &nMaxInt16);
8359
0
                }
8360
0
            }
8361
0
        }
8362
0
    };
8363
8364
0
    if (bApproxOK && HasArbitraryOverviews())
8365
0
    {
8366
        /* --------------------------------------------------------------------
8367
         */
8368
        /*      Figure out how much the image should be reduced to get an */
8369
        /*      approximate value. */
8370
        /* --------------------------------------------------------------------
8371
         */
8372
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8373
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8374
8375
0
        int nXReduced = nRasterXSize;
8376
0
        int nYReduced = nRasterYSize;
8377
0
        if (dfReduction > 1.0)
8378
0
        {
8379
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8380
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8381
8382
            // Catch the case of huge resizing ratios here
8383
0
            if (nXReduced == 0)
8384
0
                nXReduced = 1;
8385
0
            if (nYReduced == 0)
8386
0
                nYReduced = 1;
8387
0
        }
8388
8389
0
        void *const pData = CPLMalloc(cpl::fits_on<int>(
8390
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8391
8392
0
        const CPLErr eErr =
8393
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8394
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8395
0
        if (eErr != CE_None)
8396
0
        {
8397
0
            CPLFree(pData);
8398
0
            return eErr;
8399
0
        }
8400
8401
0
        GByte *pabyMaskData = nullptr;
8402
0
        if (poMaskBand)
8403
0
        {
8404
0
            pabyMaskData =
8405
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8406
0
            if (!pabyMaskData)
8407
0
            {
8408
0
                CPLFree(pData);
8409
0
                return CE_Failure;
8410
0
            }
8411
8412
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8413
0
                                     pabyMaskData, nXReduced, nYReduced,
8414
0
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
8415
0
            {
8416
0
                CPLFree(pData);
8417
0
                CPLFree(pabyMaskData);
8418
0
                return CE_Failure;
8419
0
            }
8420
0
        }
8421
8422
0
        if (bUseOptimizedPath)
8423
0
        {
8424
0
            ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8425
0
        }
8426
0
        else
8427
0
        {
8428
0
            ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8429
0
                                 nYReduced, nXReduced, sNoDataValues,
8430
0
                                 pabyMaskData, dfMin, dfMax);
8431
0
        }
8432
8433
0
        CPLFree(pData);
8434
0
        CPLFree(pabyMaskData);
8435
0
    }
8436
8437
0
    else  // No arbitrary overviews
8438
0
    {
8439
0
        if (!InitBlockInfo())
8440
0
            return CE_Failure;
8441
8442
        /* --------------------------------------------------------------------
8443
         */
8444
        /*      Figure out the ratio of blocks we will read to get an */
8445
        /*      approximate value. */
8446
        /* --------------------------------------------------------------------
8447
         */
8448
0
        int nSampleRate = 1;
8449
8450
0
        if (bApproxOK)
8451
0
        {
8452
0
            nSampleRate = static_cast<int>(std::max(
8453
0
                1.0,
8454
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8455
            // We want to avoid probing only the first column of blocks for
8456
            // a square shaped raster, because it is not unlikely that it may
8457
            // be padding only (#6378).
8458
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8459
0
                nSampleRate += 1;
8460
0
        }
8461
8462
0
        if (bUseOptimizedPath)
8463
0
        {
8464
0
            for (GIntBig iSampleBlock = 0;
8465
0
                 iSampleBlock <
8466
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8467
0
                 iSampleBlock += nSampleRate)
8468
0
            {
8469
0
                const int iYBlock =
8470
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
8471
0
                const int iXBlock =
8472
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
8473
8474
0
                GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8475
0
                if (poBlock == nullptr)
8476
0
                    return CE_Failure;
8477
8478
0
                void *const pData = poBlock->GetDataRef();
8479
8480
0
                int nXCheck = 0, nYCheck = 0;
8481
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8482
8483
0
                ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8484
8485
0
                poBlock->DropLock();
8486
8487
0
                if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
8488
0
                    nMax == 255)
8489
0
                    break;
8490
0
            }
8491
0
        }
8492
0
        else
8493
0
        {
8494
0
            const GIntBig nTotalBlocks =
8495
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8496
0
            if (!ComputeMinMaxGenericIterBlocks(
8497
0
                    this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8498
0
                    nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8499
0
            {
8500
0
                return CE_Failure;
8501
0
            }
8502
0
        }
8503
0
    }
8504
8505
0
    if (bUseOptimizedPath)
8506
0
    {
8507
0
        if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
8508
0
        {
8509
0
            dfMin = nMin;
8510
0
            dfMax = nMax;
8511
0
        }
8512
0
        else if (eDataType == GDT_Int16)
8513
0
        {
8514
0
            dfMin = nMinInt16;
8515
0
            dfMax = nMaxInt16;
8516
0
        }
8517
0
    }
8518
8519
0
    if (dfMin > dfMax)
8520
0
    {
8521
0
        adfMinMax[0] = 0;
8522
0
        adfMinMax[1] = 0;
8523
0
        ReportError(
8524
0
            CE_Failure, CPLE_AppDefined,
8525
0
            "Failed to compute min/max, no valid pixels found in sampling.");
8526
0
        return CE_Failure;
8527
0
    }
8528
8529
0
    adfMinMax[0] = dfMin;
8530
0
    adfMinMax[1] = dfMax;
8531
8532
0
    return CE_None;
8533
0
}
8534
8535
/************************************************************************/
8536
/*                      GDALComputeRasterMinMax()                       */
8537
/************************************************************************/
8538
8539
/**
8540
 * \brief Compute the min/max values for a band.
8541
 *
8542
 * @see GDALRasterBand::ComputeRasterMinMax()
8543
 *
8544
 * @note Prior to GDAL 3.6, this function returned void
8545
 */
8546
8547
CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8548
                                           double adfMinMax[2])
8549
8550
0
{
8551
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8552
8553
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8554
0
    return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8555
0
}
8556
8557
/************************************************************************/
8558
/*                    ComputeRasterMinMaxLocation()                     */
8559
/************************************************************************/
8560
8561
/**
8562
 * \brief Compute the min/max values for a band, and their location.
8563
 *
8564
 * Pixels whose value matches the nodata value or are masked by the mask
8565
 * band are ignored.
8566
 *
8567
 * If the minimum or maximum value is hit in several locations, it is not
8568
 * specified which one will be returned.
8569
 *
8570
 * @param[out] pdfMin Pointer to the minimum value.
8571
 * @param[out] pdfMax Pointer to the maximum value.
8572
 * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8573
 * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8574
 * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8575
 * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8576
 *
8577
 * @return CE_None in case of success, CE_Warning if there are no valid values,
8578
 *         CE_Failure in case of error.
8579
 *
8580
 * @since GDAL 3.11
8581
 */
8582
8583
CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8584
                                                   double *pdfMax, int *pnMinX,
8585
                                                   int *pnMinY, int *pnMaxX,
8586
                                                   int *pnMaxY)
8587
0
{
8588
0
    int nMinX = -1;
8589
0
    int nMinY = -1;
8590
0
    int nMaxX = -1;
8591
0
    int nMaxY = -1;
8592
0
    double dfMin = std::numeric_limits<double>::infinity();
8593
0
    double dfMax = -std::numeric_limits<double>::infinity();
8594
0
    if (pdfMin)
8595
0
        *pdfMin = dfMin;
8596
0
    if (pdfMax)
8597
0
        *pdfMax = dfMax;
8598
0
    if (pnMinX)
8599
0
        *pnMinX = nMinX;
8600
0
    if (pnMinY)
8601
0
        *pnMinY = nMinY;
8602
0
    if (pnMaxX)
8603
0
        *pnMaxX = nMaxX;
8604
0
    if (pnMaxY)
8605
0
        *pnMaxY = nMaxY;
8606
8607
0
    if (GDALDataTypeIsComplex(eDataType))
8608
0
    {
8609
0
        CPLError(CE_Failure, CPLE_NotSupported,
8610
0
                 "Complex data type not supported");
8611
0
        return CE_Failure;
8612
0
    }
8613
8614
0
    if (!InitBlockInfo())
8615
0
        return CE_Failure;
8616
8617
0
    GDALNoDataValues sNoDataValues(this, eDataType);
8618
0
    GDALRasterBand *poMaskBand = nullptr;
8619
0
    if (!sNoDataValues.bGotNoDataValue)
8620
0
    {
8621
0
        const int l_nMaskFlags = GetMaskFlags();
8622
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
8623
0
            GetColorInterpretation() != GCI_AlphaBand)
8624
0
        {
8625
0
            poMaskBand = GetMaskBand();
8626
0
        }
8627
0
    }
8628
8629
0
    bool bSignedByte = false;
8630
0
    if (eDataType == GDT_Byte)
8631
0
    {
8632
0
        EnablePixelTypeSignedByteWarning(false);
8633
0
        const char *pszPixelType =
8634
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8635
0
        EnablePixelTypeSignedByteWarning(true);
8636
0
        bSignedByte =
8637
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8638
0
    }
8639
8640
0
    GByte *pabyMaskData = nullptr;
8641
0
    if (poMaskBand)
8642
0
    {
8643
0
        pabyMaskData =
8644
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8645
0
        if (!pabyMaskData)
8646
0
        {
8647
0
            return CE_Failure;
8648
0
        }
8649
0
    }
8650
8651
0
    const GIntBig nTotalBlocks =
8652
0
        static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8653
0
    bool bNeedsMin = pdfMin || pnMinX || pnMinY;
8654
0
    bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
8655
0
    for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
8656
0
    {
8657
0
        const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
8658
0
        const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
8659
8660
0
        int nXCheck = 0, nYCheck = 0;
8661
0
        GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8662
8663
0
        if (poMaskBand &&
8664
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8665
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
8666
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
8667
0
                                 nBlockXSize, nullptr) != CE_None)
8668
0
        {
8669
0
            CPLFree(pabyMaskData);
8670
0
            return CE_Failure;
8671
0
        }
8672
8673
0
        GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8674
0
        if (poBlock == nullptr)
8675
0
        {
8676
0
            CPLFree(pabyMaskData);
8677
0
            return CE_Failure;
8678
0
        }
8679
8680
0
        void *const pData = poBlock->GetDataRef();
8681
8682
0
        if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
8683
0
        {
8684
0
            for (int iY = 0; iY < nYCheck; ++iY)
8685
0
            {
8686
0
                for (int iX = 0; iX < nXCheck; ++iX)
8687
0
                {
8688
0
                    const GPtrDiff_t iOffset =
8689
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8690
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
8691
0
                        continue;
8692
0
                    bool bValid = true;
8693
0
                    double dfValue =
8694
0
                        GetPixelValue(eDataType, bSignedByte, pData, iOffset,
8695
0
                                      sNoDataValues, bValid);
8696
0
                    if (!bValid)
8697
0
                        continue;
8698
0
                    if (dfValue < dfMin)
8699
0
                    {
8700
0
                        dfMin = dfValue;
8701
0
                        nMinX = iXBlock * nBlockXSize + iX;
8702
0
                        nMinY = iYBlock * nBlockYSize + iY;
8703
0
                    }
8704
0
                    if (dfValue > dfMax)
8705
0
                    {
8706
0
                        dfMax = dfValue;
8707
0
                        nMaxX = iXBlock * nBlockXSize + iX;
8708
0
                        nMaxY = iYBlock * nBlockYSize + iY;
8709
0
                    }
8710
0
                }
8711
0
            }
8712
0
        }
8713
0
        else
8714
0
        {
8715
0
            size_t pos_min = 0;
8716
0
            size_t pos_max = 0;
8717
0
            const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
8718
0
            if (bNeedsMin && bNeedsMax)
8719
0
            {
8720
0
                std::tie(pos_min, pos_max) = gdal::minmax_element(
8721
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8722
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
8723
0
                    sNoDataValues.dfNoDataValue);
8724
0
            }
8725
0
            else if (bNeedsMin)
8726
0
            {
8727
0
                pos_min = gdal::min_element(
8728
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8729
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
8730
0
                    sNoDataValues.dfNoDataValue);
8731
0
            }
8732
0
            else if (bNeedsMax)
8733
0
            {
8734
0
                pos_max = gdal::max_element(
8735
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8736
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
8737
0
                    sNoDataValues.dfNoDataValue);
8738
0
            }
8739
8740
0
            if (bNeedsMin)
8741
0
            {
8742
0
                const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
8743
0
                const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
8744
0
                bool bValid = true;
8745
0
                const double dfMinValueBlock =
8746
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_min,
8747
0
                                  sNoDataValues, bValid);
8748
0
                if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
8749
0
                {
8750
0
                    dfMin = dfMinValueBlock;
8751
0
                    nMinX = iXBlock * nBlockXSize + nMinXBlock;
8752
0
                    nMinY = iYBlock * nBlockYSize + nMinYBlock;
8753
0
                }
8754
0
            }
8755
8756
0
            if (bNeedsMax)
8757
0
            {
8758
0
                const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
8759
0
                const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
8760
0
                bool bValid = true;
8761
0
                const double dfMaxValueBlock =
8762
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_max,
8763
0
                                  sNoDataValues, bValid);
8764
0
                if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
8765
0
                {
8766
0
                    dfMax = dfMaxValueBlock;
8767
0
                    nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
8768
0
                    nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
8769
0
                }
8770
0
            }
8771
0
        }
8772
8773
0
        poBlock->DropLock();
8774
8775
0
        if (eDataType == GDT_Byte)
8776
0
        {
8777
0
            if (bNeedsMin && dfMin == 0)
8778
0
            {
8779
0
                bNeedsMin = false;
8780
0
            }
8781
0
            if (bNeedsMax && dfMax == 255)
8782
0
            {
8783
0
                bNeedsMax = false;
8784
0
            }
8785
0
            if (!bNeedsMin && !bNeedsMax)
8786
0
            {
8787
0
                break;
8788
0
            }
8789
0
        }
8790
0
    }
8791
8792
0
    CPLFree(pabyMaskData);
8793
8794
0
    if (pdfMin)
8795
0
        *pdfMin = dfMin;
8796
0
    if (pdfMax)
8797
0
        *pdfMax = dfMax;
8798
0
    if (pnMinX)
8799
0
        *pnMinX = nMinX;
8800
0
    if (pnMinY)
8801
0
        *pnMinY = nMinY;
8802
0
    if (pnMaxX)
8803
0
        *pnMaxX = nMaxX;
8804
0
    if (pnMaxY)
8805
0
        *pnMaxY = nMaxY;
8806
0
    return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
8807
0
                                                                  : CE_None;
8808
0
}
8809
8810
/************************************************************************/
8811
/*                    GDALComputeRasterMinMaxLocation()                 */
8812
/************************************************************************/
8813
8814
/**
8815
 * \brief Compute the min/max values for a band, and their location.
8816
 *
8817
 * @see GDALRasterBand::ComputeRasterMinMax()
8818
 * @since GDAL 3.11
8819
 */
8820
8821
CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
8822
                                       double *pdfMax, int *pnMinX, int *pnMinY,
8823
                                       int *pnMaxX, int *pnMaxY)
8824
8825
0
{
8826
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
8827
8828
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8829
0
    return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
8830
0
                                               pnMaxX, pnMaxY);
8831
0
}
8832
8833
/************************************************************************/
8834
/*                        SetDefaultHistogram()                         */
8835
/************************************************************************/
8836
8837
/* FIXME : add proper documentation */
8838
/**
8839
 * \brief Set default histogram.
8840
 *
8841
 * This method is the same as the C function GDALSetDefaultHistogram() and
8842
 * GDALSetDefaultHistogramEx()
8843
 */
8844
CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
8845
                                           double /* dfMax */,
8846
                                           int /* nBuckets */,
8847
                                           GUIntBig * /* panHistogram */)
8848
8849
0
{
8850
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8851
0
        ReportError(CE_Failure, CPLE_NotSupported,
8852
0
                    "SetDefaultHistogram() not implemented for this format.");
8853
8854
0
    return CE_Failure;
8855
0
}
8856
8857
/************************************************************************/
8858
/*                      GDALSetDefaultHistogram()                       */
8859
/************************************************************************/
8860
8861
/**
8862
 * \brief Set default histogram.
8863
 *
8864
 * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8865
 * 2 billion.
8866
 *
8867
 * @see GDALRasterBand::SetDefaultHistogram()
8868
 * @see GDALSetRasterHistogramEx()
8869
 */
8870
8871
CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8872
                                           double dfMax, int nBuckets,
8873
                                           int *panHistogram)
8874
8875
0
{
8876
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8877
8878
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8879
8880
0
    GUIntBig *panHistogramTemp =
8881
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8882
0
    if (panHistogramTemp == nullptr)
8883
0
    {
8884
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8885
0
                            "Out of memory in GDALSetDefaultHistogram().");
8886
0
        return CE_Failure;
8887
0
    }
8888
8889
0
    for (int i = 0; i < nBuckets; ++i)
8890
0
    {
8891
0
        panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8892
0
    }
8893
8894
0
    const CPLErr eErr =
8895
0
        poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8896
8897
0
    CPLFree(panHistogramTemp);
8898
8899
0
    return eErr;
8900
0
}
8901
8902
/************************************************************************/
8903
/*                     GDALSetDefaultHistogramEx()                      */
8904
/************************************************************************/
8905
8906
/**
8907
 * \brief Set default histogram.
8908
 *
8909
 * @see GDALRasterBand::SetDefaultHistogram()
8910
 *
8911
 */
8912
8913
CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8914
                                             double dfMin, double dfMax,
8915
                                             int nBuckets,
8916
                                             GUIntBig *panHistogram)
8917
8918
0
{
8919
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8920
8921
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8922
0
    return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8923
0
}
8924
8925
/************************************************************************/
8926
/*                           GetDefaultRAT()                            */
8927
/************************************************************************/
8928
8929
/**
8930
 * \brief Fetch default Raster Attribute Table.
8931
 *
8932
 * A RAT will be returned if there is a default one associated with the
8933
 * band, otherwise NULL is returned.  The returned RAT is owned by the
8934
 * band and should not be deleted by the application.
8935
 *
8936
 * This method is the same as the C function GDALGetDefaultRAT().
8937
 *
8938
 * @return NULL, or a pointer to an internal RAT owned by the band.
8939
 */
8940
8941
GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8942
8943
0
{
8944
0
    return nullptr;
8945
0
}
8946
8947
/************************************************************************/
8948
/*                         GDALGetDefaultRAT()                          */
8949
/************************************************************************/
8950
8951
/**
8952
 * \brief Fetch default Raster Attribute Table.
8953
 *
8954
 * @see GDALRasterBand::GetDefaultRAT()
8955
 */
8956
8957
GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8958
8959
0
{
8960
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8961
8962
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8963
0
    return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8964
0
}
8965
8966
/************************************************************************/
8967
/*                           SetDefaultRAT()                            */
8968
/************************************************************************/
8969
8970
/**
8971
 * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8972
 * \brief Set default Raster Attribute Table.
8973
 *
8974
 * Associates a default RAT with the band.  If not implemented for the
8975
 * format a CPLE_NotSupported error will be issued.  If successful a copy
8976
 * of the RAT is made, the original remains owned by the caller.
8977
 *
8978
 * This method is the same as the C function GDALSetDefaultRAT().
8979
 *
8980
 * @param poRAT the RAT to assign to the band.
8981
 *
8982
 * @return CE_None on success or CE_Failure if unsupported or otherwise
8983
 * failing.
8984
 */
8985
8986
/**/
8987
/**/
8988
8989
CPLErr
8990
GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8991
0
{
8992
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8993
0
    {
8994
0
        CPLPushErrorHandler(CPLQuietErrorHandler);
8995
0
        ReportError(CE_Failure, CPLE_NotSupported,
8996
0
                    "SetDefaultRAT() not implemented for this format.");
8997
0
        CPLPopErrorHandler();
8998
0
    }
8999
0
    return CE_Failure;
9000
0
}
9001
9002
/************************************************************************/
9003
/*                         GDALSetDefaultRAT()                          */
9004
/************************************************************************/
9005
9006
/**
9007
 * \brief Set default Raster Attribute Table.
9008
 *
9009
 * @see GDALRasterBand::GDALSetDefaultRAT()
9010
 */
9011
9012
CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9013
                                     GDALRasterAttributeTableH hRAT)
9014
9015
0
{
9016
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9017
9018
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9019
9020
0
    return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9021
0
}
9022
9023
/************************************************************************/
9024
/*                            GetMaskBand()                             */
9025
/************************************************************************/
9026
9027
/**
9028
 * \brief Return the mask band associated with the band.
9029
 *
9030
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
9031
 * that returns one of four default implementations :
9032
 * <ul>
9033
 * <li>If a corresponding .msk file exists it will be used for the mask band.
9034
 * </li>
9035
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9036
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9037
 * GMF_NODATA | GMF_PER_DATASET.
9038
 * </li>
9039
 * <li>If the band has a nodata value set, an instance of the new
9040
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9041
 * GMF_NODATA.
9042
 * </li>
9043
 * <li>If there is no nodata value, but the dataset has an alpha band that seems
9044
 * to apply to this band (specific rules yet to be determined) and that is of
9045
 * type GDT_Byte then that alpha band will be returned, and the flags
9046
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9047
 * </li>
9048
 * <li>If neither of the above apply, an instance of the new
9049
 * GDALAllValidRasterBand class will be returned that has 255 values for all
9050
 * pixels. The null flags will return GMF_ALL_VALID.
9051
 * </li>
9052
 * </ul>
9053
 *
9054
 * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9055
 * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9056
 *
9057
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9058
 * dataset, with the same name as the main dataset and suffixed with .msk,
9059
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9060
 * main dataset.
9061
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9062
 * level, where xx matches the band number of a band of the main dataset. The
9063
 * value of those items is a combination of the flags GMF_ALL_VALID,
9064
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9065
 * a band, then the other rules explained above will be used to generate a
9066
 * on-the-fly mask band.
9067
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9068
 *
9069
 * This method is the same as the C function GDALGetMaskBand().
9070
 *
9071
 * @return a valid mask band.
9072
 *
9073
 *
9074
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9075
 *
9076
 */
9077
GDALRasterBand *GDALRasterBand::GetMaskBand()
9078
9079
0
{
9080
0
    const auto HasNoData = [this]()
9081
0
    {
9082
0
        int bHaveNoDataRaw = FALSE;
9083
0
        bool bHaveNoData = false;
9084
0
        if (eDataType == GDT_Int64)
9085
0
        {
9086
0
            CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
9087
0
            bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9088
0
        }
9089
0
        else if (eDataType == GDT_UInt64)
9090
0
        {
9091
0
            CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9092
0
            bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9093
0
        }
9094
0
        else
9095
0
        {
9096
0
            const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
9097
0
            if (bHaveNoDataRaw &&
9098
0
                GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9099
0
            {
9100
0
                bHaveNoData = true;
9101
0
            }
9102
0
        }
9103
0
        return bHaveNoData;
9104
0
    };
9105
9106
0
    if (poMask != nullptr)
9107
0
    {
9108
0
        if (poMask.IsOwned())
9109
0
        {
9110
0
            if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9111
0
            {
9112
0
                if (HasNoData())
9113
0
                {
9114
0
                    InvalidateMaskBand();
9115
0
                }
9116
0
            }
9117
0
            else if (auto poNoDataMaskBand =
9118
0
                         dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9119
0
            {
9120
0
                int bHaveNoDataRaw = FALSE;
9121
0
                bool bIsSame = false;
9122
0
                if (eDataType == GDT_Int64)
9123
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9124
0
                                  GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9125
0
                              bHaveNoDataRaw;
9126
0
                else if (eDataType == GDT_UInt64)
9127
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9128
0
                                  GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9129
0
                              bHaveNoDataRaw;
9130
0
                else
9131
0
                {
9132
0
                    const double dfNoDataValue =
9133
0
                        GetNoDataValue(&bHaveNoDataRaw);
9134
0
                    if (bHaveNoDataRaw)
9135
0
                    {
9136
0
                        bIsSame =
9137
0
                            std::isnan(dfNoDataValue)
9138
0
                                ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9139
0
                                : poNoDataMaskBand->m_dfNoDataValue ==
9140
0
                                      dfNoDataValue;
9141
0
                    }
9142
0
                }
9143
0
                if (!bIsSame)
9144
0
                    InvalidateMaskBand();
9145
0
            }
9146
0
        }
9147
9148
0
        if (poMask)
9149
0
            return poMask.get();
9150
0
    }
9151
9152
    /* -------------------------------------------------------------------- */
9153
    /*      Check for a mask in a .msk file.                                */
9154
    /* -------------------------------------------------------------------- */
9155
0
    if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9156
0
    {
9157
0
        poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9158
0
        if (poMask != nullptr)
9159
0
        {
9160
0
            nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9161
0
            return poMask.get();
9162
0
        }
9163
0
    }
9164
9165
    /* -------------------------------------------------------------------- */
9166
    /*      Check for NODATA_VALUES metadata.                               */
9167
    /* -------------------------------------------------------------------- */
9168
0
    if (poDS != nullptr)
9169
0
    {
9170
0
        const char *pszGDALNoDataValues =
9171
0
            poDS->GetMetadataItem("NODATA_VALUES");
9172
0
        if (pszGDALNoDataValues != nullptr)
9173
0
        {
9174
0
            char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9175
0
                pszGDALNoDataValues, " ", FALSE, FALSE);
9176
9177
            // Make sure we have as many values as bands.
9178
0
            if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9179
0
                poDS->GetRasterCount() != 0)
9180
0
            {
9181
                // Make sure that all bands have the same data type
9182
                // This is clearly not a fundamental condition, just a
9183
                // condition to make implementation easier.
9184
0
                GDALDataType eDT = GDT_Unknown;
9185
0
                int i = 0;  // Used after for.
9186
0
                for (; i < poDS->GetRasterCount(); ++i)
9187
0
                {
9188
0
                    if (i == 0)
9189
0
                        eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9190
0
                    else if (eDT !=
9191
0
                             poDS->GetRasterBand(i + 1)->GetRasterDataType())
9192
0
                    {
9193
0
                        break;
9194
0
                    }
9195
0
                }
9196
0
                if (i == poDS->GetRasterCount())
9197
0
                {
9198
0
                    nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9199
0
                    try
9200
0
                    {
9201
0
                        poMask.reset(
9202
0
                            std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9203
0
                    }
9204
0
                    catch (const std::bad_alloc &)
9205
0
                    {
9206
0
                        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9207
0
                        poMask.reset();
9208
0
                    }
9209
0
                    CSLDestroy(papszGDALNoDataValues);
9210
0
                    return poMask.get();
9211
0
                }
9212
0
                else
9213
0
                {
9214
0
                    ReportError(CE_Warning, CPLE_AppDefined,
9215
0
                                "All bands should have the same type in "
9216
0
                                "order the NODATA_VALUES metadata item "
9217
0
                                "to be used as a mask.");
9218
0
                }
9219
0
            }
9220
0
            else
9221
0
            {
9222
0
                ReportError(
9223
0
                    CE_Warning, CPLE_AppDefined,
9224
0
                    "NODATA_VALUES metadata item doesn't have the same number "
9225
0
                    "of values as the number of bands.  "
9226
0
                    "Ignoring it for mask.");
9227
0
            }
9228
9229
0
            CSLDestroy(papszGDALNoDataValues);
9230
0
        }
9231
0
    }
9232
9233
    /* -------------------------------------------------------------------- */
9234
    /*      Check for nodata case.                                          */
9235
    /* -------------------------------------------------------------------- */
9236
0
    if (HasNoData())
9237
0
    {
9238
0
        nMaskFlags = GMF_NODATA;
9239
0
        try
9240
0
        {
9241
0
            poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9242
0
        }
9243
0
        catch (const std::bad_alloc &)
9244
0
        {
9245
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9246
0
            poMask.reset();
9247
0
        }
9248
0
        return poMask.get();
9249
0
    }
9250
9251
    /* -------------------------------------------------------------------- */
9252
    /*      Check for alpha case.                                           */
9253
    /* -------------------------------------------------------------------- */
9254
0
    if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9255
0
        this == poDS->GetRasterBand(1) &&
9256
0
        poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9257
0
    {
9258
0
        if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
9259
0
        {
9260
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9261
0
            poMask.resetNotOwned(poDS->GetRasterBand(2));
9262
0
            return poMask.get();
9263
0
        }
9264
0
        else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9265
0
        {
9266
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9267
0
            try
9268
0
            {
9269
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9270
0
                    poDS->GetRasterBand(2)));
9271
0
            }
9272
0
            catch (const std::bad_alloc &)
9273
0
            {
9274
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9275
0
                poMask.reset();
9276
0
            }
9277
0
            return poMask.get();
9278
0
        }
9279
0
    }
9280
9281
0
    if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9282
0
        (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9283
0
         this == poDS->GetRasterBand(3)) &&
9284
0
        poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9285
0
    {
9286
0
        if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
9287
0
        {
9288
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9289
0
            poMask.resetNotOwned(poDS->GetRasterBand(4));
9290
0
            return poMask.get();
9291
0
        }
9292
0
        else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9293
0
        {
9294
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9295
0
            try
9296
0
            {
9297
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9298
0
                    poDS->GetRasterBand(4)));
9299
0
            }
9300
0
            catch (const std::bad_alloc &)
9301
0
            {
9302
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9303
0
                poMask.reset();
9304
0
            }
9305
0
            return poMask.get();
9306
0
        }
9307
0
    }
9308
9309
    /* -------------------------------------------------------------------- */
9310
    /*      Fallback to all valid case.                                     */
9311
    /* -------------------------------------------------------------------- */
9312
0
    nMaskFlags = GMF_ALL_VALID;
9313
0
    try
9314
0
    {
9315
0
        poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9316
0
    }
9317
0
    catch (const std::bad_alloc &)
9318
0
    {
9319
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9320
0
        poMask.reset();
9321
0
    }
9322
9323
0
    return poMask.get();
9324
0
}
9325
9326
/************************************************************************/
9327
/*                          GDALGetMaskBand()                           */
9328
/************************************************************************/
9329
9330
/**
9331
 * \brief Return the mask band associated with the band.
9332
 *
9333
 * @see GDALRasterBand::GetMaskBand()
9334
 */
9335
9336
GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9337
9338
0
{
9339
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9340
9341
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9342
0
    return poBand->GetMaskBand();
9343
0
}
9344
9345
/************************************************************************/
9346
/*                            GetMaskFlags()                            */
9347
/************************************************************************/
9348
9349
/**
9350
 * \brief Return the status flags of the mask band associated with the band.
9351
 *
9352
 * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9353
 * the following available definitions that may be extended in the future:
9354
 * <ul>
9355
 * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9356
 * 255. When used this will normally be the only flag set.
9357
 * </li>
9358
 * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9359
 * dataset.
9360
 * </li>
9361
 * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9362
 * and may have values other than 0 and 255.
9363
 * </li>
9364
 * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9365
 * nodata values. (mutually exclusive of GMF_ALPHA)
9366
 * </li>
9367
 * </ul>
9368
 *
9369
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
9370
 * that returns one of four default implementations:
9371
 * <ul>
9372
 * <li>If a corresponding .msk file exists it will be used for the mask band.
9373
 * </li>
9374
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9375
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9376
 * GMF_NODATA | GMF_PER_DATASET.
9377
 * </li>
9378
 * <li>If the band has a nodata value set, an instance of the new
9379
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9380
 * GMF_NODATA.
9381
 * </li>
9382
 * <li>If there is no nodata value, but the dataset has an alpha band that
9383
 * seems to apply to this band (specific rules yet to be determined) and that is
9384
 * of type GDT_Byte then that alpha band will be returned, and the flags
9385
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9386
 * </li>
9387
 * <li>If neither of the above apply, an instance of the new
9388
 * GDALAllValidRasterBand class will be returned that has 255 values for all
9389
 * pixels. The null flags will return GMF_ALL_VALID.
9390
 * </li>
9391
 * </ul>
9392
 *
9393
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9394
 * dataset, with the same name as the main dataset and suffixed with .msk,
9395
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9396
 * main dataset.
9397
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9398
 * level, where xx matches the band number of a band of the main dataset. The
9399
 * value of those items is a combination of the flags GMF_ALL_VALID,
9400
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9401
 * a band, then the other rules explained above will be used to generate a
9402
 * on-the-fly mask band.
9403
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9404
 *
9405
 * This method is the same as the C function GDALGetMaskFlags().
9406
 *
9407
 *
9408
 * @return a valid mask band.
9409
 *
9410
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9411
 *
9412
 */
9413
int GDALRasterBand::GetMaskFlags()
9414
9415
0
{
9416
    // If we don't have a band yet, force this now so that the masks value
9417
    // will be initialized.
9418
9419
0
    if (poMask == nullptr)
9420
0
        GetMaskBand();
9421
9422
0
    return nMaskFlags;
9423
0
}
9424
9425
/************************************************************************/
9426
/*                          GDALGetMaskFlags()                          */
9427
/************************************************************************/
9428
9429
/**
9430
 * \brief Return the status flags of the mask band associated with the band.
9431
 *
9432
 * @see GDALRasterBand::GetMaskFlags()
9433
 */
9434
9435
int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9436
9437
0
{
9438
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9439
9440
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9441
0
    return poBand->GetMaskFlags();
9442
0
}
9443
9444
/************************************************************************/
9445
/*                         InvalidateMaskBand()                         */
9446
/************************************************************************/
9447
9448
//! @cond Doxygen_Suppress
9449
void GDALRasterBand::InvalidateMaskBand()
9450
0
{
9451
0
    poMask.reset();
9452
0
    nMaskFlags = 0;
9453
0
}
9454
9455
//! @endcond
9456
9457
/************************************************************************/
9458
/*                           CreateMaskBand()                           */
9459
/************************************************************************/
9460
9461
/**
9462
 * \brief Adds a mask band to the current band
9463
 *
9464
 * The default implementation of the CreateMaskBand() method is implemented
9465
 * based on similar rules to the .ovr handling implemented using the
9466
 * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9467
 * be created with the same basename as the original file, and it will have
9468
 * as many bands as the original image (or just one for GMF_PER_DATASET).
9469
 * The mask images will be deflate compressed tiled images with the same
9470
 * block size as the original image if possible.
9471
 * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9472
 * level, where xx matches the band number of a band of the main dataset. The
9473
 * value of those items will be the one of the nFlagsIn parameter.
9474
 *
9475
 * Note that if you got a mask band with a previous call to GetMaskBand(),
9476
 * it might be invalidated by CreateMaskBand(). So you have to call
9477
 * GetMaskBand() again.
9478
 *
9479
 * This method is the same as the C function GDALCreateMaskBand().
9480
 *
9481
 *
9482
 * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9483
 *
9484
 * @return CE_None on success or CE_Failure on an error.
9485
 *
9486
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9487
 * @see GDALDataset::CreateMaskBand()
9488
 *
9489
 */
9490
9491
CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9492
9493
0
{
9494
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9495
0
    {
9496
0
        const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9497
0
        if (eErr != CE_None)
9498
0
            return eErr;
9499
9500
0
        InvalidateMaskBand();
9501
9502
0
        return CE_None;
9503
0
    }
9504
9505
0
    ReportError(CE_Failure, CPLE_NotSupported,
9506
0
                "CreateMaskBand() not supported for this band.");
9507
9508
0
    return CE_Failure;
9509
0
}
9510
9511
/************************************************************************/
9512
/*                         GDALCreateMaskBand()                         */
9513
/************************************************************************/
9514
9515
/**
9516
 * \brief Adds a mask band to the current band
9517
 *
9518
 * @see GDALRasterBand::CreateMaskBand()
9519
 */
9520
9521
CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9522
9523
0
{
9524
0
    VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9525
9526
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9527
0
    return poBand->CreateMaskBand(nFlags);
9528
0
}
9529
9530
/************************************************************************/
9531
/*                            IsMaskBand()                              */
9532
/************************************************************************/
9533
9534
/**
9535
 * \brief Returns whether a band is a mask band.
9536
 *
9537
 * Mask band must be understood in the broad term: it can be a per-dataset
9538
 * mask band, an alpha band, or an implicit mask band.
9539
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9540
 *
9541
 * This method is the same as the C function GDALIsMaskBand().
9542
 *
9543
 * @return true if the band is a mask band.
9544
 *
9545
 * @see GDALDataset::CreateMaskBand()
9546
 *
9547
 * @since GDAL 3.5.0
9548
 *
9549
 */
9550
9551
bool GDALRasterBand::IsMaskBand() const
9552
0
{
9553
    // The GeoTIFF driver, among others, override this method to
9554
    // also handle external .msk bands.
9555
0
    return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9556
0
           GCI_AlphaBand;
9557
0
}
9558
9559
/************************************************************************/
9560
/*                            GDALIsMaskBand()                          */
9561
/************************************************************************/
9562
9563
/**
9564
 * \brief Returns whether a band is a mask band.
9565
 *
9566
 * Mask band must be understood in the broad term: it can be a per-dataset
9567
 * mask band, an alpha band, or an implicit mask band.
9568
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9569
 *
9570
 * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9571
 *
9572
 * @return true if the band is a mask band.
9573
 *
9574
 * @see GDALRasterBand::IsMaskBand()
9575
 *
9576
 * @since GDAL 3.5.0
9577
 *
9578
 */
9579
9580
bool GDALIsMaskBand(GDALRasterBandH hBand)
9581
9582
0
{
9583
0
    VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9584
9585
0
    const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9586
0
    return poBand->IsMaskBand();
9587
0
}
9588
9589
/************************************************************************/
9590
/*                         GetMaskValueRange()                          */
9591
/************************************************************************/
9592
9593
/**
9594
 * \brief Returns the range of values that a mask band can take.
9595
 *
9596
 * @return the range of values that a mask band can take.
9597
 *
9598
 * @since GDAL 3.5.0
9599
 *
9600
 */
9601
9602
GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
9603
0
{
9604
0
    return GMVR_UNKNOWN;
9605
0
}
9606
9607
/************************************************************************/
9608
/*                    GetIndexColorTranslationTo()                      */
9609
/************************************************************************/
9610
9611
/**
9612
 * \brief Compute translation table for color tables.
9613
 *
9614
 * When the raster band has a palette index, it may be useful to compute
9615
 * the "translation" of this palette to the palette of another band.
9616
 * The translation tries to do exact matching first, and then approximate
9617
 * matching if no exact matching is possible.
9618
 * This method returns a table such that table[i] = j where i is an index
9619
 * of the 'this' rasterband and j the corresponding index for the reference
9620
 * rasterband.
9621
 *
9622
 * This method is thought as internal to GDAL and is used for drivers
9623
 * like RPFTOC.
9624
 *
9625
 * The implementation only supports 1-byte palette rasterbands.
9626
 *
9627
 * @param poReferenceBand the raster band
9628
 * @param pTranslationTable an already allocated translation table (at least 256
9629
 * bytes), or NULL to let the method allocate it
9630
 * @param pApproximateMatching a pointer to a flag that is set if the matching
9631
 *                              is approximate. May be NULL.
9632
 *
9633
 * @return a translation table if the two bands are palette index and that they
9634
 * do not match or NULL in other cases. The table must be freed with CPLFree if
9635
 * NULL was passed for pTranslationTable.
9636
 */
9637
9638
unsigned char *
9639
GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
9640
                                           unsigned char *pTranslationTable,
9641
                                           int *pApproximateMatching)
9642
0
{
9643
0
    if (poReferenceBand == nullptr)
9644
0
        return nullptr;
9645
9646
    // cppcheck-suppress knownConditionTrueFalse
9647
0
    if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
9648
        // cppcheck-suppress knownConditionTrueFalse
9649
0
        GetColorInterpretation() == GCI_PaletteIndex &&
9650
0
        poReferenceBand->GetRasterDataType() == GDT_Byte &&
9651
0
        GetRasterDataType() == GDT_Byte)
9652
0
    {
9653
0
        const GDALColorTable *srcColorTable = GetColorTable();
9654
0
        GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
9655
0
        if (srcColorTable != nullptr && destColorTable != nullptr)
9656
0
        {
9657
0
            const int nEntries = srcColorTable->GetColorEntryCount();
9658
0
            const int nRefEntries = destColorTable->GetColorEntryCount();
9659
9660
0
            int bHasNoDataValueSrc = FALSE;
9661
0
            double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
9662
0
            if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
9663
0
                  dfNoDataValueSrc <= 255 &&
9664
0
                  dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
9665
0
                bHasNoDataValueSrc = FALSE;
9666
0
            const int noDataValueSrc =
9667
0
                bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
9668
9669
0
            int bHasNoDataValueRef = FALSE;
9670
0
            const double dfNoDataValueRef =
9671
0
                poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
9672
0
            if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
9673
0
                  dfNoDataValueRef <= 255 &&
9674
0
                  dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
9675
0
                bHasNoDataValueRef = FALSE;
9676
0
            const int noDataValueRef =
9677
0
                bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
9678
9679
0
            bool samePalette = false;
9680
9681
0
            if (pApproximateMatching)
9682
0
                *pApproximateMatching = FALSE;
9683
9684
0
            if (nEntries == nRefEntries &&
9685
0
                bHasNoDataValueSrc == bHasNoDataValueRef &&
9686
0
                (bHasNoDataValueSrc == FALSE ||
9687
0
                 noDataValueSrc == noDataValueRef))
9688
0
            {
9689
0
                samePalette = true;
9690
0
                for (int i = 0; i < nEntries; ++i)
9691
0
                {
9692
0
                    if (noDataValueSrc == i)
9693
0
                        continue;
9694
0
                    const GDALColorEntry *entry =
9695
0
                        srcColorTable->GetColorEntry(i);
9696
0
                    const GDALColorEntry *entryRef =
9697
0
                        destColorTable->GetColorEntry(i);
9698
0
                    if (entry->c1 != entryRef->c1 ||
9699
0
                        entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
9700
0
                    {
9701
0
                        samePalette = false;
9702
0
                    }
9703
0
                }
9704
0
            }
9705
9706
0
            if (!samePalette)
9707
0
            {
9708
0
                if (pTranslationTable == nullptr)
9709
0
                {
9710
0
                    pTranslationTable = static_cast<unsigned char *>(
9711
0
                        VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
9712
0
                    if (pTranslationTable == nullptr)
9713
0
                        return nullptr;
9714
0
                }
9715
9716
                // Trying to remap the product palette on the subdataset
9717
                // palette.
9718
0
                for (int i = 0; i < nEntries; ++i)
9719
0
                {
9720
0
                    if (bHasNoDataValueSrc && bHasNoDataValueRef &&
9721
0
                        noDataValueSrc == i)
9722
0
                        continue;
9723
0
                    const GDALColorEntry *entry =
9724
0
                        srcColorTable->GetColorEntry(i);
9725
0
                    bool bMatchFound = false;
9726
0
                    for (int j = 0; j < nRefEntries; ++j)
9727
0
                    {
9728
0
                        if (bHasNoDataValueRef && noDataValueRef == j)
9729
0
                            continue;
9730
0
                        const GDALColorEntry *entryRef =
9731
0
                            destColorTable->GetColorEntry(j);
9732
0
                        if (entry->c1 == entryRef->c1 &&
9733
0
                            entry->c2 == entryRef->c2 &&
9734
0
                            entry->c3 == entryRef->c3)
9735
0
                        {
9736
0
                            pTranslationTable[i] =
9737
0
                                static_cast<unsigned char>(j);
9738
0
                            bMatchFound = true;
9739
0
                            break;
9740
0
                        }
9741
0
                    }
9742
0
                    if (!bMatchFound)
9743
0
                    {
9744
                        // No exact match. Looking for closest color now.
9745
0
                        int best_j = 0;
9746
0
                        int best_distance = 0;
9747
0
                        if (pApproximateMatching)
9748
0
                            *pApproximateMatching = TRUE;
9749
0
                        for (int j = 0; j < nRefEntries; ++j)
9750
0
                        {
9751
0
                            const GDALColorEntry *entryRef =
9752
0
                                destColorTable->GetColorEntry(j);
9753
0
                            int distance = (entry->c1 - entryRef->c1) *
9754
0
                                               (entry->c1 - entryRef->c1) +
9755
0
                                           (entry->c2 - entryRef->c2) *
9756
0
                                               (entry->c2 - entryRef->c2) +
9757
0
                                           (entry->c3 - entryRef->c3) *
9758
0
                                               (entry->c3 - entryRef->c3);
9759
0
                            if (j == 0 || distance < best_distance)
9760
0
                            {
9761
0
                                best_j = j;
9762
0
                                best_distance = distance;
9763
0
                            }
9764
0
                        }
9765
0
                        pTranslationTable[i] =
9766
0
                            static_cast<unsigned char>(best_j);
9767
0
                    }
9768
0
                }
9769
0
                if (bHasNoDataValueRef && bHasNoDataValueSrc)
9770
0
                    pTranslationTable[noDataValueSrc] =
9771
0
                        static_cast<unsigned char>(noDataValueRef);
9772
9773
0
                return pTranslationTable;
9774
0
            }
9775
0
        }
9776
0
    }
9777
0
    return nullptr;
9778
0
}
9779
9780
/************************************************************************/
9781
/*                         SetFlushBlockErr()                           */
9782
/************************************************************************/
9783
9784
/**
9785
 * \brief Store that an error occurred while writing a dirty block.
9786
 *
9787
 * This function stores the fact that an error occurred while writing a dirty
9788
 * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
9789
 * flushed when the block cache get full, it is not convenient/possible to
9790
 * report that a dirty block could not be written correctly. This function
9791
 * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
9792
 * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
9793
 * places where the user can easily match the error with the relevant dataset.
9794
 */
9795
9796
void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
9797
0
{
9798
0
    eFlushBlockErr = eErr;
9799
0
}
9800
9801
/************************************************************************/
9802
/*                         IncDirtyBlocks()                             */
9803
/************************************************************************/
9804
9805
/**
9806
 * \brief Increment/decrement the number of dirty blocks
9807
 */
9808
9809
void GDALRasterBand::IncDirtyBlocks(int nInc)
9810
0
{
9811
0
    if (poBandBlockCache)
9812
0
        poBandBlockCache->IncDirtyBlocks(nInc);
9813
0
}
9814
9815
/************************************************************************/
9816
/*                            ReportError()                             */
9817
/************************************************************************/
9818
9819
#ifndef DOXYGEN_XML
9820
/**
9821
 * \brief Emits an error related to a raster band.
9822
 *
9823
 * This function is a wrapper for regular CPLError(). The only difference
9824
 * with CPLError() is that it prepends the error message with the dataset
9825
 * name and the band number.
9826
 *
9827
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
9828
 * @param err_no the error number (CPLE_*) from cpl_error.h.
9829
 * @param fmt a printf() style format string.  Any additional arguments
9830
 * will be treated as arguments to fill in this format in a manner
9831
 * similar to printf().
9832
 *
9833
 */
9834
9835
void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
9836
                                 const char *fmt, ...) const
9837
0
{
9838
0
    va_list args;
9839
9840
0
    va_start(args, fmt);
9841
9842
0
    const char *pszDSName = poDS ? poDS->GetDescription() : "";
9843
0
    pszDSName = CPLGetFilename(pszDSName);
9844
0
    if (pszDSName[0] != '\0')
9845
0
    {
9846
0
        CPLError(eErrClass, err_no, "%s",
9847
0
                 CPLString()
9848
0
                     .Printf("%s, band %d: ", pszDSName, GetBand())
9849
0
                     .append(CPLString().vPrintf(fmt, args))
9850
0
                     .c_str());
9851
0
    }
9852
0
    else
9853
0
    {
9854
0
        CPLErrorV(eErrClass, err_no, fmt, args);
9855
0
    }
9856
9857
0
    va_end(args);
9858
0
}
9859
#endif
9860
9861
/************************************************************************/
9862
/*                           GetVirtualMemAuto()                        */
9863
/************************************************************************/
9864
9865
/** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9866
 *
9867
 * Only supported on Linux and Unix systems with mmap() for now.
9868
 *
9869
 * This method allows creating a virtual memory object for a GDALRasterBand,
9870
 * that exposes the whole image data as a virtual array.
9871
 *
9872
 * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9873
 * specialized implementation, such as for raw files, may also directly use
9874
 * mechanisms of the operating system to create a view of the underlying file
9875
 * into virtual memory ( CPLVirtualMemFileMapNew() )
9876
 *
9877
 * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9878
 * offer a specialized implementation with direct file mapping, provided that
9879
 * some requirements are met :
9880
 *   - for all drivers, the dataset must be backed by a "real" file in the file
9881
 *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9882
 *     must match the native ordering of the CPU.
9883
 *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9884
 * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9885
 * the file in sequential order, and be equally spaced (which is generally the
9886
 * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9887
 * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9888
 *
9889
 * The pointer returned remains valid until CPLVirtualMemFree() is called.
9890
 * CPLVirtualMemFree() must be called before the raster band object is
9891
 * destroyed.
9892
 *
9893
 * If p is such a pointer and base_type the type matching
9894
 * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9895
 * accessed with
9896
 * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9897
 *
9898
 * This method is the same as the C GDALGetVirtualMemAuto() function.
9899
 *
9900
 * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9901
 * read/write the band.
9902
 *
9903
 * @param pnPixelSpace Output parameter giving the byte offset from the start of
9904
 * one pixel value in the buffer to the start of the next pixel value within a
9905
 * scanline.
9906
 *
9907
 * @param pnLineSpace Output parameter giving the byte offset from the start of
9908
 * one scanline in the buffer to the start of the next.
9909
 *
9910
 * @param papszOptions NULL terminated list of options.
9911
 *                     If a specialized implementation exists, defining
9912
 * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9913
 * used. On the contrary, defining
9914
 * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9915
 * being used (thus only allowing efficient implementations to be used). When
9916
 * requiring or falling back to the default implementation, the following
9917
 *                     options are available : CACHE_SIZE (in bytes, defaults to
9918
 * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9919
 * to FALSE)
9920
 *
9921
 * @return a virtual memory object that must be unreferenced by
9922
 * CPLVirtualMemFree(), or NULL in case of failure.
9923
 *
9924
 */
9925
9926
CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9927
                                                 int *pnPixelSpace,
9928
                                                 GIntBig *pnLineSpace,
9929
                                                 char **papszOptions)
9930
0
{
9931
0
    const char *pszImpl = CSLFetchNameValueDef(
9932
0
        papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9933
0
    if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9934
0
        EQUAL(pszImpl, "FALSE"))
9935
0
    {
9936
0
        return nullptr;
9937
0
    }
9938
9939
0
    const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9940
0
    const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9941
0
    if (pnPixelSpace)
9942
0
        *pnPixelSpace = nPixelSpace;
9943
0
    if (pnLineSpace)
9944
0
        *pnLineSpace = nLineSpace;
9945
0
    const size_t nCacheSize =
9946
0
        atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9947
0
    const size_t nPageSizeHint =
9948
0
        atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9949
0
    const bool bSingleThreadUsage = CPLTestBool(
9950
0
        CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9951
0
    return GDALRasterBandGetVirtualMem(
9952
0
        GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9953
0
        nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9954
0
        nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9955
0
        papszOptions);
9956
0
}
9957
9958
/************************************************************************/
9959
/*                         GDALGetVirtualMemAuto()                      */
9960
/************************************************************************/
9961
9962
/**
9963
 * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9964
 *
9965
 * @see GDALRasterBand::GetVirtualMemAuto()
9966
 */
9967
9968
CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9969
                                     int *pnPixelSpace, GIntBig *pnLineSpace,
9970
                                     CSLConstList papszOptions)
9971
0
{
9972
0
    VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9973
9974
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9975
9976
0
    return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9977
0
                                     const_cast<char **>(papszOptions));
9978
0
}
9979
9980
/************************************************************************/
9981
/*                        GDALGetDataCoverageStatus()                   */
9982
/************************************************************************/
9983
9984
/**
9985
 * \brief Get the coverage status of a sub-window of the raster.
9986
 *
9987
 * Returns whether a sub-window of the raster contains only data, only empty
9988
 * blocks or a mix of both. This function can be used to determine quickly
9989
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9990
 * be sparse.
9991
 *
9992
 * Empty blocks are blocks that are generally not physically present in the
9993
 * file, and when read through GDAL, contain only pixels whose value is the
9994
 * nodata value when it is set, or whose value is 0 when the nodata value is
9995
 * not set.
9996
 *
9997
 * The query is done in an efficient way without reading the actual pixel
9998
 * values. If not possible, or not implemented at all by the driver,
9999
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10000
 * be returned.
10001
 *
10002
 * The values that can be returned by the function are the following,
10003
 * potentially combined with the binary or operator :
10004
 * <ul>
10005
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10006
 * GetDataCoverageStatus(). This flag should be returned together with
10007
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10008
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10009
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10010
 * the queried window. This is typically identified by the concept of missing
10011
 * block in formats that supports it.
10012
 * </li>
10013
 * </ul>
10014
 *
10015
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10016
 * should be interpreted more as hint of potential presence of data. For example
10017
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10018
 * nodata value), instead of using the missing block mechanism,
10019
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10020
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10021
 *
10022
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10023
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10024
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10025
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10026
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10027
 * the function will exit, so that you can potentially refine the requested area
10028
 * to find which particular region(s) have missing blocks.
10029
 *
10030
 * @see GDALRasterBand::GetDataCoverageStatus()
10031
 *
10032
 * @param hBand raster band
10033
 *
10034
 * @param nXOff The pixel offset to the top left corner of the region
10035
 * of the band to be queried. This would be zero to start from the left side.
10036
 *
10037
 * @param nYOff The line offset to the top left corner of the region
10038
 * of the band to be queried. This would be zero to start from the top.
10039
 *
10040
 * @param nXSize The width of the region of the band to be queried in pixels.
10041
 *
10042
 * @param nYSize The height of the region of the band to be queried in lines.
10043
 *
10044
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10045
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10046
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10047
 * as the computation of the coverage matches the mask, the computation will be
10048
 * stopped. *pdfDataPct will not be valid in that case.
10049
 *
10050
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10051
 * to the (approximate) percentage in [0,100] of pixels in the queried
10052
 * sub-window that have valid values. The implementation might not always be
10053
 * able to compute it, in which case it will be set to a negative value.
10054
 *
10055
 * @return a binary-or'ed combination of possible values
10056
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10057
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10058
 */
10059
10060
int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10061
                                          int nYOff, int nXSize, int nYSize,
10062
                                          int nMaskFlagStop, double *pdfDataPct)
10063
0
{
10064
0
    VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10065
0
                      GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10066
10067
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10068
10069
0
    return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10070
0
                                         nMaskFlagStop, pdfDataPct);
10071
0
}
10072
10073
/************************************************************************/
10074
/*                          GetDataCoverageStatus()                     */
10075
/************************************************************************/
10076
10077
/**
10078
 * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10079
 *                                           int nYOff,
10080
 *                                           int nXSize,
10081
 *                                           int nYSize,
10082
 *                                           int nMaskFlagStop,
10083
 *                                           double* pdfDataPct)
10084
 * \brief Get the coverage status of a sub-window of the raster.
10085
 *
10086
 * Returns whether a sub-window of the raster contains only data, only empty
10087
 * blocks or a mix of both. This function can be used to determine quickly
10088
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10089
 * be sparse.
10090
 *
10091
 * Empty blocks are blocks that contain only pixels whose value is the nodata
10092
 * value when it is set, or whose value is 0 when the nodata value is not set.
10093
 *
10094
 * The query is done in an efficient way without reading the actual pixel
10095
 * values. If not possible, or not implemented at all by the driver,
10096
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10097
 * be returned.
10098
 *
10099
 * The values that can be returned by the function are the following,
10100
 * potentially combined with the binary or operator :
10101
 * <ul>
10102
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10103
 * GetDataCoverageStatus(). This flag should be returned together with
10104
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10105
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10106
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10107
 * the queried window. This is typically identified by the concept of missing
10108
 * block in formats that supports it.
10109
 * </li>
10110
 * </ul>
10111
 *
10112
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10113
 * should be interpreted more as hint of potential presence of data. For example
10114
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10115
 * nodata value), instead of using the missing block mechanism,
10116
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10117
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10118
 *
10119
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10120
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10121
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10122
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10123
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10124
 * the function will exit, so that you can potentially refine the requested area
10125
 * to find which particular region(s) have missing blocks.
10126
 *
10127
 * @see GDALGetDataCoverageStatus()
10128
 *
10129
 * @param nXOff The pixel offset to the top left corner of the region
10130
 * of the band to be queried. This would be zero to start from the left side.
10131
 *
10132
 * @param nYOff The line offset to the top left corner of the region
10133
 * of the band to be queried. This would be zero to start from the top.
10134
 *
10135
 * @param nXSize The width of the region of the band to be queried in pixels.
10136
 *
10137
 * @param nYSize The height of the region of the band to be queried in lines.
10138
 *
10139
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10140
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10141
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10142
 * as the computation of the coverage matches the mask, the computation will be
10143
 * stopped. *pdfDataPct will not be valid in that case.
10144
 *
10145
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10146
 * to the (approximate) percentage in [0,100] of pixels in the queried
10147
 * sub-window that have valid values. The implementation might not always be
10148
 * able to compute it, in which case it will be set to a negative value.
10149
 *
10150
 * @return a binary-or'ed combination of possible values
10151
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10152
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10153
 */
10154
10155
/**
10156
 * \brief Get the coverage status of a sub-window of the raster.
10157
 *
10158
 * Returns whether a sub-window of the raster contains only data, only empty
10159
 * blocks or a mix of both. This function can be used to determine quickly
10160
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10161
 * be sparse.
10162
 *
10163
 * Empty blocks are blocks that contain only pixels whose value is the nodata
10164
 * value when it is set, or whose value is 0 when the nodata value is not set.
10165
 *
10166
 * The query is done in an efficient way without reading the actual pixel
10167
 * values. If not possible, or not implemented at all by the driver,
10168
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10169
 * be returned.
10170
 *
10171
 * The values that can be returned by the function are the following,
10172
 * potentially combined with the binary or operator :
10173
 * <ul>
10174
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10175
 * GetDataCoverageStatus(). This flag should be returned together with
10176
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10177
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10178
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10179
 * the queried window. This is typically identified by the concept of missing
10180
 * block in formats that supports it.
10181
 * </li>
10182
 * </ul>
10183
 *
10184
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10185
 * should be interpreted more as hint of potential presence of data. For example
10186
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10187
 * nodata value), instead of using the missing block mechanism,
10188
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10189
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10190
 *
10191
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10192
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10193
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10194
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10195
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10196
 * the function will exit, so that you can potentially refine the requested area
10197
 * to find which particular region(s) have missing blocks.
10198
 *
10199
 * @see GDALGetDataCoverageStatus()
10200
 *
10201
 * @param nXOff The pixel offset to the top left corner of the region
10202
 * of the band to be queried. This would be zero to start from the left side.
10203
 *
10204
 * @param nYOff The line offset to the top left corner of the region
10205
 * of the band to be queried. This would be zero to start from the top.
10206
 *
10207
 * @param nXSize The width of the region of the band to be queried in pixels.
10208
 *
10209
 * @param nYSize The height of the region of the band to be queried in lines.
10210
 *
10211
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10212
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10213
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10214
 * as the computation of the coverage matches the mask, the computation will be
10215
 * stopped. *pdfDataPct will not be valid in that case.
10216
 *
10217
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10218
 * to the (approximate) percentage in [0,100] of pixels in the queried
10219
 * sub-window that have valid values. The implementation might not always be
10220
 * able to compute it, in which case it will be set to a negative value.
10221
 *
10222
 * @return a binary-or'ed combination of possible values
10223
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10224
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10225
 */
10226
10227
int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10228
                                          int nYSize, int nMaskFlagStop,
10229
                                          double *pdfDataPct)
10230
0
{
10231
0
    if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
10232
0
        nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
10233
0
        nYOff + nYSize > nRasterYSize)
10234
0
    {
10235
0
        CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10236
0
        if (pdfDataPct)
10237
0
            *pdfDataPct = 0.0;
10238
0
        return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10239
0
               GDAL_DATA_COVERAGE_STATUS_EMPTY;
10240
0
    }
10241
0
    return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10242
0
                                  pdfDataPct);
10243
0
}
10244
10245
/************************************************************************/
10246
/*                         IGetDataCoverageStatus()                     */
10247
/************************************************************************/
10248
10249
int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10250
                                           int /*nXSize*/, int /*nYSize*/,
10251
                                           int /*nMaskFlagStop*/,
10252
                                           double *pdfDataPct)
10253
0
{
10254
0
    if (pdfDataPct != nullptr)
10255
0
        *pdfDataPct = 100.0;
10256
0
    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10257
0
           GDAL_DATA_COVERAGE_STATUS_DATA;
10258
0
}
10259
10260
//! @cond Doxygen_Suppress
10261
/************************************************************************/
10262
/*                          EnterReadWrite()                            */
10263
/************************************************************************/
10264
10265
int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10266
0
{
10267
0
    if (poDS != nullptr)
10268
0
        return poDS->EnterReadWrite(eRWFlag);
10269
0
    return FALSE;
10270
0
}
10271
10272
/************************************************************************/
10273
/*                         LeaveReadWrite()                             */
10274
/************************************************************************/
10275
10276
void GDALRasterBand::LeaveReadWrite()
10277
0
{
10278
0
    if (poDS != nullptr)
10279
0
        poDS->LeaveReadWrite();
10280
0
}
10281
10282
/************************************************************************/
10283
/*                           InitRWLock()                               */
10284
/************************************************************************/
10285
10286
void GDALRasterBand::InitRWLock()
10287
0
{
10288
0
    if (poDS != nullptr)
10289
0
        poDS->InitRWLock();
10290
0
}
10291
10292
//! @endcond
10293
10294
// clang-format off
10295
10296
/**
10297
 * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10298
 * \brief Set metadata.
10299
 *
10300
 * CAUTION: depending on the format, older values of the updated information
10301
 * might still be found in the file in a "ghost" state, even if no longer
10302
 * accessible through the GDAL API. This is for example the case of the GTiff
10303
 * format (this is not a exhaustive list)
10304
 *
10305
 * The C function GDALSetMetadata() does the same thing as this method.
10306
 *
10307
 * @param papszMetadata the metadata in name=value string list format to
10308
 * apply.
10309
 * @param pszDomain the domain of interest.  Use "" or NULL for the default
10310
 * domain.
10311
 * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10312
 * metadata has been accepted, but is likely not maintained persistently
10313
 * by the underlying object between sessions.
10314
 */
10315
10316
/**
10317
 * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10318
 * \brief Set single metadata item.
10319
 *
10320
 * CAUTION: depending on the format, older values of the updated information
10321
 * might still be found in the file in a "ghost" state, even if no longer
10322
 * accessible through the GDAL API. This is for example the case of the GTiff
10323
 * format (this is not a exhaustive list)
10324
 *
10325
 * The C function GDALSetMetadataItem() does the same thing as this method.
10326
 *
10327
 * @param pszName the key for the metadata item to fetch.
10328
 * @param pszValue the value to assign to the key.
10329
 * @param pszDomain the domain to set within, use NULL for the default domain.
10330
 *
10331
 * @return CE_None on success, or an error code on failure.
10332
 */
10333
10334
// clang-format on
10335
10336
//! @cond Doxygen_Suppress
10337
/************************************************************************/
10338
/*                    EnablePixelTypeSignedByteWarning()                */
10339
/************************************************************************/
10340
10341
void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10342
0
{
10343
0
    m_bEnablePixelTypeSignedByteWarning = b;
10344
0
}
10345
10346
void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10347
0
{
10348
0
    GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10349
0
}
10350
10351
//! @endcond
10352
10353
/************************************************************************/
10354
/*                           GetMetadataItem()                          */
10355
/************************************************************************/
10356
10357
const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10358
                                            const char *pszDomain)
10359
0
{
10360
    // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10361
0
    if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
10362
0
        pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
10363
0
        EQUAL(pszName, "PIXELTYPE"))
10364
0
    {
10365
0
        CPLError(CE_Warning, CPLE_AppDefined,
10366
0
                 "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10367
0
                 "used to signal signed 8-bit raster. Change your code to "
10368
0
                 "test for the new GDT_Int8 data type instead.");
10369
0
    }
10370
0
    return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10371
0
}
10372
10373
/************************************************************************/
10374
/*                            WindowIterator                            */
10375
/************************************************************************/
10376
10377
//! @cond Doxygen_Suppress
10378
10379
GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10380
                                               int nRasterYSize,
10381
                                               int nBlockXSize, int nBlockYSize,
10382
                                               int nRow, int nCol)
10383
0
    : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10384
0
      m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10385
0
      m_col(nCol)
10386
0
{
10387
0
}
10388
10389
bool GDALRasterBand::WindowIterator::operator==(
10390
    const WindowIterator &other) const
10391
0
{
10392
0
    return m_row == other.m_row && m_col == other.m_col &&
10393
0
           m_nRasterXSize == other.m_nRasterXSize &&
10394
0
           m_nRasterYSize == other.m_nRasterYSize &&
10395
0
           m_nBlockXSize == other.m_nBlockXSize &&
10396
0
           m_nBlockYSize == other.m_nBlockYSize;
10397
0
}
10398
10399
bool GDALRasterBand::WindowIterator::operator!=(
10400
    const WindowIterator &other) const
10401
0
{
10402
0
    return !(*this == other);
10403
0
}
10404
10405
GDALRasterBand::WindowIterator::value_type
10406
GDALRasterBand::WindowIterator::operator*() const
10407
0
{
10408
0
    GDALRasterWindow ret;
10409
0
    ret.nXOff = m_col * m_nBlockXSize;
10410
0
    ret.nYOff = m_row * m_nBlockYSize;
10411
0
    ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10412
0
    ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10413
10414
0
    return ret;
10415
0
}
10416
10417
GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10418
0
{
10419
0
    m_col++;
10420
0
    if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10421
0
    {
10422
0
        m_col = 0;
10423
0
        m_row++;
10424
0
    }
10425
0
    return *this;
10426
0
}
10427
10428
GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10429
    const GDALRasterBand &band, size_t maxSize)
10430
0
    : m_nRasterXSize(band.GetXSize()), m_nRasterYSize(band.GetYSize()),
10431
0
      m_nBlockXSize(-1), m_nBlockYSize(-1)
10432
0
{
10433
#ifdef CSA_BUILD
10434
    assert(this);
10435
#endif
10436
0
    int nXSize, nYSize;
10437
10438
0
    CPLErrorStateBackuper state(CPLQuietErrorHandler);
10439
0
    band.GetBlockSize(&nXSize, &nYSize);
10440
0
    if (nXSize < 1 || nYSize < 0)
10441
0
    {
10442
        // If invalid block size is reported, assume scanlines
10443
0
        nXSize = m_nRasterXSize;
10444
0
        nYSize = 1;
10445
0
    }
10446
10447
0
    if (maxSize == 0)
10448
0
    {
10449
0
        m_nBlockXSize = nXSize;
10450
0
        m_nBlockYSize = nYSize;
10451
0
        return;
10452
0
    }
10453
10454
0
    const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10455
0
    const double dfBlocksPerChunk =
10456
0
        static_cast<double>(maxSize) /
10457
0
        (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10458
10459
0
    if (dfBlocksPerChunk < dfBlocksPerRow)
10460
0
    {
10461
0
        m_nBlockXSize = static_cast<int>(std::min<double>(
10462
0
            m_nRasterXSize,
10463
0
            nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10464
0
        m_nBlockYSize = nYSize;
10465
0
    }
10466
0
    else
10467
0
    {
10468
0
        m_nBlockXSize = m_nRasterXSize;
10469
0
        m_nBlockYSize = static_cast<int>(std::min<double>(
10470
0
            m_nRasterYSize,
10471
0
            nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
10472
0
    }
10473
    if constexpr (sizeof(size_t) < sizeof(uint64_t))
10474
    {
10475
        if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
10476
        {
10477
            nXSize = m_nRasterXSize;
10478
            nYSize = 1;
10479
        }
10480
    }
10481
0
}
10482
10483
GDALRasterBand::WindowIterator
10484
GDALRasterBand::WindowIteratorWrapper::begin() const
10485
0
{
10486
0
    return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10487
0
                          m_nBlockYSize, 0, 0);
10488
0
}
10489
10490
GDALRasterBand::WindowIterator
10491
GDALRasterBand::WindowIteratorWrapper::end() const
10492
0
{
10493
0
    return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10494
0
                          m_nBlockYSize,
10495
0
                          DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
10496
0
}
10497
10498
uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
10499
0
{
10500
0
    return static_cast<uint64_t>(
10501
0
               cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
10502
0
           static_cast<uint64_t>(
10503
0
               cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
10504
0
}
10505
10506
//! @endcond
10507
10508
/** Return an object whose begin() and end() methods can be used to iterate
10509
 *  over GDALRasterWindow objects that are aligned with blocks in this raster
10510
 *  band. The iteration order is from left to right, then from top to bottom.
10511
 *
10512
\code{.cpp}
10513
    std::vector<double> pixelValues;
10514
    for (const auto& window : poBand->IterateWindows()) {
10515
        CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
10516
                                         window.nXSize, window.nYSize);
10517
        // check eErr
10518
    }
10519
\endcode
10520
 *
10521
 *
10522
 *  @param maxSize The maximum number of pixels in each window. If set to
10523
 *         zero (the default), or a number smaller than the block size,
10524
 *         the window size will be the same as the block size.
10525
 *  @since GDAL 3.12
10526
 */
10527
GDALRasterBand::WindowIteratorWrapper
10528
GDALRasterBand::IterateWindows(size_t maxSize) const
10529
0
{
10530
0
    return WindowIteratorWrapper(*this, maxSize);
10531
0
}
10532
10533
/************************************************************************/
10534
/*                     GDALMDArrayFromRasterBand                        */
10535
/************************************************************************/
10536
10537
class GDALMDArrayFromRasterBand final : public GDALMDArray
10538
{
10539
    CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
10540
10541
    GDALDataset *m_poDS;
10542
    GDALRasterBand *m_poBand;
10543
    GDALExtendedDataType m_dt;
10544
    std::vector<std::shared_ptr<GDALDimension>> m_dims{};
10545
    std::string m_osUnit;
10546
    std::vector<GByte> m_pabyNoData{};
10547
    std::shared_ptr<GDALMDArray> m_varX{};
10548
    std::shared_ptr<GDALMDArray> m_varY{};
10549
    std::string m_osFilename{};
10550
10551
    bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
10552
                   const size_t *count, const GInt64 *arrayStep,
10553
                   const GPtrDiff_t *bufferStride,
10554
                   const GDALExtendedDataType &bufferDataType,
10555
                   void *pBuffer) const;
10556
10557
  protected:
10558
    GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
10559
0
        : GDALAbstractMDArray(std::string(),
10560
0
                              std::string(poDS->GetDescription()) +
10561
0
                                  CPLSPrintf(" band %d", poBand->GetBand())),
10562
0
          GDALMDArray(std::string(),
10563
0
                      std::string(poDS->GetDescription()) +
10564
0
                          CPLSPrintf(" band %d", poBand->GetBand())),
10565
0
          m_poDS(poDS), m_poBand(poBand),
10566
0
          m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
10567
0
          m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
10568
0
    {
10569
0
        m_poDS->Reference();
10570
10571
0
        int bHasNoData = false;
10572
0
        if (m_poBand->GetRasterDataType() == GDT_Int64)
10573
0
        {
10574
0
            const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
10575
0
            if (bHasNoData)
10576
0
            {
10577
0
                m_pabyNoData.resize(m_dt.GetSize());
10578
0
                GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
10579
0
                                m_dt.GetNumericDataType(), 0, 1);
10580
0
            }
10581
0
        }
10582
0
        else if (m_poBand->GetRasterDataType() == GDT_UInt64)
10583
0
        {
10584
0
            const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
10585
0
            if (bHasNoData)
10586
0
            {
10587
0
                m_pabyNoData.resize(m_dt.GetSize());
10588
0
                GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
10589
0
                                m_dt.GetNumericDataType(), 0, 1);
10590
0
            }
10591
0
        }
10592
0
        else
10593
0
        {
10594
0
            const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
10595
0
            if (bHasNoData)
10596
0
            {
10597
0
                m_pabyNoData.resize(m_dt.GetSize());
10598
0
                GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
10599
0
                                m_dt.GetNumericDataType(), 0, 1);
10600
0
            }
10601
0
        }
10602
10603
0
        const int nXSize = poBand->GetXSize();
10604
0
        const int nYSize = poBand->GetYSize();
10605
10606
0
        auto poSRS = m_poDS->GetSpatialRef();
10607
0
        std::string osTypeY;
10608
0
        std::string osTypeX;
10609
0
        std::string osDirectionY;
10610
0
        std::string osDirectionX;
10611
0
        if (poSRS && poSRS->GetAxesCount() == 2)
10612
0
        {
10613
0
            const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
10614
0
            OGRAxisOrientation eOrientation1 = OAO_Other;
10615
0
            poSRS->GetAxis(nullptr, 0, &eOrientation1);
10616
0
            OGRAxisOrientation eOrientation2 = OAO_Other;
10617
0
            poSRS->GetAxis(nullptr, 1, &eOrientation2);
10618
0
            if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
10619
0
            {
10620
0
                if (mapping == std::vector<int>{1, 2})
10621
0
                {
10622
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
10623
0
                    osDirectionY = "NORTH";
10624
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
10625
0
                    osDirectionX = "EAST";
10626
0
                }
10627
0
            }
10628
0
            else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
10629
0
            {
10630
0
                if (mapping == std::vector<int>{2, 1})
10631
0
                {
10632
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
10633
0
                    osDirectionY = "NORTH";
10634
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
10635
0
                    osDirectionX = "EAST";
10636
0
                }
10637
0
            }
10638
0
        }
10639
10640
0
        m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
10641
0
                      "/", "Y", osTypeY, osDirectionY, nYSize),
10642
0
                  std::make_shared<GDALDimensionWeakIndexingVar>(
10643
0
                      "/", "X", osTypeX, osDirectionX, nXSize)};
10644
10645
0
        GDALGeoTransform gt;
10646
0
        if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
10647
0
        {
10648
0
            m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
10649
0
                                                        gt[0], gt[1], 0.5);
10650
0
            m_dims[1]->SetIndexingVariable(m_varX);
10651
10652
0
            m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
10653
0
                                                        gt[3], gt[5], 0.5);
10654
0
            m_dims[0]->SetIndexingVariable(m_varY);
10655
0
        }
10656
0
    }
10657
10658
    bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
10659
               const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10660
               const GDALExtendedDataType &bufferDataType,
10661
               void *pDstBuffer) const override;
10662
10663
    bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
10664
                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10665
                const GDALExtendedDataType &bufferDataType,
10666
                const void *pSrcBuffer) override
10667
0
    {
10668
0
        return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
10669
0
                         bufferStride, bufferDataType,
10670
0
                         const_cast<void *>(pSrcBuffer));
10671
0
    }
10672
10673
  public:
10674
    ~GDALMDArrayFromRasterBand() override
10675
0
    {
10676
0
        m_poDS->ReleaseRef();
10677
0
    }
10678
10679
    static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
10680
                                               GDALRasterBand *poBand)
10681
0
    {
10682
0
        auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
10683
0
            new GDALMDArrayFromRasterBand(poDS, poBand)));
10684
0
        array->SetSelf(array);
10685
0
        return array;
10686
0
    }
10687
10688
    bool IsWritable() const override
10689
0
    {
10690
0
        return m_poDS->GetAccess() == GA_Update;
10691
0
    }
10692
10693
    const std::string &GetFilename() const override
10694
0
    {
10695
0
        return m_osFilename;
10696
0
    }
10697
10698
    const std::vector<std::shared_ptr<GDALDimension>> &
10699
    GetDimensions() const override
10700
0
    {
10701
0
        return m_dims;
10702
0
    }
10703
10704
    const GDALExtendedDataType &GetDataType() const override
10705
0
    {
10706
0
        return m_dt;
10707
0
    }
10708
10709
    const std::string &GetUnit() const override
10710
0
    {
10711
0
        return m_osUnit;
10712
0
    }
10713
10714
    const void *GetRawNoDataValue() const override
10715
0
    {
10716
0
        return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
10717
0
    }
10718
10719
    double GetOffset(bool *pbHasOffset,
10720
                     GDALDataType *peStorageType) const override
10721
0
    {
10722
0
        int bHasOffset = false;
10723
0
        double dfRes = m_poBand->GetOffset(&bHasOffset);
10724
0
        if (pbHasOffset)
10725
0
            *pbHasOffset = CPL_TO_BOOL(bHasOffset);
10726
0
        if (peStorageType)
10727
0
            *peStorageType = GDT_Unknown;
10728
0
        return dfRes;
10729
0
    }
10730
10731
    double GetScale(bool *pbHasScale,
10732
                    GDALDataType *peStorageType) const override
10733
0
    {
10734
0
        int bHasScale = false;
10735
0
        double dfRes = m_poBand->GetScale(&bHasScale);
10736
0
        if (pbHasScale)
10737
0
            *pbHasScale = CPL_TO_BOOL(bHasScale);
10738
0
        if (peStorageType)
10739
0
            *peStorageType = GDT_Unknown;
10740
0
        return dfRes;
10741
0
    }
10742
10743
    std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
10744
0
    {
10745
0
        auto poSrcSRS = m_poDS->GetSpatialRef();
10746
0
        if (!poSrcSRS)
10747
0
            return nullptr;
10748
0
        auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
10749
10750
0
        auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
10751
0
        constexpr int iYDim = 0;
10752
0
        constexpr int iXDim = 1;
10753
0
        for (auto &m : axisMapping)
10754
0
        {
10755
0
            if (m == 1)
10756
0
                m = iXDim + 1;
10757
0
            else if (m == 2)
10758
0
                m = iYDim + 1;
10759
0
            else
10760
0
                m = 0;
10761
0
        }
10762
0
        poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
10763
0
        return poSRS;
10764
0
    }
10765
10766
    std::vector<GUInt64> GetBlockSize() const override
10767
0
    {
10768
0
        int nBlockXSize = 0;
10769
0
        int nBlockYSize = 0;
10770
0
        m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
10771
0
        return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
10772
0
                                    static_cast<GUInt64>(nBlockXSize)};
10773
0
    }
10774
10775
    std::vector<std::shared_ptr<GDALAttribute>>
10776
    GetAttributes(CSLConstList) const override
10777
0
    {
10778
0
        std::vector<std::shared_ptr<GDALAttribute>> res;
10779
0
        auto papszMD = m_poBand->GetMetadata();
10780
0
        for (auto iter = papszMD; iter && iter[0]; ++iter)
10781
0
        {
10782
0
            char *pszKey = nullptr;
10783
0
            const char *pszValue = CPLParseNameValue(*iter, &pszKey);
10784
0
            if (pszKey && pszValue)
10785
0
            {
10786
0
                res.emplace_back(
10787
0
                    std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
10788
0
            }
10789
0
            CPLFree(pszKey);
10790
0
        }
10791
0
        return res;
10792
0
    }
10793
};
10794
10795
bool GDALMDArrayFromRasterBand::IRead(
10796
    const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
10797
    const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
10798
    void *pDstBuffer) const
10799
0
{
10800
0
    return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
10801
0
                     bufferDataType, pDstBuffer);
10802
0
}
10803
10804
/************************************************************************/
10805
/*                            ReadWrite()                               */
10806
/************************************************************************/
10807
10808
bool GDALMDArrayFromRasterBand::ReadWrite(
10809
    GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
10810
    const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10811
    const GDALExtendedDataType &bufferDataType, void *pBuffer) const
10812
0
{
10813
0
    constexpr size_t iDimX = 1;
10814
0
    constexpr size_t iDimY = 0;
10815
0
    return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
10816
0
                                  arrayStartIdx, count, arrayStep, bufferStride,
10817
0
                                  bufferDataType, pBuffer);
10818
0
}
10819
10820
/************************************************************************/
10821
/*                       GDALMDRasterIOFromBand()                       */
10822
/************************************************************************/
10823
10824
bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
10825
                            size_t iDimX, size_t iDimY,
10826
                            const GUInt64 *arrayStartIdx, const size_t *count,
10827
                            const GInt64 *arrayStep,
10828
                            const GPtrDiff_t *bufferStride,
10829
                            const GDALExtendedDataType &bufferDataType,
10830
                            void *pBuffer)
10831
0
{
10832
0
    const auto eDT(bufferDataType.GetNumericDataType());
10833
0
    const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
10834
0
    const int nX =
10835
0
        arrayStep[iDimX] > 0
10836
0
            ? static_cast<int>(arrayStartIdx[iDimX])
10837
0
            : static_cast<int>(arrayStartIdx[iDimX] -
10838
0
                               (count[iDimX] - 1) * -arrayStep[iDimX]);
10839
0
    const int nY =
10840
0
        arrayStep[iDimY] > 0
10841
0
            ? static_cast<int>(arrayStartIdx[iDimY])
10842
0
            : static_cast<int>(arrayStartIdx[iDimY] -
10843
0
                               (count[iDimY] - 1) * -arrayStep[iDimY]);
10844
0
    const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
10845
0
    const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
10846
0
    GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
10847
0
    int nStrideXSign = 1;
10848
0
    if (arrayStep[iDimX] < 0)
10849
0
    {
10850
0
        pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
10851
0
        nStrideXSign = -1;
10852
0
    }
10853
0
    int nStrideYSign = 1;
10854
0
    if (arrayStep[iDimY] < 0)
10855
0
    {
10856
0
        pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
10857
0
        nStrideYSign = -1;
10858
0
    }
10859
10860
0
    return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
10861
0
                            static_cast<int>(count[iDimX]),
10862
0
                            static_cast<int>(count[iDimY]), eDT,
10863
0
                            static_cast<GSpacing>(
10864
0
                                nStrideXSign * bufferStride[iDimX] * nDTSize),
10865
0
                            static_cast<GSpacing>(
10866
0
                                nStrideYSign * bufferStride[iDimY] * nDTSize),
10867
0
                            nullptr) == CE_None;
10868
0
}
10869
10870
/************************************************************************/
10871
/*                            AsMDArray()                               */
10872
/************************************************************************/
10873
10874
/** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10875
 *
10876
 * The band must be linked to a GDALDataset. If this dataset is not already
10877
 * marked as shared, it will be, so that the returned array holds a reference
10878
 * to it.
10879
 *
10880
 * If the dataset has a geotransform attached, the X and Y dimensions of the
10881
 * returned array will have an associated indexing variable.
10882
 *
10883
 * This is the same as the C function GDALRasterBandAsMDArray().
10884
 *
10885
 * The "reverse" method is GDALMDArray::AsClassicDataset().
10886
 *
10887
 * @return a new array, or nullptr.
10888
 *
10889
 * @since GDAL 3.1
10890
 */
10891
std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
10892
0
{
10893
0
    if (!poDS)
10894
0
    {
10895
0
        CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
10896
0
        return nullptr;
10897
0
    }
10898
0
    if (!poDS->GetShared())
10899
0
    {
10900
0
        poDS->MarkAsShared();
10901
0
    }
10902
0
    return GDALMDArrayFromRasterBand::Create(
10903
0
        poDS, const_cast<GDALRasterBand *>(this));
10904
0
}
10905
10906
/************************************************************************/
10907
/*                             InterpolateAtPoint()                     */
10908
/************************************************************************/
10909
10910
/**
10911
 * \brief Interpolates the value between pixels using a resampling algorithm,
10912
 * taking pixel/line coordinates as input.
10913
 *
10914
 * @param dfPixel pixel coordinate as a double, where interpolation should be done.
10915
 * @param dfLine line coordinate as a double, where interpolation should be done.
10916
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10917
 * @param pdfRealValue pointer to real part of interpolated value
10918
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10919
 *
10920
 * @return CE_None on success, or an error code on failure.
10921
 * @since GDAL 3.10
10922
 */
10923
10924
CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
10925
                                          GDALRIOResampleAlg eInterpolation,
10926
                                          double *pdfRealValue,
10927
                                          double *pdfImagValue) const
10928
0
{
10929
0
    if (eInterpolation != GRIORA_NearestNeighbour &&
10930
0
        eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
10931
0
        eInterpolation != GRIORA_CubicSpline)
10932
0
    {
10933
0
        CPLError(CE_Failure, CPLE_AppDefined,
10934
0
                 "Only nearest, bilinear, cubic and cubicspline interpolation "
10935
0
                 "methods "
10936
0
                 "allowed");
10937
10938
0
        return CE_Failure;
10939
0
    }
10940
10941
0
    GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
10942
0
    if (!m_poPointsCache)
10943
0
        m_poPointsCache = new GDALDoublePointsCache();
10944
10945
0
    const bool res =
10946
0
        GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
10947
0
                               dfPixel, dfLine, pdfRealValue, pdfImagValue);
10948
10949
0
    return res ? CE_None : CE_Failure;
10950
0
}
10951
10952
/************************************************************************/
10953
/*                        GDALRasterInterpolateAtPoint()                */
10954
/************************************************************************/
10955
10956
/**
10957
 * \brief Interpolates the value between pixels using
10958
 * a resampling algorithm
10959
 *
10960
 * @see GDALRasterBand::InterpolateAtPoint()
10961
 * @since GDAL 3.10
10962
 */
10963
10964
CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10965
                                    double dfLine,
10966
                                    GDALRIOResampleAlg eInterpolation,
10967
                                    double *pdfRealValue, double *pdfImagValue)
10968
0
{
10969
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10970
10971
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10972
0
    return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10973
0
                                      pdfRealValue, pdfImagValue);
10974
0
}
10975
10976
/************************************************************************/
10977
/*                    InterpolateAtGeolocation()                        */
10978
/************************************************************************/
10979
10980
/**
10981
 * \brief Interpolates the value between pixels using a resampling algorithm,
10982
 * taking georeferenced coordinates as input.
10983
 *
10984
 * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
10985
 * must be in the "natural" SRS of the dataset, that is the one returned by
10986
 * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
10987
 * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
10988
 * array (generally WGS 84) if there is a geolocation array.
10989
 * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10990
 * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10991
 * be a easting, and dfGeolocY a northing.
10992
 *
10993
 * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10994
 * expressed in that CRS, and that tuple must be conformant with the
10995
 * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10996
 * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10997
 * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10998
 * before calling this method, and in that case, dfGeolocX must be a longitude
10999
 * or an easting value, and dfGeolocX a latitude or a northing value.
11000
 *
11001
 * The GDALDataset::GeolocationToPixelLine() will be used to transform from
11002
 * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
11003
 * it for details on how that transformation is done.
11004
 *
11005
 * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11006
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11007
 * where interpolation should be done.
11008
 * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11009
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11010
 * where interpolation should be done.
11011
 * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11012
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11013
 * @param pdfRealValue pointer to real part of interpolated value
11014
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11015
 * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11016
 *
11017
 * @return CE_None on success, or an error code on failure.
11018
 * @since GDAL 3.11
11019
 */
11020
11021
CPLErr GDALRasterBand::InterpolateAtGeolocation(
11022
    double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11023
    GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11024
    double *pdfImagValue, CSLConstList papszTransformerOptions) const
11025
0
{
11026
0
    double dfPixel;
11027
0
    double dfLine;
11028
0
    if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11029
0
                                     &dfLine,
11030
0
                                     papszTransformerOptions) != CE_None)
11031
0
    {
11032
0
        return CE_Failure;
11033
0
    }
11034
0
    return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11035
0
                              pdfImagValue);
11036
0
}
11037
11038
/************************************************************************/
11039
/*                  GDALRasterInterpolateAtGeolocation()                */
11040
/************************************************************************/
11041
11042
/**
11043
 * \brief Interpolates the value between pixels using a resampling algorithm,
11044
 * taking georeferenced coordinates as input.
11045
 *
11046
 * @see GDALRasterBand::InterpolateAtGeolocation()
11047
 * @since GDAL 3.11
11048
 */
11049
11050
CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11051
                                          double dfGeolocX, double dfGeolocY,
11052
                                          OGRSpatialReferenceH hSRS,
11053
                                          GDALRIOResampleAlg eInterpolation,
11054
                                          double *pdfRealValue,
11055
                                          double *pdfImagValue,
11056
                                          CSLConstList papszTransformerOptions)
11057
0
{
11058
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11059
11060
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11061
0
    return poBand->InterpolateAtGeolocation(
11062
0
        dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11063
0
        eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11064
0
}
11065
11066
/************************************************************************/
11067
/*                    GDALRasterBand::SplitRasterIO()                   */
11068
/************************************************************************/
11069
11070
//! @cond Doxygen_Suppress
11071
11072
/** Implements IRasterIO() by dividing the request in 2.
11073
 *
11074
 * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11075
 *
11076
 * Return CE_Warning if the split could not be done, CE_None in case of
11077
 * success and CE_Failure in case of error.
11078
 *
11079
 * @since 3.12
11080
 */
11081
CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11082
                                     [[maybe_unused]] int nXSize,
11083
                                     [[maybe_unused]] int nYSize, void *pData,
11084
                                     int nBufXSize, int nBufYSize,
11085
                                     GDALDataType eBufType,
11086
                                     GSpacing nPixelSpace, GSpacing nLineSpace,
11087
                                     GDALRasterIOExtraArg *psExtraArg)
11088
0
{
11089
0
    CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11090
11091
0
    GByte *pabyData = static_cast<GByte *>(pData);
11092
0
    if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11093
0
    {
11094
0
        GDALRasterIOExtraArg sArg;
11095
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
11096
0
        const int nHalfHeight = nBufYSize / 2;
11097
11098
0
        sArg.pfnProgress = GDALScaledProgress;
11099
0
        sArg.pProgressData = GDALCreateScaledProgress(
11100
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11101
0
        if (sArg.pProgressData == nullptr)
11102
0
            sArg.pfnProgress = nullptr;
11103
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11104
0
                                pabyData, nBufXSize, nHalfHeight, eBufType,
11105
0
                                nPixelSpace, nLineSpace, &sArg);
11106
0
        GDALDestroyScaledProgress(sArg.pProgressData);
11107
11108
0
        if (eErr == CE_None)
11109
0
        {
11110
0
            sArg.pfnProgress = GDALScaledProgress;
11111
0
            sArg.pProgressData = GDALCreateScaledProgress(
11112
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11113
0
            if (sArg.pProgressData == nullptr)
11114
0
                sArg.pfnProgress = nullptr;
11115
0
            eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11116
0
                             nBufYSize - nHalfHeight,
11117
0
                             pabyData + nHalfHeight * nLineSpace, nBufXSize,
11118
0
                             nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11119
0
                             nLineSpace, &sArg);
11120
0
            GDALDestroyScaledProgress(sArg.pProgressData);
11121
0
        }
11122
0
        return eErr;
11123
0
    }
11124
0
    else if (nBufXSize >= 2)
11125
0
    {
11126
0
        GDALRasterIOExtraArg sArg;
11127
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
11128
0
        const int nHalfWidth = nBufXSize / 2;
11129
11130
0
        sArg.pfnProgress = GDALScaledProgress;
11131
0
        sArg.pProgressData = GDALCreateScaledProgress(
11132
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11133
0
        if (sArg.pProgressData == nullptr)
11134
0
            sArg.pfnProgress = nullptr;
11135
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11136
0
                                pabyData, nHalfWidth, nBufYSize, eBufType,
11137
0
                                nPixelSpace, nLineSpace, &sArg);
11138
0
        GDALDestroyScaledProgress(sArg.pProgressData);
11139
11140
0
        if (eErr == CE_None)
11141
0
        {
11142
0
            sArg.pfnProgress = GDALScaledProgress;
11143
0
            sArg.pProgressData = GDALCreateScaledProgress(
11144
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11145
0
            if (sArg.pProgressData == nullptr)
11146
0
                sArg.pfnProgress = nullptr;
11147
0
            eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11148
0
                             nBufXSize - nHalfWidth, nBufYSize,
11149
0
                             pabyData + nHalfWidth * nPixelSpace,
11150
0
                             nBufXSize - nHalfWidth, nBufYSize, eBufType,
11151
0
                             nPixelSpace, nLineSpace, &sArg);
11152
0
            GDALDestroyScaledProgress(sArg.pProgressData);
11153
0
        }
11154
0
        return eErr;
11155
0
    }
11156
11157
0
    return CE_Warning;
11158
0
}
11159
11160
//! @endcond
11161
11162
/************************************************************************/
11163
/*                         ThrowIfNotSameDimensions()                   */
11164
/************************************************************************/
11165
11166
//! @cond Doxygen_Suppress
11167
/* static */
11168
void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11169
                                              const GDALRasterBand &second)
11170
0
{
11171
0
    if (first.GetXSize() != second.GetXSize() ||
11172
0
        first.GetYSize() != second.GetYSize())
11173
0
    {
11174
0
        throw std::runtime_error("Bands do not have the same dimensions");
11175
0
    }
11176
0
}
11177
11178
//! @endcond
11179
11180
/************************************************************************/
11181
/*                          GDALRasterBandUnaryOp()                     */
11182
/************************************************************************/
11183
11184
/** Apply a unary operation on this band.
11185
 *
11186
 * The resulting band is lazy evaluated. A reference is taken on the input
11187
 * dataset.
11188
 *
11189
 * @since 3.12
11190
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11191
 */
11192
GDALComputedRasterBandH
11193
GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11194
                      GDALRasterAlgebraUnaryOperation eOp)
11195
0
{
11196
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11197
0
    GDALComputedRasterBand::Operation cppOp{};
11198
0
    switch (eOp)
11199
0
    {
11200
0
        case GRAUO_LOGICAL_NOT:
11201
0
            return new GDALComputedRasterBand(
11202
0
                GDALComputedRasterBand::Operation::OP_NE,
11203
0
                *(GDALRasterBand::FromHandle(hBand)), true);
11204
0
        case GRAUO_ABS:
11205
0
            cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11206
0
            break;
11207
0
        case GRAUO_SQRT:
11208
0
            cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11209
0
            break;
11210
0
        case GRAUO_LOG:
11211
0
#ifndef HAVE_MUPARSER
11212
0
            CPLError(
11213
0
                CE_Failure, CPLE_NotSupported,
11214
0
                "log(band) not available on a GDAL build without muparser");
11215
0
            return nullptr;
11216
#else
11217
            cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11218
            break;
11219
#endif
11220
0
        case GRAUO_LOG10:
11221
0
            cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11222
0
            break;
11223
0
    }
11224
0
    return new GDALComputedRasterBand(cppOp,
11225
0
                                      *(GDALRasterBand::FromHandle(hBand)));
11226
0
}
11227
11228
/************************************************************************/
11229
/*            ConvertGDALRasterAlgebraBinaryOperationToCpp()            */
11230
/************************************************************************/
11231
11232
static GDALComputedRasterBand::Operation
11233
ConvertGDALRasterAlgebraBinaryOperationToCpp(
11234
    GDALRasterAlgebraBinaryOperation eOp)
11235
0
{
11236
0
    switch (eOp)
11237
0
    {
11238
0
        case GRABO_ADD:
11239
0
            return GDALComputedRasterBand::Operation::OP_ADD;
11240
0
        case GRABO_SUB:
11241
0
            return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11242
0
        case GRABO_MUL:
11243
0
            return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11244
0
        case GRABO_DIV:
11245
0
            return GDALComputedRasterBand::Operation::OP_DIVIDE;
11246
0
        case GRABO_GT:
11247
0
            return GDALComputedRasterBand::Operation::OP_GT;
11248
0
        case GRABO_GE:
11249
0
            return GDALComputedRasterBand::Operation::OP_GE;
11250
0
        case GRABO_LT:
11251
0
            return GDALComputedRasterBand::Operation::OP_LT;
11252
0
        case GRABO_LE:
11253
0
            return GDALComputedRasterBand::Operation::OP_LE;
11254
0
        case GRABO_EQ:
11255
0
            return GDALComputedRasterBand::Operation::OP_EQ;
11256
0
        case GRABO_NE:
11257
0
            break;
11258
0
        case GRABO_LOGICAL_AND:
11259
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11260
0
        case GRABO_LOGICAL_OR:
11261
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11262
0
        case GRABO_POW:
11263
0
            return GDALComputedRasterBand::Operation::OP_POW;
11264
0
    }
11265
0
    return GDALComputedRasterBand::Operation::OP_NE;
11266
0
}
11267
11268
/************************************************************************/
11269
/*                     GDALRasterBandBinaryOpBand()                     */
11270
/************************************************************************/
11271
11272
/** Apply a binary operation on this band with another one.
11273
 *
11274
 * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11275
 * "hBand1 - hBand2".
11276
 *
11277
 * The resulting band is lazy evaluated. A reference is taken on both input
11278
 * datasets.
11279
 *
11280
 * @since 3.12
11281
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11282
 */
11283
GDALComputedRasterBandH
11284
GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11285
                           GDALRasterAlgebraBinaryOperation eOp,
11286
                           GDALRasterBandH hOtherBand)
11287
0
{
11288
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11289
0
    VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11290
0
#ifndef HAVE_MUPARSER
11291
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11292
0
    {
11293
0
        CPLError(
11294
0
            CE_Failure, CPLE_NotSupported,
11295
0
            "Band comparison operators not available on a GDAL build without "
11296
0
            "muparser");
11297
0
        return nullptr;
11298
0
    }
11299
0
    else if (eOp == GRABO_POW)
11300
0
    {
11301
0
        CPLError(
11302
0
            CE_Failure, CPLE_NotSupported,
11303
0
            "pow(band, band) not available on a GDAL build without muparser");
11304
0
        return nullptr;
11305
0
    }
11306
0
#endif
11307
0
    auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11308
0
    auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11309
0
    try
11310
0
    {
11311
0
        GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11312
0
    }
11313
0
    catch (const std::exception &e)
11314
0
    {
11315
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11316
0
        return nullptr;
11317
0
    }
11318
0
    return new GDALComputedRasterBand(
11319
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11320
0
        secondBand);
11321
0
}
11322
11323
/************************************************************************/
11324
/*                     GDALRasterBandBinaryOpDouble()                   */
11325
/************************************************************************/
11326
11327
/** Apply a binary operation on this band with a constant
11328
 *
11329
 * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11330
 * "hBand - constant".
11331
 *
11332
 * The resulting band is lazy evaluated. A reference is taken on the input
11333
 * dataset.
11334
 *
11335
 * @since 3.12
11336
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11337
 */
11338
GDALComputedRasterBandH
11339
GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11340
                             GDALRasterAlgebraBinaryOperation eOp,
11341
                             double constant)
11342
0
{
11343
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11344
0
#ifndef HAVE_MUPARSER
11345
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11346
0
    {
11347
0
        CPLError(
11348
0
            CE_Failure, CPLE_NotSupported,
11349
0
            "Band comparison operators not available on a GDAL build without "
11350
0
            "muparser");
11351
0
        return nullptr;
11352
0
    }
11353
0
#endif
11354
0
    return new GDALComputedRasterBand(
11355
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11356
0
        *(GDALRasterBand::FromHandle(hBand)), constant);
11357
0
}
11358
11359
/************************************************************************/
11360
/*                   GDALRasterBandBinaryOpDoubleToBand()               */
11361
/************************************************************************/
11362
11363
/** Apply a binary operation on the constant with this band
11364
 *
11365
 * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11366
 * "constant - hBand".
11367
 *
11368
 * The resulting band is lazy evaluated. A reference is taken on the input
11369
 * dataset.
11370
 *
11371
 * @since 3.12
11372
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11373
 */
11374
GDALComputedRasterBandH
11375
GDALRasterBandBinaryOpDoubleToBand(double constant,
11376
                                   GDALRasterAlgebraBinaryOperation eOp,
11377
                                   GDALRasterBandH hBand)
11378
0
{
11379
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11380
0
#ifndef HAVE_MUPARSER
11381
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11382
0
    {
11383
0
        CPLError(
11384
0
            CE_Failure, CPLE_NotSupported,
11385
0
            "Band comparison operators not available on a GDAL build without "
11386
0
            "muparser");
11387
0
        return nullptr;
11388
0
    }
11389
0
#endif
11390
0
    switch (eOp)
11391
0
    {
11392
0
        case GRABO_ADD:
11393
0
        case GRABO_MUL:
11394
0
        {
11395
0
            return new GDALComputedRasterBand(
11396
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11397
0
                *(GDALRasterBand::FromHandle(hBand)), constant);
11398
0
        }
11399
11400
0
        case GRABO_DIV:
11401
0
        case GRABO_GT:
11402
0
        case GRABO_GE:
11403
0
        case GRABO_LT:
11404
0
        case GRABO_LE:
11405
0
        case GRABO_EQ:
11406
0
        case GRABO_NE:
11407
0
        case GRABO_LOGICAL_AND:
11408
0
        case GRABO_LOGICAL_OR:
11409
0
        case GRABO_POW:
11410
0
        {
11411
0
            return new GDALComputedRasterBand(
11412
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11413
0
                *(GDALRasterBand::FromHandle(hBand)));
11414
0
        }
11415
11416
0
        case GRABO_SUB:
11417
0
        {
11418
0
            break;
11419
0
        }
11420
0
    }
11421
11422
0
    return new GDALComputedRasterBand(
11423
0
        GDALComputedRasterBand::Operation::OP_ADD,
11424
0
        GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
11425
0
                               *(GDALRasterBand::FromHandle(hBand)), -1.0),
11426
0
        constant);
11427
0
}
11428
11429
/************************************************************************/
11430
/*                           operator+()                                */
11431
/************************************************************************/
11432
11433
/** Add this band with another one.
11434
 *
11435
 * The resulting band is lazy evaluated. A reference is taken on both input
11436
 * datasets.
11437
 *
11438
 * @since 3.12
11439
 * @throw std::runtime_error if both bands do not have the same dimensions.
11440
 */
11441
GDALComputedRasterBand
11442
GDALRasterBand::operator+(const GDALRasterBand &other) const
11443
0
{
11444
0
    ThrowIfNotSameDimensions(*this, other);
11445
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11446
0
                                  *this, other);
11447
0
}
11448
11449
/************************************************************************/
11450
/*                           operator+()                                */
11451
/************************************************************************/
11452
11453
/** Add this band with a constant.
11454
 *
11455
 * The resulting band is lazy evaluated. A reference is taken on the input
11456
 * dataset.
11457
 *
11458
 * @since 3.12
11459
 */
11460
GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
11461
0
{
11462
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11463
0
                                  *this, constant);
11464
0
}
11465
11466
/************************************************************************/
11467
/*                           operator+()                                */
11468
/************************************************************************/
11469
11470
/** Add a band with a constant.
11471
 *
11472
 * The resulting band is lazy evaluated. A reference is taken on the input
11473
 * dataset.
11474
 *
11475
 * @since 3.12
11476
 */
11477
GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
11478
0
{
11479
0
    return other + constant;
11480
0
}
11481
11482
/************************************************************************/
11483
/*                           operator-()                                */
11484
/************************************************************************/
11485
11486
/** Return a band whose value is the opposite value of the band for each
11487
 * pixel.
11488
 *
11489
 * The resulting band is lazy evaluated. A reference is taken on the input
11490
 * dataset.
11491
 *
11492
 * @since 3.12
11493
 */
11494
GDALComputedRasterBand GDALRasterBand::operator-() const
11495
0
{
11496
0
    return 0 - *this;
11497
0
}
11498
11499
/************************************************************************/
11500
/*                           operator-()                                */
11501
/************************************************************************/
11502
11503
/** Subtract this band with another one.
11504
 *
11505
 * The resulting band is lazy evaluated. A reference is taken on both input
11506
 * datasets.
11507
 *
11508
 * @since 3.12
11509
 * @throw std::runtime_error if both bands do not have the same dimensions.
11510
 */
11511
GDALComputedRasterBand
11512
GDALRasterBand::operator-(const GDALRasterBand &other) const
11513
0
{
11514
0
    ThrowIfNotSameDimensions(*this, other);
11515
0
    return GDALComputedRasterBand(
11516
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
11517
0
}
11518
11519
/************************************************************************/
11520
/*                           operator-()                                */
11521
/************************************************************************/
11522
11523
/** Subtract this band with a constant.
11524
 *
11525
 * The resulting band is lazy evaluated. A reference is taken on the input
11526
 * dataset.
11527
 *
11528
 * @since 3.12
11529
 */
11530
GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
11531
0
{
11532
0
    return GDALComputedRasterBand(
11533
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
11534
0
}
11535
11536
/************************************************************************/
11537
/*                           operator-()                                */
11538
/************************************************************************/
11539
11540
/** Subtract a constant with a band.
11541
 *
11542
 * The resulting band is lazy evaluated. A reference is taken on the input
11543
 * dataset.
11544
 *
11545
 * @since 3.12
11546
 */
11547
GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
11548
0
{
11549
0
    return other * (-1.0) + constant;
11550
0
}
11551
11552
/************************************************************************/
11553
/*                           operator*()                                */
11554
/************************************************************************/
11555
11556
/** Multiply this band with another one.
11557
 *
11558
 * The resulting band is lazy evaluated. A reference is taken on both input
11559
 * datasets.
11560
 *
11561
 * @since 3.12
11562
 * @throw std::runtime_error if both bands do not have the same dimensions.
11563
 */
11564
GDALComputedRasterBand
11565
GDALRasterBand::operator*(const GDALRasterBand &other) const
11566
0
{
11567
0
    ThrowIfNotSameDimensions(*this, other);
11568
0
    return GDALComputedRasterBand(
11569
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
11570
0
}
11571
11572
/************************************************************************/
11573
/*                           operator*()                                */
11574
/************************************************************************/
11575
11576
/** Multiply this band by a constant.
11577
 *
11578
 * The resulting band is lazy evaluated. A reference is taken on the input
11579
 * dataset.
11580
 *
11581
 * @since 3.12
11582
 */
11583
GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
11584
0
{
11585
0
    return GDALComputedRasterBand(
11586
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
11587
0
}
11588
11589
/************************************************************************/
11590
/*                           operator*()                                */
11591
/************************************************************************/
11592
11593
/** Multiply a band with a constant.
11594
 *
11595
 * The resulting band is lazy evaluated. A reference is taken on the input
11596
 * dataset.
11597
 *
11598
 * @since 3.12
11599
 */
11600
GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
11601
0
{
11602
0
    return other * constant;
11603
0
}
11604
11605
/************************************************************************/
11606
/*                           operator/()                                */
11607
/************************************************************************/
11608
11609
/** Divide this band with another one.
11610
 *
11611
 * The resulting band is lazy evaluated. A reference is taken on both input
11612
 * datasets.
11613
 *
11614
 * @since 3.12
11615
 * @throw std::runtime_error if both bands do not have the same dimensions.
11616
 */
11617
GDALComputedRasterBand
11618
GDALRasterBand::operator/(const GDALRasterBand &other) const
11619
0
{
11620
0
    ThrowIfNotSameDimensions(*this, other);
11621
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11622
0
                                  *this, other);
11623
0
}
11624
11625
/************************************************************************/
11626
/*                           operator/()                                */
11627
/************************************************************************/
11628
11629
/** Divide this band by a constant.
11630
 *
11631
 * The resulting band is lazy evaluated. A reference is taken on the input
11632
 * dataset.
11633
 *
11634
 * @since 3.12
11635
 */
11636
GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
11637
0
{
11638
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11639
0
                                  *this, constant);
11640
0
}
11641
11642
/************************************************************************/
11643
/*                           operator/()                                */
11644
/************************************************************************/
11645
11646
/** Divide a constant by a band.
11647
 *
11648
 * The resulting band is lazy evaluated. A reference is taken on the input
11649
 * dataset.
11650
 *
11651
 * @since 3.12
11652
 */
11653
GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
11654
0
{
11655
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11656
0
                                  constant, other);
11657
0
}
11658
11659
/************************************************************************/
11660
/*                          ThrowIfNotMuparser()                        */
11661
/************************************************************************/
11662
11663
#ifndef HAVE_MUPARSER
11664
static GDALComputedRasterBand ThrowIfNotMuparser()
11665
0
{
11666
0
    throw std::runtime_error("Operator not available on a "
11667
0
                             "GDAL build without muparser");
11668
0
}
11669
#endif
11670
11671
/************************************************************************/
11672
/*                           operator>()                                */
11673
/************************************************************************/
11674
11675
/** Return a band whose value is 1 if the pixel value of the left operand
11676
 * is greater than the pixel value of the right operand.
11677
 *
11678
 * The resulting band is lazy evaluated. A reference is taken on the input
11679
 * dataset.
11680
 *
11681
 * @since 3.12
11682
 */
11683
GDALComputedRasterBand
11684
GDALRasterBand::operator>(const GDALRasterBand &other) const
11685
0
{
11686
0
#ifndef HAVE_MUPARSER
11687
0
    (void)other;
11688
0
    return ThrowIfNotMuparser();
11689
#else
11690
    ThrowIfNotSameDimensions(*this, other);
11691
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11692
                                  *this, other);
11693
#endif
11694
0
}
11695
11696
/************************************************************************/
11697
/*                           operator>()                                */
11698
/************************************************************************/
11699
11700
/** Return a band whose value is 1 if the pixel value of the left operand
11701
 * is greater than the constant.
11702
 *
11703
 * The resulting band is lazy evaluated. A reference is taken on the input
11704
 * dataset.
11705
 *
11706
 * @since 3.12
11707
 */
11708
GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
11709
0
{
11710
0
#ifndef HAVE_MUPARSER
11711
0
    (void)constant;
11712
0
    return ThrowIfNotMuparser();
11713
#else
11714
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11715
                                  *this, constant);
11716
#endif
11717
0
}
11718
11719
/************************************************************************/
11720
/*                           operator>()                                */
11721
/************************************************************************/
11722
11723
/** Return a band whose value is 1 if the constant is greater than the pixel
11724
 * value of the right operand.
11725
 *
11726
 * The resulting band is lazy evaluated. A reference is taken on the input
11727
 * dataset.
11728
 *
11729
 * @since 3.12
11730
 */
11731
GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
11732
0
{
11733
0
#ifndef HAVE_MUPARSER
11734
0
    (void)constant;
11735
0
    (void)other;
11736
0
    return ThrowIfNotMuparser();
11737
#else
11738
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11739
                                  constant, other);
11740
#endif
11741
0
}
11742
11743
/************************************************************************/
11744
/*                           operator>=()                               */
11745
/************************************************************************/
11746
11747
/** Return a band whose value is 1 if the pixel value of the left operand
11748
 * is greater or equal to the pixel value of the right operand.
11749
 *
11750
 * The resulting band is lazy evaluated. A reference is taken on the input
11751
 * dataset.
11752
 *
11753
 * @since 3.12
11754
 */
11755
GDALComputedRasterBand
11756
GDALRasterBand::operator>=(const GDALRasterBand &other) const
11757
0
{
11758
0
#ifndef HAVE_MUPARSER
11759
0
    (void)other;
11760
0
    return ThrowIfNotMuparser();
11761
#else
11762
    ThrowIfNotSameDimensions(*this, other);
11763
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11764
                                  *this, other);
11765
#endif
11766
0
}
11767
11768
/************************************************************************/
11769
/*                           operator>=()                               */
11770
/************************************************************************/
11771
11772
/** Return a band whose value is 1 if the pixel value of the left operand
11773
 * is greater or equal to the constant.
11774
 *
11775
 * The resulting band is lazy evaluated. A reference is taken on the input
11776
 * dataset.
11777
 *
11778
 * @since 3.12
11779
 */
11780
GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
11781
0
{
11782
0
#ifndef HAVE_MUPARSER
11783
0
    (void)constant;
11784
0
    return ThrowIfNotMuparser();
11785
#else
11786
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11787
                                  *this, constant);
11788
#endif
11789
0
}
11790
11791
/************************************************************************/
11792
/*                           operator>=()                               */
11793
/************************************************************************/
11794
11795
/** Return a band whose value is 1 if the constant is greater or equal to
11796
 * the pixel value of the right operand.
11797
 *
11798
 * The resulting band is lazy evaluated. A reference is taken on the input
11799
 * dataset.
11800
 *
11801
 * @since 3.12
11802
 */
11803
GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
11804
0
{
11805
0
#ifndef HAVE_MUPARSER
11806
0
    (void)constant;
11807
0
    (void)other;
11808
0
    return ThrowIfNotMuparser();
11809
#else
11810
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11811
                                  constant, other);
11812
#endif
11813
0
}
11814
11815
/************************************************************************/
11816
/*                           operator<()                                */
11817
/************************************************************************/
11818
11819
/** Return a band whose value is 1 if the pixel value of the left operand
11820
 * is lesser than the pixel value of the right operand.
11821
 *
11822
 * The resulting band is lazy evaluated. A reference is taken on the input
11823
 * dataset.
11824
 *
11825
 * @since 3.12
11826
 */
11827
GDALComputedRasterBand
11828
GDALRasterBand::operator<(const GDALRasterBand &other) const
11829
0
{
11830
0
#ifndef HAVE_MUPARSER
11831
0
    (void)other;
11832
0
    return ThrowIfNotMuparser();
11833
#else
11834
    ThrowIfNotSameDimensions(*this, other);
11835
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11836
                                  *this, other);
11837
#endif
11838
0
}
11839
11840
/************************************************************************/
11841
/*                           operator<()                                */
11842
/************************************************************************/
11843
11844
/** Return a band whose value is 1 if the pixel value of the left operand
11845
 * is lesser than the constant.
11846
 *
11847
 * The resulting band is lazy evaluated. A reference is taken on the input
11848
 * dataset.
11849
 *
11850
 * @since 3.12
11851
 */
11852
GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
11853
0
{
11854
0
#ifndef HAVE_MUPARSER
11855
0
    (void)constant;
11856
0
    return ThrowIfNotMuparser();
11857
#else
11858
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11859
                                  *this, constant);
11860
#endif
11861
0
}
11862
11863
/************************************************************************/
11864
/*                           operator<()                                */
11865
/************************************************************************/
11866
11867
/** Return a band whose value is 1 if the constant is lesser than the pixel
11868
 * value of the right operand.
11869
 *
11870
 * The resulting band is lazy evaluated. A reference is taken on the input
11871
 * dataset.
11872
 *
11873
 * @since 3.12
11874
 */
11875
GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
11876
0
{
11877
0
#ifndef HAVE_MUPARSER
11878
0
    (void)constant;
11879
0
    (void)other;
11880
0
    return ThrowIfNotMuparser();
11881
#else
11882
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11883
                                  constant, other);
11884
#endif
11885
0
}
11886
11887
/************************************************************************/
11888
/*                           operator<=()                               */
11889
/************************************************************************/
11890
11891
/** Return a band whose value is 1 if the pixel value of the left operand
11892
 * is lesser or equal to the pixel value of the right operand.
11893
 *
11894
 * The resulting band is lazy evaluated. A reference is taken on the input
11895
 * dataset.
11896
 *
11897
 * @since 3.12
11898
 */
11899
GDALComputedRasterBand
11900
GDALRasterBand::operator<=(const GDALRasterBand &other) const
11901
0
{
11902
0
#ifndef HAVE_MUPARSER
11903
0
    (void)other;
11904
0
    return ThrowIfNotMuparser();
11905
#else
11906
    ThrowIfNotSameDimensions(*this, other);
11907
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11908
                                  *this, other);
11909
#endif
11910
0
}
11911
11912
/************************************************************************/
11913
/*                           operator<=()                               */
11914
/************************************************************************/
11915
11916
/** Return a band whose value is 1 if the pixel value of the left operand
11917
 * is lesser or equal to the constant.
11918
 *
11919
 * The resulting band is lazy evaluated. A reference is taken on the input
11920
 * dataset.
11921
 *
11922
 * @since 3.12
11923
 */
11924
GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
11925
0
{
11926
0
#ifndef HAVE_MUPARSER
11927
0
    (void)constant;
11928
0
    return ThrowIfNotMuparser();
11929
#else
11930
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11931
                                  *this, constant);
11932
#endif
11933
0
}
11934
11935
/************************************************************************/
11936
/*                           operator<=()                               */
11937
/************************************************************************/
11938
11939
/** Return a band whose value is 1 if the constant is lesser or equal to
11940
 * the pixel value of the right operand.
11941
 *
11942
 * The resulting band is lazy evaluated. A reference is taken on the input
11943
 * dataset.
11944
 *
11945
 * @since 3.12
11946
 */
11947
GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
11948
0
{
11949
0
#ifndef HAVE_MUPARSER
11950
0
    (void)constant;
11951
0
    (void)other;
11952
0
    return ThrowIfNotMuparser();
11953
#else
11954
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11955
                                  constant, other);
11956
#endif
11957
0
}
11958
11959
/************************************************************************/
11960
/*                           operator==()                               */
11961
/************************************************************************/
11962
11963
/** Return a band whose value is 1 if the pixel value of the left operand
11964
 * is equal to the pixel value of the right operand.
11965
 *
11966
 * The resulting band is lazy evaluated. A reference is taken on the input
11967
 * dataset.
11968
 *
11969
 * @since 3.12
11970
 */
11971
GDALComputedRasterBand
11972
GDALRasterBand::operator==(const GDALRasterBand &other) const
11973
0
{
11974
0
#ifndef HAVE_MUPARSER
11975
0
    (void)other;
11976
0
    return ThrowIfNotMuparser();
11977
#else
11978
    ThrowIfNotSameDimensions(*this, other);
11979
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11980
                                  *this, other);
11981
#endif
11982
0
}
11983
11984
/************************************************************************/
11985
/*                           operator==()                               */
11986
/************************************************************************/
11987
11988
/** Return a band whose value is 1 if the pixel value of the left operand
11989
 * is equal to the constant.
11990
 *
11991
 * The resulting band is lazy evaluated. A reference is taken on the input
11992
 * dataset.
11993
 *
11994
 * @since 3.12
11995
 */
11996
GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
11997
0
{
11998
0
#ifndef HAVE_MUPARSER
11999
0
    (void)constant;
12000
0
    return ThrowIfNotMuparser();
12001
#else
12002
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12003
                                  *this, constant);
12004
#endif
12005
0
}
12006
12007
/************************************************************************/
12008
/*                           operator==()                               */
12009
/************************************************************************/
12010
12011
/** Return a band whose value is 1 if the constant is equal to
12012
 * the pixel value of the right operand.
12013
 *
12014
 * The resulting band is lazy evaluated. A reference is taken on the input
12015
 * dataset.
12016
 *
12017
 * @since 3.12
12018
 */
12019
GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12020
0
{
12021
0
#ifndef HAVE_MUPARSER
12022
0
    (void)constant;
12023
0
    (void)other;
12024
0
    return ThrowIfNotMuparser();
12025
#else
12026
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12027
                                  constant, other);
12028
#endif
12029
0
}
12030
12031
/************************************************************************/
12032
/*                           operator!=()                               */
12033
/************************************************************************/
12034
12035
/** Return a band whose value is 1 if the pixel value of the left operand
12036
 * is different from the pixel value of the right operand.
12037
 *
12038
 * The resulting band is lazy evaluated. A reference is taken on the input
12039
 * dataset.
12040
 *
12041
 * @since 3.12
12042
 */
12043
GDALComputedRasterBand
12044
GDALRasterBand::operator!=(const GDALRasterBand &other) const
12045
0
{
12046
0
#ifndef HAVE_MUPARSER
12047
0
    (void)other;
12048
0
    return ThrowIfNotMuparser();
12049
#else
12050
    ThrowIfNotSameDimensions(*this, other);
12051
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12052
                                  *this, other);
12053
#endif
12054
0
}
12055
12056
/************************************************************************/
12057
/*                           operator!=()                               */
12058
/************************************************************************/
12059
12060
/** Return a band whose value is 1 if the pixel value of the left operand
12061
 * is different from the constant.
12062
 *
12063
 * The resulting band is lazy evaluated. A reference is taken on the input
12064
 * dataset.
12065
 *
12066
 * @since 3.12
12067
 */
12068
GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12069
0
{
12070
0
#ifndef HAVE_MUPARSER
12071
0
    (void)constant;
12072
0
    return ThrowIfNotMuparser();
12073
#else
12074
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12075
                                  *this, constant);
12076
#endif
12077
0
}
12078
12079
/************************************************************************/
12080
/*                           operator!=()                               */
12081
/************************************************************************/
12082
12083
/** Return a band whose value is 1 if the constant is different from
12084
 * the pixel value of the right operand.
12085
 *
12086
 * The resulting band is lazy evaluated. A reference is taken on the input
12087
 * dataset.
12088
 *
12089
 * @since 3.12
12090
 */
12091
GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12092
0
{
12093
0
#ifndef HAVE_MUPARSER
12094
0
    (void)constant;
12095
0
    (void)other;
12096
0
    return ThrowIfNotMuparser();
12097
#else
12098
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12099
                                  constant, other);
12100
#endif
12101
0
}
12102
12103
#if defined(__GNUC__)
12104
#pragma GCC diagnostic push
12105
#pragma GCC diagnostic ignored "-Weffc++"
12106
#endif
12107
12108
/************************************************************************/
12109
/*                           operator&&()                               */
12110
/************************************************************************/
12111
12112
/** Return a band whose value is 1 if the pixel value of the left and right
12113
 * operands is true.
12114
 *
12115
 * The resulting band is lazy evaluated. A reference is taken on the input
12116
 * dataset.
12117
 *
12118
 * @since 3.12
12119
 */
12120
GDALComputedRasterBand
12121
GDALRasterBand::operator&&(const GDALRasterBand &other) const
12122
0
{
12123
0
#ifndef HAVE_MUPARSER
12124
0
    (void)other;
12125
0
    return ThrowIfNotMuparser();
12126
#else
12127
    ThrowIfNotSameDimensions(*this, other);
12128
    return GDALComputedRasterBand(
12129
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
12130
#endif
12131
0
}
12132
12133
/************************************************************************/
12134
/*                           operator&&()                               */
12135
/************************************************************************/
12136
12137
/** Return a band whose value is 1 if the pixel value of the left operand
12138
 * is true, as well as the constant
12139
 *
12140
 * The resulting band is lazy evaluated. A reference is taken on the input
12141
 * dataset.
12142
 *
12143
 * @since 3.12
12144
 */
12145
GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12146
0
{
12147
0
#ifndef HAVE_MUPARSER
12148
0
    (void)constant;
12149
0
    return ThrowIfNotMuparser();
12150
#else
12151
    return GDALComputedRasterBand(
12152
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
12153
#endif
12154
0
}
12155
12156
/************************************************************************/
12157
/*                           operator&&()                               */
12158
/************************************************************************/
12159
12160
/** Return a band whose value is 1 if the constant is true, as well as
12161
 * the pixel value of the right operand.
12162
 *
12163
 * The resulting band is lazy evaluated. A reference is taken on the input
12164
 * dataset.
12165
 *
12166
 * @since 3.12
12167
 */
12168
GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12169
0
{
12170
0
#ifndef HAVE_MUPARSER
12171
0
    (void)constant;
12172
0
    (void)other;
12173
0
    return ThrowIfNotMuparser();
12174
#else
12175
    return GDALComputedRasterBand(
12176
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
12177
#endif
12178
0
}
12179
12180
/************************************************************************/
12181
/*                           operator||()                               */
12182
/************************************************************************/
12183
12184
/** Return a band whose value is 1 if the pixel value of the left or right
12185
 * operands is true.
12186
 *
12187
 * The resulting band is lazy evaluated. A reference is taken on the input
12188
 * dataset.
12189
 *
12190
 * @since 3.12
12191
 */
12192
GDALComputedRasterBand
12193
GDALRasterBand::operator||(const GDALRasterBand &other) const
12194
0
{
12195
0
#ifndef HAVE_MUPARSER
12196
0
    (void)other;
12197
0
    return ThrowIfNotMuparser();
12198
#else
12199
    ThrowIfNotSameDimensions(*this, other);
12200
    return GDALComputedRasterBand(
12201
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
12202
#endif
12203
0
}
12204
12205
/************************************************************************/
12206
/*                           operator||()                               */
12207
/************************************************************************/
12208
12209
/** Return a band whose value is 1 if the pixel value of the left operand
12210
 * is true, or if the constant is true
12211
 *
12212
 * The resulting band is lazy evaluated. A reference is taken on the input
12213
 * dataset.
12214
 *
12215
 * @since 3.12
12216
 */
12217
GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12218
0
{
12219
0
#ifndef HAVE_MUPARSER
12220
0
    (void)constant;
12221
0
    return ThrowIfNotMuparser();
12222
#else
12223
    return GDALComputedRasterBand(
12224
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
12225
#endif
12226
0
}
12227
12228
/************************************************************************/
12229
/*                           operator||()                               */
12230
/************************************************************************/
12231
12232
/** Return a band whose value is 1 if the constant is true, or
12233
 * the pixel value of the right operand is true
12234
 *
12235
 * The resulting band is lazy evaluated. A reference is taken on the input
12236
 * dataset.
12237
 *
12238
 * @since 3.12
12239
 */
12240
GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12241
0
{
12242
0
#ifndef HAVE_MUPARSER
12243
0
    (void)constant;
12244
0
    (void)other;
12245
0
    return ThrowIfNotMuparser();
12246
#else
12247
    return GDALComputedRasterBand(
12248
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
12249
#endif
12250
0
}
12251
12252
#if defined(__GNUC__)
12253
#pragma GCC diagnostic pop
12254
#endif
12255
12256
/************************************************************************/
12257
/*                            operator!()                               */
12258
/************************************************************************/
12259
12260
/** Return a band whose value is the logical negation of the pixel value
12261
 *
12262
 * The resulting band is lazy evaluated. A reference is taken on the input
12263
 * dataset.
12264
 *
12265
 * @since 3.12
12266
 */
12267
GDALComputedRasterBand GDALRasterBand::operator!() const
12268
0
{
12269
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12270
0
                                  *this, true);
12271
0
}
12272
12273
namespace gdal
12274
{
12275
12276
/************************************************************************/
12277
/*                           IfThenElse()                               */
12278
/************************************************************************/
12279
12280
/** Return a band whose value is thenBand if the corresponding pixel in condBand
12281
 * is not zero, or the one from elseBand otherwise.
12282
 *
12283
 * Variants of this method exits where thenBand and/or elseBand can be double
12284
 * values.
12285
 *
12286
 * The resulting band is lazy evaluated. A reference is taken on the input
12287
 * datasets.
12288
 *
12289
 * This method is the same as the C function GDALRasterBandIfThenElse()
12290
 *
12291
 * @since 3.12
12292
 */
12293
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12294
                                  const GDALRasterBand &thenBand,
12295
                                  const GDALRasterBand &elseBand)
12296
0
{
12297
0
#ifndef HAVE_MUPARSER
12298
0
    (void)condBand;
12299
0
    (void)thenBand;
12300
0
    (void)elseBand;
12301
0
    return ThrowIfNotMuparser();
12302
#else
12303
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12304
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12305
    return GDALComputedRasterBand(
12306
        GDALComputedRasterBand::Operation::OP_TERNARY,
12307
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12308
#endif
12309
0
}
12310
12311
//! @cond Doxygen_Suppress
12312
12313
/************************************************************************/
12314
/*                           IfThenElse()                               */
12315
/************************************************************************/
12316
12317
/** Return a band whose value is thenValue if the corresponding pixel in condBand
12318
 * is not zero, or the one from elseBand otherwise.
12319
 *
12320
 * The resulting band is lazy evaluated. A reference is taken on the input
12321
 * datasets.
12322
 *
12323
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12324
 * with thenBand = (condBand * 0) + thenValue
12325
 *
12326
 * @since 3.12
12327
 */
12328
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12329
                                  double thenValue,
12330
                                  const GDALRasterBand &elseBand)
12331
0
{
12332
0
#ifndef HAVE_MUPARSER
12333
0
    (void)condBand;
12334
0
    (void)thenValue;
12335
0
    (void)elseBand;
12336
0
    return ThrowIfNotMuparser();
12337
#else
12338
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12339
    auto thenBand =
12340
        (condBand * 0)
12341
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12342
        thenValue;
12343
    return GDALComputedRasterBand(
12344
        GDALComputedRasterBand::Operation::OP_TERNARY,
12345
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12346
#endif
12347
0
}
12348
12349
/************************************************************************/
12350
/*                           IfThenElse()                               */
12351
/************************************************************************/
12352
12353
/** Return a band whose value is thenBand if the corresponding pixel in condBand
12354
 * is not zero, or the one from elseValue otherwise.
12355
 *
12356
 * The resulting band is lazy evaluated. A reference is taken on the input
12357
 * datasets.
12358
 *
12359
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12360
 * with elseBand = (condBand * 0) + elseValue
12361
12362
 * @since 3.12
12363
 */
12364
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12365
                                  const GDALRasterBand &thenBand,
12366
                                  double elseValue)
12367
0
{
12368
0
#ifndef HAVE_MUPARSER
12369
0
    (void)condBand;
12370
0
    (void)thenBand;
12371
0
    (void)elseValue;
12372
0
    return ThrowIfNotMuparser();
12373
#else
12374
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12375
    auto elseBand =
12376
        (condBand * 0)
12377
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12378
        elseValue;
12379
    return GDALComputedRasterBand(
12380
        GDALComputedRasterBand::Operation::OP_TERNARY,
12381
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12382
#endif
12383
0
}
12384
12385
/************************************************************************/
12386
/*                           IfThenElse()                               */
12387
/************************************************************************/
12388
12389
/** Return a band whose value is thenValue if the corresponding pixel in condBand
12390
 * is not zero, or the one from elseValue otherwise.
12391
 *
12392
 * The resulting band is lazy evaluated. A reference is taken on the input
12393
 * datasets.
12394
 *
12395
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12396
 * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12397
 *
12398
 * @since 3.12
12399
 */
12400
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12401
                                  double thenValue, double elseValue)
12402
0
{
12403
0
#ifndef HAVE_MUPARSER
12404
0
    (void)condBand;
12405
0
    (void)thenValue;
12406
0
    (void)elseValue;
12407
0
    return ThrowIfNotMuparser();
12408
#else
12409
    auto thenBand =
12410
        (condBand * 0)
12411
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12412
        thenValue;
12413
    auto elseBand =
12414
        (condBand * 0)
12415
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12416
        elseValue;
12417
    return GDALComputedRasterBand(
12418
        GDALComputedRasterBand::Operation::OP_TERNARY,
12419
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12420
#endif
12421
0
}
12422
12423
//! @endcond
12424
12425
}  // namespace gdal
12426
12427
/************************************************************************/
12428
/*                     GDALRasterBandIfThenElse()                       */
12429
/************************************************************************/
12430
12431
/** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12432
 * is not zero, or the one from hElseBand otherwise.
12433
 *
12434
 * The resulting band is lazy evaluated. A reference is taken on the input
12435
 * datasets.
12436
 *
12437
 * This function is the same as the C++ method gdal::IfThenElse()
12438
 *
12439
 * @since 3.12
12440
 */
12441
GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12442
                                                 GDALRasterBandH hThenBand,
12443
                                                 GDALRasterBandH hElseBand)
12444
0
{
12445
0
    VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12446
0
    VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12447
0
    VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12448
0
#ifndef HAVE_MUPARSER
12449
0
    CPLError(CE_Failure, CPLE_NotSupported,
12450
0
             "Band comparison operators not available on a GDAL build without "
12451
0
             "muparser");
12452
0
    return nullptr;
12453
#else
12454
12455
    auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12456
    auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12457
    auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12458
    try
12459
    {
12460
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12461
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12462
    }
12463
    catch (const std::exception &e)
12464
    {
12465
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12466
        return nullptr;
12467
    }
12468
    return new GDALComputedRasterBand(
12469
        GDALComputedRasterBand::Operation::OP_TERNARY,
12470
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12471
#endif
12472
0
}
12473
12474
/************************************************************************/
12475
/*                       GDALRasterBand::AsType()                       */
12476
/************************************************************************/
12477
12478
/** Cast this band to another type.
12479
 *
12480
 * The resulting band is lazy evaluated. A reference is taken on the input
12481
 * dataset.
12482
 *
12483
 * This method is the same as the C function GDALRasterBandAsDataType()
12484
 *
12485
 * @since 3.12
12486
 */
12487
GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
12488
0
{
12489
0
    if (dt == GDT_Unknown)
12490
0
    {
12491
0
        throw std::runtime_error("AsType(GDT_Unknown) is not supported");
12492
0
    }
12493
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
12494
0
                                  *this, dt);
12495
0
}
12496
12497
/************************************************************************/
12498
/*                       GDALRasterBandAsDataType()                     */
12499
/************************************************************************/
12500
12501
/** Cast this band to another type.
12502
 *
12503
 * The resulting band is lazy evaluated. A reference is taken on the input
12504
 * dataset.
12505
 *
12506
 * This function is the same as the C++ method GDALRasterBand::AsType()
12507
 *
12508
 * @since 3.12
12509
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12510
 */
12511
GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
12512
                                                 GDALDataType eDT)
12513
0
{
12514
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
12515
0
    if (eDT == GDT_Unknown)
12516
0
    {
12517
0
        CPLError(CE_Failure, CPLE_NotSupported,
12518
0
                 "GDALRasterBandAsDataType(GDT_Unknown) not supported");
12519
0
        return nullptr;
12520
0
    }
12521
0
    return new GDALComputedRasterBand(
12522
0
        GDALComputedRasterBand::Operation::OP_CAST,
12523
0
        *(GDALRasterBand::FromHandle(hBand)), eDT);
12524
0
}
12525
12526
/************************************************************************/
12527
/*                         GetBandVector()                              */
12528
/************************************************************************/
12529
12530
static std::vector<const GDALRasterBand *>
12531
GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
12532
0
{
12533
0
    std::vector<const GDALRasterBand *> bands;
12534
0
    for (size_t i = 0; i < nBandCount; ++i)
12535
0
    {
12536
0
        if (i > 0)
12537
0
        {
12538
0
            GDALRasterBand::ThrowIfNotSameDimensions(
12539
0
                *(GDALRasterBand::FromHandle(pahBands[0])),
12540
0
                *(GDALRasterBand::FromHandle(pahBands[i])));
12541
0
        }
12542
0
        bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
12543
0
    }
12544
0
    return bands;
12545
0
}
12546
12547
/************************************************************************/
12548
/*                       GDALOperationOnNBands()                        */
12549
/************************************************************************/
12550
12551
static GDALComputedRasterBandH
12552
GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
12553
                      GDALRasterBandH *pahBands)
12554
0
{
12555
0
    VALIDATE_POINTER1(pahBands, __func__, nullptr);
12556
0
    if (nBandCount == 0)
12557
0
    {
12558
0
        CPLError(CE_Failure, CPLE_AppDefined,
12559
0
                 "At least one band should be passed");
12560
0
        return nullptr;
12561
0
    }
12562
12563
0
    std::vector<const GDALRasterBand *> bands;
12564
0
    try
12565
0
    {
12566
0
        bands = GetBandVector(nBandCount, pahBands);
12567
0
    }
12568
0
    catch (const std::exception &e)
12569
0
    {
12570
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12571
0
        return nullptr;
12572
0
    }
12573
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
12574
0
}
12575
12576
/************************************************************************/
12577
/*                       GDALMaximumOfNBands()                          */
12578
/************************************************************************/
12579
12580
/** Return a band whose each pixel value is the maximum of the corresponding
12581
 * pixel values in the input bands.
12582
 *
12583
 * The resulting band is lazy evaluated. A reference is taken on input
12584
 * datasets.
12585
 *
12586
 * This function is the same as the C ++ method gdal::max()
12587
 *
12588
 * @since 3.12
12589
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12590
 */
12591
GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
12592
                                            GDALRasterBandH *pahBands)
12593
0
{
12594
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
12595
0
                                 nBandCount, pahBands);
12596
0
}
12597
12598
/************************************************************************/
12599
/*                               gdal::max()                            */
12600
/************************************************************************/
12601
12602
namespace gdal
12603
{
12604
/** Return a band whose each pixel value is the maximum of the corresponding
12605
 * pixel values in the inputs (bands or constants)
12606
 *
12607
 * The resulting band is lazy evaluated. A reference is taken on input
12608
 * datasets.
12609
 *
12610
 * Two or more bands can be passed.
12611
 *
12612
 * This method is the same as the C function GDALMaximumOfNBands()
12613
 *
12614
 * @since 3.12
12615
 * @throw std::runtime_error if bands do not have the same dimensions.
12616
 */
12617
GDALComputedRasterBand max(const GDALRasterBand &first,
12618
                           const GDALRasterBand &second)
12619
0
{
12620
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12621
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
12622
0
                                  first, second);
12623
0
}
12624
}  // namespace gdal
12625
12626
/************************************************************************/
12627
/*                     GDALRasterBandMaxConstant()                      */
12628
/************************************************************************/
12629
12630
/** Return a band whose each pixel value is the maximum of the corresponding
12631
 * pixel values in the input band and the constant.
12632
 *
12633
 * The resulting band is lazy evaluated. A reference is taken on the input
12634
 * dataset.
12635
 *
12636
 * This function is the same as the C ++ method gdal::max()
12637
 *
12638
 * @since 3.12
12639
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12640
 */
12641
GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
12642
                                                  double dfConstant)
12643
0
{
12644
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
12645
0
        GDALComputedRasterBand::Operation::OP_MAX,
12646
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
12647
0
        dfConstant));
12648
0
}
12649
12650
/************************************************************************/
12651
/*                       GDALMinimumOfNBands()                          */
12652
/************************************************************************/
12653
12654
/** Return a band whose each pixel value is the minimum of the corresponding
12655
 * pixel values in the input bands.
12656
 *
12657
 * The resulting band is lazy evaluated. A reference is taken on input
12658
 * datasets.
12659
 *
12660
 * This function is the same as the C ++ method gdal::min()
12661
 *
12662
 * @since 3.12
12663
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12664
 */
12665
GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
12666
                                            GDALRasterBandH *pahBands)
12667
0
{
12668
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
12669
0
                                 nBandCount, pahBands);
12670
0
}
12671
12672
/************************************************************************/
12673
/*                               gdal::min()                            */
12674
/************************************************************************/
12675
12676
namespace gdal
12677
{
12678
/** Return a band whose each pixel value is the minimum of the corresponding
12679
 * pixel values in the inputs (bands or constants)
12680
 *
12681
 * The resulting band is lazy evaluated. A reference is taken on input
12682
 * datasets.
12683
 *
12684
 * Two or more bands can be passed.
12685
 *
12686
 * This method is the same as the C function GDALMinimumOfNBands()
12687
 *
12688
 * @since 3.12
12689
 * @throw std::runtime_error if bands do not have the same dimensions.
12690
 */
12691
GDALComputedRasterBand min(const GDALRasterBand &first,
12692
                           const GDALRasterBand &second)
12693
0
{
12694
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12695
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
12696
0
                                  first, second);
12697
0
}
12698
}  // namespace gdal
12699
12700
/************************************************************************/
12701
/*                     GDALRasterBandMinConstant()                      */
12702
/************************************************************************/
12703
12704
/** Return a band whose each pixel value is the minimum of the corresponding
12705
 * pixel values in the input band and the constant.
12706
 *
12707
 * The resulting band is lazy evaluated. A reference is taken on the input
12708
 * dataset.
12709
 *
12710
 * This function is the same as the C ++ method gdal::min()
12711
 *
12712
 * @since 3.12
12713
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12714
 */
12715
GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
12716
                                                  double dfConstant)
12717
0
{
12718
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
12719
0
        GDALComputedRasterBand::Operation::OP_MIN,
12720
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
12721
0
        dfConstant));
12722
0
}
12723
12724
/************************************************************************/
12725
/*                         GDALMeanOfNBands()                           */
12726
/************************************************************************/
12727
12728
/** Return a band whose each pixel value is the arithmetic mean of the
12729
 * corresponding pixel values in the input bands.
12730
 *
12731
 * The resulting band is lazy evaluated. A reference is taken on input
12732
 * datasets.
12733
 *
12734
 * This function is the same as the C ++ method gdal::mean()
12735
 *
12736
 * @since 3.12
12737
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12738
 */
12739
GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
12740
                                         GDALRasterBandH *pahBands)
12741
0
{
12742
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
12743
0
                                 nBandCount, pahBands);
12744
0
}
12745
12746
/************************************************************************/
12747
/*                              gdal::mean()                            */
12748
/************************************************************************/
12749
12750
namespace gdal
12751
{
12752
12753
/** Return a band whose each pixel value is the arithmetic mean of the
12754
 * corresponding pixel values in the input bands.
12755
 *
12756
 * The resulting band is lazy evaluated. A reference is taken on input
12757
 * datasets.
12758
 *
12759
 * Two or more bands can be passed.
12760
 *
12761
 * This method is the same as the C function GDALMeanOfNBands()
12762
 *
12763
 * @since 3.12
12764
 * @throw std::runtime_error if bands do not have the same dimensions.
12765
 */
12766
GDALComputedRasterBand mean(const GDALRasterBand &first,
12767
                            const GDALRasterBand &second)
12768
0
{
12769
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12770
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
12771
0
                                  first, second);
12772
0
}
12773
}  // namespace gdal
12774
12775
/************************************************************************/
12776
/*                              gdal::abs()                             */
12777
/************************************************************************/
12778
12779
namespace gdal
12780
{
12781
12782
/** Return a band whose each pixel value is the absolute value (or module
12783
 * for complex data type) of the corresponding pixel value in the input band.
12784
 *
12785
 * The resulting band is lazy evaluated. A reference is taken on input
12786
 * datasets.
12787
 *
12788
 * @since 3.12
12789
 */
12790
GDALComputedRasterBand abs(const GDALRasterBand &band)
12791
0
{
12792
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12793
0
                                  band);
12794
0
}
12795
}  // namespace gdal
12796
12797
/************************************************************************/
12798
/*                             gdal::fabs()                             */
12799
/************************************************************************/
12800
12801
namespace gdal
12802
{
12803
12804
/** Return a band whose each pixel value is the absolute value (or module
12805
 * for complex data type) of the corresponding pixel value in the input band.
12806
 *
12807
 * The resulting band is lazy evaluated. A reference is taken on input
12808
 * datasets.
12809
 *
12810
 * @since 3.12
12811
 */
12812
GDALComputedRasterBand fabs(const GDALRasterBand &band)
12813
0
{
12814
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12815
0
                                  band);
12816
0
}
12817
}  // namespace gdal
12818
12819
/************************************************************************/
12820
/*                             gdal::sqrt()                             */
12821
/************************************************************************/
12822
12823
namespace gdal
12824
{
12825
12826
/** Return a band whose each pixel value is the square root of the
12827
 * corresponding pixel value in the input band.
12828
 *
12829
 * The resulting band is lazy evaluated. A reference is taken on input
12830
 * datasets.
12831
 *
12832
 * @since 3.12
12833
 */
12834
GDALComputedRasterBand sqrt(const GDALRasterBand &band)
12835
0
{
12836
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
12837
0
                                  band);
12838
0
}
12839
}  // namespace gdal
12840
12841
/************************************************************************/
12842
/*                             gdal::log()                              */
12843
/************************************************************************/
12844
12845
namespace gdal
12846
{
12847
12848
/** Return a band whose each pixel value is the natural logarithm of the
12849
 * corresponding pixel value in the input band.
12850
 *
12851
 * The resulting band is lazy evaluated. A reference is taken on input
12852
 * datasets.
12853
 *
12854
 * @since 3.12
12855
 */
12856
GDALComputedRasterBand log(const GDALRasterBand &band)
12857
0
{
12858
0
#ifndef HAVE_MUPARSER
12859
0
    (void)band;
12860
0
    return ThrowIfNotMuparser();
12861
#else
12862
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
12863
                                  band);
12864
#endif
12865
0
}
12866
}  // namespace gdal
12867
12868
/************************************************************************/
12869
/*                             gdal::log10()                            */
12870
/************************************************************************/
12871
12872
namespace gdal
12873
{
12874
12875
/** Return a band whose each pixel value is the logarithm base 10 of the
12876
 * corresponding pixel value in the input band.
12877
 *
12878
 * The resulting band is lazy evaluated. A reference is taken on input
12879
 * datasets.
12880
 *
12881
 * @since 3.12
12882
 */
12883
GDALComputedRasterBand log10(const GDALRasterBand &band)
12884
0
{
12885
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
12886
0
                                  band);
12887
0
}
12888
}  // namespace gdal
12889
12890
/************************************************************************/
12891
/*                             gdal::pow()                              */
12892
/************************************************************************/
12893
12894
namespace gdal
12895
{
12896
12897
#ifndef DOXYGEN_SKIP
12898
/** Return a band whose each pixel value is the constant raised to the power of
12899
 * the corresponding pixel value in the input band.
12900
 *
12901
 * The resulting band is lazy evaluated. A reference is taken on input
12902
 * datasets.
12903
 *
12904
 * @since 3.12
12905
 */
12906
GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
12907
0
{
12908
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12909
0
                                  constant, band);
12910
0
}
12911
#endif
12912
12913
}  // namespace gdal
12914
12915
/************************************************************************/
12916
/*                             gdal::pow()                              */
12917
/************************************************************************/
12918
12919
namespace gdal
12920
{
12921
12922
/** Return a band whose each pixel value is the the corresponding pixel value
12923
 * in the input band raised to the power of the constant.
12924
 *
12925
 * The resulting band is lazy evaluated. A reference is taken on input
12926
 * datasets.
12927
 *
12928
 * @since 3.12
12929
 */
12930
GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
12931
0
{
12932
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12933
0
                                  band, constant);
12934
0
}
12935
}  // namespace gdal
12936
12937
/************************************************************************/
12938
/*                             gdal::pow()                              */
12939
/************************************************************************/
12940
12941
namespace gdal
12942
{
12943
12944
#ifndef DOXYGEN_SKIP
12945
/** Return a band whose each pixel value is the the corresponding pixel value
12946
 * in the input band1 raised to the power of the corresponding pixel value
12947
 * in the input band2
12948
 *
12949
 * The resulting band is lazy evaluated. A reference is taken on input
12950
 * datasets.
12951
 *
12952
 * @since 3.12
12953
 * @throw std::runtime_error if bands do not have the same dimensions.
12954
 */
12955
GDALComputedRasterBand pow(const GDALRasterBand &band1,
12956
                           const GDALRasterBand &band2)
12957
0
{
12958
0
#ifndef HAVE_MUPARSER
12959
0
    (void)band1;
12960
0
    (void)band2;
12961
0
    return ThrowIfNotMuparser();
12962
#else
12963
    GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
12964
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12965
                                  band1, band2);
12966
#endif
12967
0
}
12968
#endif
12969
}  // namespace gdal