Coverage Report

Created: 2025-06-13 06:29

/src/gdal/gcore/gdalrasterband.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Base class for format specific band class implementation.  This
5
 *           base class provides default implementation for many methods.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 1998, Frank Warmerdam
10
 * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14
15
#include "cpl_port.h"
16
#include "cpl_float.h"
17
#include "gdal_priv.h"
18
19
#include <climits>
20
#include <cmath>
21
#include <cstdarg>
22
#include <cstddef>
23
#include <cstdio>
24
#include <cstdlib>
25
#include <cstring>
26
#include <algorithm>
27
#include <limits>
28
#include <memory>
29
#include <new>
30
#include <type_traits>
31
32
#include "cpl_conv.h"
33
#include "cpl_error.h"
34
#include "cpl_float.h"
35
#include "cpl_progress.h"
36
#include "cpl_string.h"
37
#include "cpl_virtualmem.h"
38
#include "cpl_vsi.h"
39
#include "gdal.h"
40
#include "gdal_rat.h"
41
#include "gdal_priv_templates.hpp"
42
#include "gdal_interpolateatpoint.h"
43
#include "gdal_minmax_element.hpp"
44
45
/************************************************************************/
46
/*                           GDALRasterBand()                           */
47
/************************************************************************/
48
49
/*! Constructor. Applications should never create GDALRasterBands directly. */
50
51
GDALRasterBand::GDALRasterBand()
52
0
    : GDALRasterBand(
53
0
          CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
54
0
{
55
0
}
56
57
/** Constructor. Applications should never create GDALRasterBands directly.
58
 * @param bForceCachedIOIn Whether cached IO should be forced.
59
 */
60
GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
61
0
    : bForceCachedIO(bForceCachedIOIn)
62
63
0
{
64
0
}
65
66
/************************************************************************/
67
/*                          ~GDALRasterBand()                           */
68
/************************************************************************/
69
70
/*! Destructor. Applications should never destroy GDALRasterBands directly,
71
    instead destroy the GDALDataset. */
72
73
GDALRasterBand::~GDALRasterBand()
74
75
0
{
76
0
    if (poDS && poDS->IsMarkedSuppressOnClose())
77
0
    {
78
0
        if (poBandBlockCache)
79
0
            poBandBlockCache->DisableDirtyBlockWriting();
80
0
    }
81
0
    GDALRasterBand::FlushCache(true);
82
83
0
    delete poBandBlockCache;
84
85
0
    if (static_cast<GIntBig>(nBlockReads) >
86
0
            static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
87
0
        nBand == 1 && poDS != nullptr)
88
0
    {
89
0
        CPLDebug(
90
0
            "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
91
0
            nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
92
0
            poDS->GetDescription());
93
0
    }
94
95
0
    InvalidateMaskBand();
96
0
    nBand = -nBand;
97
98
0
    delete m_poPointsCache;
99
0
}
100
101
/************************************************************************/
102
/*                              RasterIO()                              */
103
/************************************************************************/
104
105
/**
106
 * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
107
 *                                int nXOff, int nYOff, int nXSize, int nYSize,
108
 *                                void * pData, int nBufXSize, int nBufYSize,
109
 *                                GDALDataType eBufType,
110
 *                                GSpacing nPixelSpace,
111
 *                                GSpacing nLineSpace,
112
 *                                GDALRasterIOExtraArg* psExtraArg )
113
 * \brief Read/write a region of image data for this band.
114
 *
115
 * This method allows reading a region of a GDALRasterBand into a buffer,
116
 * or writing data from a buffer into a region of a GDALRasterBand. It
117
 * automatically takes care of data type translation if the data type
118
 * (eBufType) of the buffer is different than that of the GDALRasterBand.
119
 * The method also takes care of image decimation / replication if the
120
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
121
 * region being accessed (nXSize x nYSize).
122
 *
123
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
124
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
125
 * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
126
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
127
 * Or use nLineSpace and a possibly shifted pData value.
128
 *
129
 * The nPixelSpace and nLineSpace parameters allow reading into or
130
 * writing from unusually organized buffers. This is primarily used
131
 * for buffers containing more than one bands raster data in interleaved
132
 * format.
133
 *
134
 * Some formats may efficiently implement decimation into a buffer by
135
 * reading from lower resolution overview images. The logic of the default
136
 * implementation in the base class GDALRasterBand is the following one. It
137
 * computes a target_downscaling_factor from the window of interest and buffer
138
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
139
 * It then walks through overviews and will select the first one whose
140
 * downscaling factor is greater than target_downscaling_factor / 1.2.
141
 *
142
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
143
 * The relationship between target_downscaling_factor and the select overview
144
 * level is the following one:
145
 *
146
 * target_downscaling_factor  | selected_overview
147
 * -------------------------  | -----------------
148
 * ]0,       2 / 1.2]         | full resolution band
149
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
150
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
151
 * ]8 / 1.2, infinity[        | 8x downsampled band
152
 *
153
 * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
154
 * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
155
 * option. Also note that starting with GDAL 3.9, when the resampling algorithm
156
 * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
157
 * this oversampling threshold defaults to 1. Consequently if there are overviews
158
 * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
159
 * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
160
 *
161
 * For highest performance full resolution data access, read and write
162
 * on "block boundaries" as returned by GetBlockSize(), or use the
163
 * ReadBlock() and WriteBlock() methods.
164
 *
165
 * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
166
 * functions.
167
 *
168
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
169
 * write a region of data.
170
 *
171
 * @param nXOff The pixel offset to the top left corner of the region
172
 * of the band to be accessed. This would be zero to start from the left side.
173
 *
174
 * @param nYOff The line offset to the top left corner of the region
175
 * of the band to be accessed. This would be zero to start from the top.
176
 *
177
 * @param nXSize The width of the region of the band to be accessed in pixels.
178
 *
179
 * @param nYSize The height of the region of the band to be accessed in lines.
180
 *
181
 * @param pData The buffer into which the data should be read, or from which
182
 * it should be written. This buffer must contain at least nBufXSize *
183
 * nBufYSize words of type eBufType. It is organized in left to right,
184
 * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
185
 * and nLineSpace parameters.
186
 * Note that even with eRWFlag==GF_Write, the content of the buffer might be
187
 * temporarily modified during the execution of this method (and eventually
188
 * restored back to its original content), so it is not safe to use a buffer
189
 * stored in a read-only section of the calling program.
190
 *
191
 * @param nBufXSize the width of the buffer image into which the desired region
192
 * is to be read, or from which it is to be written.
193
 *
194
 * @param nBufYSize the height of the buffer image into which the desired region
195
 * is to be read, or from which it is to be written.
196
 *
197
 * @param eBufType the type of the pixel values in the pData data buffer. The
198
 * pixel values will automatically be translated to/from the GDALRasterBand
199
 * data type as needed. Most driver implementations will use GDALCopyWords64()
200
 * to perform data type translation.
201
 *
202
 * @param nPixelSpace The byte offset from the start of one pixel value in
203
 * pData to the start of the next pixel value within a scanline. If defaulted
204
 * (0) the size of the datatype eBufType is used.
205
 *
206
 * @param nLineSpace The byte offset from the start of one scanline in
207
 * pData to the start of the next. If defaulted (0) the size of the datatype
208
 * eBufType * nBufXSize is used.
209
 *
210
 * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
211
 * structure with additional arguments to specify resampling and progress
212
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
213
 * configuration option can also be defined to override the default resampling
214
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
215
 *
216
 * @return CE_Failure if the access fails, otherwise CE_None.
217
 */
218
219
/**
220
 * \brief Read/write a region of image data for this band.
221
 *
222
 * This method allows reading a region of a GDALRasterBand into a buffer,
223
 * or writing data from a buffer into a region of a GDALRasterBand. It
224
 * automatically takes care of data type translation if the data type
225
 * (eBufType) of the buffer is different than that of the GDALRasterBand.
226
 * The method also takes care of image decimation / replication if the
227
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
228
 * region being accessed (nXSize x nYSize).
229
 *
230
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
231
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
232
 * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
233
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
234
 * Or use nLineSpace and a possibly shifted pData value.
235
 *
236
 * The nPixelSpace and nLineSpace parameters allow reading into or
237
 * writing from unusually organized buffers. This is primarily used
238
 * for buffers containing more than one bands raster data in interleaved
239
 * format.
240
 *
241
 * Some formats may efficiently implement decimation into a buffer by
242
 * reading from lower resolution overview images. The logic of the default
243
 * implementation in the base class GDALRasterBand is the following one. It
244
 * computes a target_downscaling_factor from the window of interest and buffer
245
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
246
 * It then walks through overviews and will select the first one whose
247
 * downscaling factor is greater than target_downscaling_factor / 1.2.
248
 *
249
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
250
 * The relationship between target_downscaling_factor and the select overview
251
 * level is the following one:
252
 *
253
 * target_downscaling_factor  | selected_overview
254
 * -------------------------  | -----------------
255
 * ]0,       2 / 1.2]         | full resolution band
256
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
257
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
258
 * ]8 / 1.2, infinity[        | 8x downsampled band
259
 *
260
 * For highest performance full resolution data access, read and write
261
 * on "block boundaries" as returned by GetBlockSize(), or use the
262
 * ReadBlock() and WriteBlock() methods.
263
 *
264
 * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
265
 * functions.
266
 *
267
 * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
268
 * more convenient to use for most common use cases.
269
 *
270
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
271
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
272
 * instance of this dataset) concurrently from several threads.
273
 *
274
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
275
 * write a region of data.
276
 *
277
 * @param nXOff The pixel offset to the top left corner of the region
278
 * of the band to be accessed. This would be zero to start from the left side.
279
 *
280
 * @param nYOff The line offset to the top left corner of the region
281
 * of the band to be accessed. This would be zero to start from the top.
282
 *
283
 * @param nXSize The width of the region of the band to be accessed in pixels.
284
 *
285
 * @param nYSize The height of the region of the band to be accessed in lines.
286
 *
287
 * @param[in,out] pData The buffer into which the data should be read, or from
288
 * which it should be written. This buffer must contain at least nBufXSize *
289
 * nBufYSize words of type eBufType. It is organized in left to right,
290
 * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
291
 * and nLineSpace parameters.
292
 *
293
 * @param nBufXSize the width of the buffer image into which the desired region
294
 * is to be read, or from which it is to be written.
295
 *
296
 * @param nBufYSize the height of the buffer image into which the desired region
297
 * is to be read, or from which it is to be written.
298
 *
299
 * @param eBufType the type of the pixel values in the pData data buffer. The
300
 * pixel values will automatically be translated to/from the GDALRasterBand
301
 * data type as needed.
302
 *
303
 * @param nPixelSpace The byte offset from the start of one pixel value in
304
 * pData to the start of the next pixel value within a scanline. If defaulted
305
 * (0) the size of the datatype eBufType is used.
306
 *
307
 * @param nLineSpace The byte offset from the start of one scanline in
308
 * pData to the start of the next. If defaulted (0) the size of the datatype
309
 * eBufType * nBufXSize is used.
310
 *
311
 * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
312
 * structure with additional arguments to specify resampling and progress
313
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
314
 * configuration option can also be defined to override the default resampling
315
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
316
 *
317
 * @return CE_Failure if the access fails, otherwise CE_None.
318
 *
319
 * @see GDALRasterBand::ReadRaster()
320
 */
321
322
CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
323
                                int nXSize, int nYSize, void *pData,
324
                                int nBufXSize, int nBufYSize,
325
                                GDALDataType eBufType, GSpacing nPixelSpace,
326
                                GSpacing nLineSpace,
327
                                GDALRasterIOExtraArg *psExtraArg)
328
329
0
{
330
0
    GDALRasterIOExtraArg sExtraArg;
331
0
    if (psExtraArg == nullptr)
332
0
    {
333
0
        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
334
0
        psExtraArg = &sExtraArg;
335
0
    }
336
0
    else if (CPL_UNLIKELY(psExtraArg->nVersion >
337
0
                          RASTERIO_EXTRA_ARG_CURRENT_VERSION))
338
0
    {
339
0
        ReportError(CE_Failure, CPLE_AppDefined,
340
0
                    "Unhandled version of GDALRasterIOExtraArg");
341
0
        return CE_Failure;
342
0
    }
343
344
0
    GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
345
0
                                       nBufYSize);
346
347
0
    if (CPL_UNLIKELY(nullptr == pData))
348
0
    {
349
0
        ReportError(CE_Failure, CPLE_AppDefined,
350
0
                    "The buffer into which the data should be read is null");
351
0
        return CE_Failure;
352
0
    }
353
354
    /* -------------------------------------------------------------------- */
355
    /*      Some size values are "noop".  Lets just return to avoid         */
356
    /*      stressing lower level functions.                                */
357
    /* -------------------------------------------------------------------- */
358
0
    if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
359
0
                     nBufYSize < 1))
360
0
    {
361
0
        CPLDebug("GDAL",
362
0
                 "RasterIO() skipped for odd window or buffer size.\n"
363
0
                 "  Window = (%d,%d)x%dx%d\n"
364
0
                 "  Buffer = %dx%d\n",
365
0
                 nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
366
367
0
        return CE_None;
368
0
    }
369
370
0
    if (eRWFlag == GF_Write)
371
0
    {
372
0
        if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
373
0
        {
374
0
            ReportError(eFlushBlockErr, CPLE_AppDefined,
375
0
                        "An error occurred while writing a dirty block "
376
0
                        "from GDALRasterBand::RasterIO");
377
0
            CPLErr eErr = eFlushBlockErr;
378
0
            eFlushBlockErr = CE_None;
379
0
            return eErr;
380
0
        }
381
0
        if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
382
0
        {
383
0
            return CE_Failure;
384
0
        }
385
0
    }
386
387
    /* -------------------------------------------------------------------- */
388
    /*      If pixel and line spacing are defaulted assign reasonable      */
389
    /*      value assuming a packed buffer.                                 */
390
    /* -------------------------------------------------------------------- */
391
0
    if (nPixelSpace == 0)
392
0
    {
393
0
        nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
394
0
    }
395
396
0
    if (nLineSpace == 0)
397
0
    {
398
0
        nLineSpace = nPixelSpace * nBufXSize;
399
0
    }
400
401
    /* -------------------------------------------------------------------- */
402
    /*      Do some validation of parameters.                               */
403
    /* -------------------------------------------------------------------- */
404
0
    if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
405
0
                     nXOff + nXSize > nRasterXSize || nYOff < 0 ||
406
0
                     nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
407
0
    {
408
0
        ReportError(CE_Failure, CPLE_IllegalArg,
409
0
                    "Access window out of range in RasterIO().  Requested\n"
410
0
                    "(%d,%d) of size %dx%d on raster of %dx%d.",
411
0
                    nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
412
0
        return CE_Failure;
413
0
    }
414
415
0
    if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
416
0
    {
417
0
        ReportError(
418
0
            CE_Failure, CPLE_IllegalArg,
419
0
            "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
420
0
            eRWFlag);
421
0
        return CE_Failure;
422
0
    }
423
0
    if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
424
0
    {
425
0
        ReportError(CE_Failure, CPLE_IllegalArg,
426
0
                    "Illegal GDT_Unknown/GDT_TypeCount argument");
427
0
        return CE_Failure;
428
0
    }
429
430
0
    return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
431
0
                            nBufXSize, nBufYSize, eBufType, nPixelSpace,
432
0
                            nLineSpace, psExtraArg);
433
0
}
434
435
/************************************************************************/
436
/*                         RasterIOInternal()                           */
437
/************************************************************************/
438
439
CPLErr GDALRasterBand::RasterIOInternal(
440
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
441
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
442
    GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
443
0
{
444
    /* -------------------------------------------------------------------- */
445
    /*      Call the format specific function.                              */
446
    /* -------------------------------------------------------------------- */
447
448
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
449
450
0
    CPLErr eErr;
451
0
    if (bForceCachedIO)
452
0
        eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
453
0
                                         pData, nBufXSize, nBufYSize, eBufType,
454
0
                                         nPixelSpace, nLineSpace, psExtraArg);
455
0
    else
456
0
        eErr =
457
0
            IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
458
0
                      nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
459
460
0
    if (bCallLeaveReadWrite)
461
0
        LeaveReadWrite();
462
463
0
    return eErr;
464
0
}
465
466
/************************************************************************/
467
/*                            GDALRasterIO()                            */
468
/************************************************************************/
469
470
/**
471
 * \brief Read/write a region of image data for this band.
472
 *
473
 * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
474
 * resolution, progress callback, etc. are needed)
475
 *
476
 * @see GDALRasterBand::RasterIO()
477
 */
478
479
CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
480
                                int nXOff, int nYOff, int nXSize, int nYSize,
481
                                void *pData, int nBufXSize, int nBufYSize,
482
                                GDALDataType eBufType, int nPixelSpace,
483
                                int nLineSpace)
484
485
0
{
486
0
    VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
487
488
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
489
490
0
    return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
491
0
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
492
0
                             nLineSpace, nullptr));
493
0
}
494
495
/************************************************************************/
496
/*                            GDALRasterIOEx()                          */
497
/************************************************************************/
498
499
/**
500
 * \brief Read/write a region of image data for this band.
501
 *
502
 * @see GDALRasterBand::RasterIO()
503
 * @since GDAL 2.0
504
 */
505
506
CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
507
                                  int nXOff, int nYOff, int nXSize, int nYSize,
508
                                  void *pData, int nBufXSize, int nBufYSize,
509
                                  GDALDataType eBufType, GSpacing nPixelSpace,
510
                                  GSpacing nLineSpace,
511
                                  GDALRasterIOExtraArg *psExtraArg)
512
513
0
{
514
0
    VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
515
516
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
517
518
0
    return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
519
0
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
520
0
                             nLineSpace, psExtraArg));
521
0
}
522
523
/************************************************************************/
524
/*                           GetGDTFromCppType()                        */
525
/************************************************************************/
526
527
namespace
528
{
529
template <class T> struct GetGDTFromCppType;
530
531
#define DEFINE_GetGDTFromCppType(T, eDT)                                       \
532
    template <> struct GetGDTFromCppType<T>                                    \
533
    {                                                                          \
534
        static constexpr GDALDataType GDT = eDT;                               \
535
    }
536
537
DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
538
DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
539
DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
540
DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
541
DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
542
DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
543
DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
544
DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
545
DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
546
DEFINE_GetGDTFromCppType(float, GDT_Float32);
547
DEFINE_GetGDTFromCppType(double, GDT_Float64);
548
// Not allowed by C++ standard
549
//DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
550
//DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
551
DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
552
DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
553
}  // namespace
554
555
/************************************************************************/
556
/*                           ReadRaster()                               */
557
/************************************************************************/
558
559
// clang-format off
560
/** Read a region of image data for this band.
561
 *
562
 * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
563
 * for common use cases, like reading a whole band.
564
 * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
565
 * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
566
 * float, double, std::complex<float|double>.
567
 *
568
 * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
569
 * and can allocate memory automatically.
570
 *
571
 * To read a whole band (assuming it fits into memory), as an array of double:
572
 *
573
\code{.cpp}
574
 double* myArray = static_cast<double*>(
575
     VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
576
 // TODO: check here that myArray != nullptr
577
 const size_t nArrayEltCount =
578
     static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
579
 if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
580
 {
581
     // do something
582
 }
583
 VSIFree(myArray)
584
\endcode
585
 *
586
 * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
587
 *
588
\code{.cpp}
589
 double* myArray = static_cast<double*>(
590
     VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
591
 // TODO: check here that myArray != nullptr
592
 const size_t nArrayEltCount = 128 * 128;
593
 if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
594
 {
595
     // do something
596
 }
597
 VSIFree(myArray)
598
\endcode
599
 *
600
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
601
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
602
 * instance of this dataset) concurrently from several threads.
603
 *
604
 * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
605
 * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
606
 * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
607
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
608
 * Or use nLineSpace and a possibly shifted pData value.
609
 *
610
 * @param[out] pData The buffer into which the data should be written.
611
 * This buffer must contain at least nBufXSize *
612
 * nBufYSize words of type T. It is organized in left to right,
613
 * top to bottom pixel order, and fully packed.
614
 * The type of the buffer does not need to be the one of GetDataType(). The
615
 * method will perform data type translation (with potential rounding, clamping)
616
 * if needed.
617
 *
618
 * @param nArrayEltCount Number of values of pData. If non zero, the method will
619
 * check that it is at least greater or equal to nBufXSize * nBufYSize, and
620
 * return in error if it is not. If set to zero, then pData is trusted to be
621
 * large enough.
622
 *
623
 * @param dfXOff The pixel offset to the top left corner of the region
624
 * of the band to be accessed. This would be zero to start from the left side.
625
 * Defaults to 0.
626
 *
627
 * @param dfYOff The line offset to the top left corner of the region
628
 * of the band to be accessed. This would be zero to start from the top.
629
 * Defaults to 0.
630
 *
631
 * @param dfXSize The width of the region of the band to be accessed in pixels.
632
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
633
 * dfXSize is set to the band width.
634
 *
635
 * @param dfYSize The height of the region of the band to be accessed in lines.
636
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
637
 * dfYSize is set to the band height.
638
 *
639
 * @param nBufXSize the width of the buffer image into which the desired region
640
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
641
 * then nBufXSize is initialized with dfXSize.
642
 *
643
 * @param nBufYSize the height of the buffer image into which the desired region
644
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
645
 * then nBufYSize is initialized with dfYSize.
646
 *
647
 * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
648
 *
649
 * @param pfnProgress Progress function. May be nullptr.
650
 *
651
 * @param pProgressData User data of pfnProgress. May be nullptr.
652
 *
653
 * @return CE_Failure if the access fails, otherwise CE_None.
654
 *
655
 * @see GDALRasterBand::RasterIO()
656
 * @since GDAL 3.10
657
 */
658
// clang-format on
659
660
template <class T>
661
CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
662
                                  double dfXOff, double dfYOff, double dfXSize,
663
                                  double dfYSize, size_t nBufXSize,
664
                                  size_t nBufYSize,
665
                                  GDALRIOResampleAlg eResampleAlg,
666
                                  GDALProgressFunc pfnProgress,
667
                                  void *pProgressData) const
668
0
{
669
0
    if (((nBufXSize | nBufYSize) >> 31) != 0)
670
0
    {
671
0
        return CE_Failure;
672
0
    }
673
674
0
    if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
675
0
    {
676
0
        dfXSize = nRasterXSize;
677
0
        dfYSize = nRasterYSize;
678
0
    }
679
0
    else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
680
0
             !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
681
0
             !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
682
0
             dfYOff + dfYSize > INT_MAX)
683
0
    {
684
0
        return CE_Failure;
685
0
    }
686
687
0
    GDALRasterIOExtraArg sExtraArg;
688
0
    sExtraArg.nVersion = 1;
689
0
    sExtraArg.eResampleAlg = eResampleAlg;
690
0
    sExtraArg.pfnProgress = pfnProgress;
691
0
    sExtraArg.pProgressData = pProgressData;
692
0
    sExtraArg.bFloatingPointWindowValidity = true;
693
0
    sExtraArg.dfXOff = dfXOff;
694
0
    sExtraArg.dfYOff = dfYOff;
695
0
    sExtraArg.dfXSize = dfXSize;
696
0
    sExtraArg.dfYSize = dfYSize;
697
0
    const int nXOff = static_cast<int>(dfXOff);
698
0
    const int nYOff = static_cast<int>(dfYOff);
699
0
    const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
700
0
    const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
701
0
    if (nBufXSize == 0 && nBufYSize == 0)
702
0
    {
703
0
        if (static_cast<int>(dfXSize) == dfXSize &&
704
0
            static_cast<int>(dfYSize) == dfYSize)
705
0
        {
706
0
            nBufXSize = static_cast<int>(dfXSize);
707
0
            nBufYSize = static_cast<int>(dfYSize);
708
0
        }
709
0
        else
710
0
        {
711
0
            CPLError(CE_Failure, CPLE_AppDefined,
712
0
                     "nBufXSize and nBufYSize must be provided if dfXSize or "
713
0
                     "dfYSize is not an integer value");
714
0
            return CE_Failure;
715
0
        }
716
0
    }
717
0
    if (nBufXSize == 0 || nBufYSize == 0)
718
0
    {
719
0
        CPLDebug("GDAL",
720
0
                 "RasterIO() skipped for odd window or buffer size.\n"
721
0
                 "  Window = (%d,%d)x%dx%d\n"
722
0
                 "  Buffer = %dx%d\n",
723
0
                 nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
724
0
                 static_cast<int>(nBufYSize));
725
726
0
        return CE_None;
727
0
    }
728
729
0
    if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
730
0
    {
731
0
        CPLError(CE_Failure, CPLE_AppDefined,
732
0
                 "Provided array is not large enough");
733
0
        return CE_Failure;
734
0
    }
735
736
0
    constexpr GSpacing nPixelSpace = sizeof(T);
737
0
    const GSpacing nLineSpace = nPixelSpace * nBufXSize;
738
0
    constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
739
740
0
    GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
741
742
0
    return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
743
0
                                   static_cast<int>(nBufXSize),
744
0
                                   static_cast<int>(nBufYSize), eBufType,
745
0
                                   nPixelSpace, nLineSpace, &sExtraArg);
746
0
}
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned char>(unsigned char*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<signed char>(signed char*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned short>(unsigned short*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<short>(short*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned int>(unsigned int*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<int>(int*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned long>(unsigned long*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<long>(long*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<cpl::Float16>(cpl::Float16*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<float>(float*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<double>(double*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<std::__1::complex<float> >(std::__1::complex<float>*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<std::__1::complex<double> >(std::__1::complex<double>*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
747
748
//! @cond Doxygen_Suppress
749
750
#define INSTANTIATE_READ_RASTER(T)                                             \
751
    template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
752
        T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
753
        double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
754
        GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
755
        void *pProgressData) const;
756
757
INSTANTIATE_READ_RASTER(uint8_t)
758
INSTANTIATE_READ_RASTER(int8_t)
759
INSTANTIATE_READ_RASTER(uint16_t)
760
INSTANTIATE_READ_RASTER(int16_t)
761
INSTANTIATE_READ_RASTER(uint32_t)
762
INSTANTIATE_READ_RASTER(int32_t)
763
INSTANTIATE_READ_RASTER(uint64_t)
764
INSTANTIATE_READ_RASTER(int64_t)
765
INSTANTIATE_READ_RASTER(GFloat16)
766
INSTANTIATE_READ_RASTER(float)
767
INSTANTIATE_READ_RASTER(double)
768
// Not allowed by C++ standard
769
// INSTANTIATE_READ_RASTER(std::complex<int16_t>)
770
// INSTANTIATE_READ_RASTER(std::complex<int32_t>)
771
INSTANTIATE_READ_RASTER(std::complex<float>)
772
INSTANTIATE_READ_RASTER(std::complex<double>)
773
774
//! @endcond
775
776
/************************************************************************/
777
/*                           ReadRaster()                               */
778
/************************************************************************/
779
780
/** Read a region of image data for this band.
781
 *
782
 * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
783
 * for common use cases, like reading a whole band.
784
 * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
785
 * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
786
 * float, double, std::complex<float|double>.
787
 *
788
 * To read a whole band (assuming it fits into memory), as a vector of double:
789
 *
790
\code
791
 std::vector<double> myArray;
792
 if (poBand->ReadRaster(myArray) == CE_None)
793
 {
794
     // do something
795
 }
796
\endcode
797
 *
798
 * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
799
 *
800
\code{.cpp}
801
 std::vector<double> myArray;
802
 if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
803
 {
804
     // do something
805
 }
806
\endcode
807
 *
808
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
809
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
810
 * instance of this dataset) concurrently from several threads.
811
 *
812
 * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
813
 * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
814
 * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
815
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
816
 * Or use nLineSpace and a possibly shifted pData value.
817
 *
818
 * @param[out] vData The vector into which the data should be written.
819
 * The vector will be resized, if needed, to contain at least nBufXSize *
820
 * nBufYSize values. The values in the vector are organized in left to right,
821
 * top to bottom pixel order, and fully packed.
822
 * The type of the vector does not need to be the one of GetDataType(). The
823
 * method will perform data type translation (with potential rounding, clamping)
824
 * if needed.
825
 *
826
 * @param dfXOff The pixel offset to the top left corner of the region
827
 * of the band to be accessed. This would be zero to start from the left side.
828
 * Defaults to 0.
829
 *
830
 * @param dfYOff The line offset to the top left corner of the region
831
 * of the band to be accessed. This would be zero to start from the top.
832
 * Defaults to 0.
833
 *
834
 * @param dfXSize The width of the region of the band to be accessed in pixels.
835
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
836
 * dfXSize is set to the band width.
837
 *
838
 * @param dfYSize The height of the region of the band to be accessed in lines.
839
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
840
 * dfYSize is set to the band height.
841
 *
842
 * @param nBufXSize the width of the buffer image into which the desired region
843
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
844
 * then nBufXSize is initialized with dfXSize.
845
 *
846
 * @param nBufYSize the height of the buffer image into which the desired region
847
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
848
 * then nBufYSize is initialized with dfYSize.
849
 *
850
 * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
851
 *
852
 * @param pfnProgress Progress function. May be nullptr.
853
 *
854
 * @param pProgressData User data of pfnProgress. May be nullptr.
855
 *
856
 * @return CE_Failure if the access fails, otherwise CE_None.
857
 *
858
 * @see GDALRasterBand::RasterIO()
859
 * @since GDAL 3.10
860
 */
861
template <class T>
862
CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
863
                                  double dfYOff, double dfXSize, double dfYSize,
864
                                  size_t nBufXSize, size_t nBufYSize,
865
                                  GDALRIOResampleAlg eResampleAlg,
866
                                  GDALProgressFunc pfnProgress,
867
                                  void *pProgressData) const
868
0
{
869
0
    if (((nBufXSize | nBufYSize) >> 31) != 0)
870
0
    {
871
0
        return CE_Failure;
872
0
    }
873
874
0
    if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
875
0
    {
876
0
        dfXSize = nRasterXSize;
877
0
        dfYSize = nRasterYSize;
878
0
    }
879
0
    else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
880
0
             !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
881
0
             !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
882
0
             dfYOff + dfYSize > INT_MAX)
883
0
    {
884
0
        return CE_Failure;
885
0
    }
886
887
0
    GDALRasterIOExtraArg sExtraArg;
888
0
    sExtraArg.nVersion = 1;
889
0
    sExtraArg.eResampleAlg = eResampleAlg;
890
0
    sExtraArg.pfnProgress = pfnProgress;
891
0
    sExtraArg.pProgressData = pProgressData;
892
0
    sExtraArg.bFloatingPointWindowValidity = true;
893
0
    sExtraArg.dfXOff = dfXOff;
894
0
    sExtraArg.dfYOff = dfYOff;
895
0
    sExtraArg.dfXSize = dfXSize;
896
0
    sExtraArg.dfYSize = dfYSize;
897
0
    const int nXOff = static_cast<int>(dfXOff);
898
0
    const int nYOff = static_cast<int>(dfYOff);
899
0
    const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
900
0
    const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
901
0
    if (nBufXSize == 0 && nBufYSize == 0)
902
0
    {
903
0
        if (static_cast<int>(dfXSize) == dfXSize &&
904
0
            static_cast<int>(dfYSize) == dfYSize)
905
0
        {
906
0
            nBufXSize = static_cast<int>(dfXSize);
907
0
            nBufYSize = static_cast<int>(dfYSize);
908
0
        }
909
0
        else
910
0
        {
911
0
            CPLError(CE_Failure, CPLE_AppDefined,
912
0
                     "nBufXSize and nBufYSize must be provided if "
913
0
                     "dfXSize or dfYSize is not an integer value");
914
0
            return CE_Failure;
915
0
        }
916
0
    }
917
0
    if (nBufXSize == 0 || nBufYSize == 0)
918
0
    {
919
0
        CPLDebug("GDAL",
920
0
                 "RasterIO() skipped for odd window or buffer size.\n"
921
0
                 "  Window = (%d,%d)x%dx%d\n"
922
0
                 "  Buffer = %dx%d\n",
923
0
                 nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
924
0
                 static_cast<int>(nBufYSize));
925
926
0
        return CE_None;
927
0
    }
928
929
    if constexpr (SIZEOF_VOIDP < 8)
930
    {
931
        if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
932
        {
933
            CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
934
            return CE_Failure;
935
        }
936
    }
937
938
0
    if (vData.size() < nBufXSize * nBufYSize)
939
0
    {
940
0
        try
941
0
        {
942
0
            vData.resize(nBufXSize * nBufYSize);
943
0
        }
944
0
        catch (const std::exception &)
945
0
        {
946
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
947
0
            return CE_Failure;
948
0
        }
949
0
    }
950
951
0
    constexpr GSpacing nPixelSpace = sizeof(T);
952
0
    const GSpacing nLineSpace = nPixelSpace * nBufXSize;
953
0
    constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
954
955
0
    GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
956
957
0
    return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
958
0
                                   vData.data(), static_cast<int>(nBufXSize),
959
0
                                   static_cast<int>(nBufYSize), eBufType,
960
0
                                   nPixelSpace, nLineSpace, &sExtraArg);
961
0
}
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned char>(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<signed char>(std::__1::vector<signed char, std::__1::allocator<signed char> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned short>(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<short>(std::__1::vector<short, std::__1::allocator<short> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<int>(std::__1::vector<int, std::__1::allocator<int> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned long>(std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<long>(std::__1::vector<long, std::__1::allocator<long> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<cpl::Float16>(std::__1::vector<cpl::Float16, std::__1::allocator<cpl::Float16> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<float>(std::__1::vector<float, std::__1::allocator<float> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<double>(std::__1::vector<double, std::__1::allocator<double> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<std::__1::complex<float> >(std::__1::vector<std::__1::complex<float>, std::__1::allocator<std::__1::complex<float> > >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<std::__1::complex<double> >(std::__1::vector<std::__1::complex<double>, std::__1::allocator<std::__1::complex<double> > >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
962
963
//! @cond Doxygen_Suppress
964
965
#define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
966
    template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
967
        std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
968
        double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
969
        GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
970
        void *pProgressData) const;
971
972
INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
973
INSTANTIATE_READ_RASTER_VECTOR(int8_t)
974
INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
975
INSTANTIATE_READ_RASTER_VECTOR(int16_t)
976
INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
977
INSTANTIATE_READ_RASTER_VECTOR(int32_t)
978
INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
979
INSTANTIATE_READ_RASTER_VECTOR(int64_t)
980
INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
981
INSTANTIATE_READ_RASTER_VECTOR(float)
982
INSTANTIATE_READ_RASTER_VECTOR(double)
983
// Not allowed by C++ standard
984
// INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
985
// INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
986
INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
987
INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
988
989
//! @endcond
990
991
/************************************************************************/
992
/*                             ReadBlock()                              */
993
/************************************************************************/
994
995
/**
996
 * \brief Read a block of image data efficiently.
997
 *
998
 * This method accesses a "natural" block from the raster band without
999
 * resampling, or data type conversion.  For a more generalized, but
1000
 * potentially less efficient access use RasterIO().
1001
 *
1002
 * This method is the same as the C GDALReadBlock() function.
1003
 *
1004
 * See the GetLockedBlockRef() method for a way of accessing internally cached
1005
 * block oriented data without an extra copy into an application buffer.
1006
 *
1007
 * The following code would efficiently compute a histogram of eight bit
1008
 * raster data.  Note that the final block may be partial ... data beyond
1009
 * the edge of the underlying raster band in these edge blocks is of an
1010
 * undetermined value.
1011
 *
1012
\code{.cpp}
1013
 CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1014
1015
 {
1016
     memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1017
1018
     CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1019
1020
     int nXBlockSize, nYBlockSize;
1021
1022
     poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1023
     int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1024
     int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1025
1026
     GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1027
1028
     for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1029
     {
1030
         for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1031
         {
1032
             int        nXValid, nYValid;
1033
1034
             poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1035
1036
             // Compute the portion of the block that is valid
1037
             // for partial edge blocks.
1038
             poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1039
1040
             // Collect the histogram counts.
1041
             for( int iY = 0; iY < nYValid; iY++ )
1042
             {
1043
                 for( int iX = 0; iX < nXValid; iX++ )
1044
                 {
1045
                     panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1046
                 }
1047
             }
1048
         }
1049
     }
1050
 }
1051
\endcode
1052
 *
1053
 * @param nXBlockOff the horizontal block offset, with zero indicating
1054
 * the left most block, 1 the next block and so forth.
1055
 *
1056
 * @param nYBlockOff the vertical block offset, with zero indicating
1057
 * the top most block, 1 the next block and so forth.
1058
 *
1059
 * @param pImage the buffer into which the data will be read.  The buffer
1060
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1061
 * of type GetRasterDataType().
1062
 *
1063
 * @return CE_None on success or CE_Failure on an error.
1064
 */
1065
1066
CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1067
1068
0
{
1069
    /* -------------------------------------------------------------------- */
1070
    /*      Validate arguments.                                             */
1071
    /* -------------------------------------------------------------------- */
1072
0
    CPLAssert(pImage != nullptr);
1073
1074
0
    if (!InitBlockInfo())
1075
0
        return CE_Failure;
1076
1077
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1078
0
    {
1079
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1080
0
                    "Illegal nXBlockOff value (%d) in "
1081
0
                    "GDALRasterBand::ReadBlock()\n",
1082
0
                    nXBlockOff);
1083
1084
0
        return (CE_Failure);
1085
0
    }
1086
1087
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1088
0
    {
1089
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1090
0
                    "Illegal nYBlockOff value (%d) in "
1091
0
                    "GDALRasterBand::ReadBlock()\n",
1092
0
                    nYBlockOff);
1093
1094
0
        return (CE_Failure);
1095
0
    }
1096
1097
    /* -------------------------------------------------------------------- */
1098
    /*      Invoke underlying implementation method.                        */
1099
    /* -------------------------------------------------------------------- */
1100
1101
0
    int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1102
0
    CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1103
0
    if (bCallLeaveReadWrite)
1104
0
        LeaveReadWrite();
1105
0
    return eErr;
1106
0
}
1107
1108
/************************************************************************/
1109
/*                           GDALReadBlock()                            */
1110
/************************************************************************/
1111
1112
/**
1113
 * \brief Read a block of image data efficiently.
1114
 *
1115
 * @see GDALRasterBand::ReadBlock()
1116
 */
1117
1118
CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1119
                                 void *pData)
1120
1121
0
{
1122
0
    VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1123
1124
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1125
0
    return (poBand->ReadBlock(nXOff, nYOff, pData));
1126
0
}
1127
1128
/************************************************************************/
1129
/*                            IReadBlock()                             */
1130
/************************************************************************/
1131
1132
/** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1133
 * ) \brief Read a block of data.
1134
 *
1135
 * Default internal implementation ... to be overridden by
1136
 * subclasses that support reading.
1137
 * @param nBlockXOff Block X Offset
1138
 * @param nBlockYOff Block Y Offset
1139
 * @param pData Pixel buffer into which to place read data.
1140
 * @return CE_None on success or CE_Failure on an error.
1141
 */
1142
1143
/************************************************************************/
1144
/*                            IWriteBlock()                             */
1145
/************************************************************************/
1146
1147
/**
1148
 * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1149
 * Write a block of data.
1150
 *
1151
 * Default internal implementation ... to be overridden by
1152
 * subclasses that support writing.
1153
 * @param nBlockXOff Block X Offset
1154
 * @param nBlockYOff Block Y Offset
1155
 * @param pData Pixel buffer to write
1156
 * @return CE_None on success or CE_Failure on an error.
1157
 */
1158
1159
/**/
1160
/**/
1161
1162
CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1163
                                   void * /*pData*/)
1164
1165
0
{
1166
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1167
0
        ReportError(CE_Failure, CPLE_NotSupported,
1168
0
                    "WriteBlock() not supported for this dataset.");
1169
1170
0
    return (CE_Failure);
1171
0
}
1172
1173
/************************************************************************/
1174
/*                             WriteBlock()                             */
1175
/************************************************************************/
1176
1177
/**
1178
 * \brief Write a block of image data efficiently.
1179
 *
1180
 * This method accesses a "natural" block from the raster band without
1181
 * resampling, or data type conversion.  For a more generalized, but
1182
 * potentially less efficient access use RasterIO().
1183
 *
1184
 * This method is the same as the C GDALWriteBlock() function.
1185
 *
1186
 * See ReadBlock() for an example of block oriented data access.
1187
 *
1188
 * @param nXBlockOff the horizontal block offset, with zero indicating
1189
 * the left most block, 1 the next block and so forth.
1190
 *
1191
 * @param nYBlockOff the vertical block offset, with zero indicating
1192
 * the left most block, 1 the next block and so forth.
1193
 *
1194
 * @param pImage the buffer from which the data will be written.  The buffer
1195
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1196
 * of type GetRasterDataType(). Note that the content of the buffer might be
1197
 * temporarily modified during the execution of this method (and eventually
1198
 * restored back to its original content), so it is not safe to use a buffer
1199
 * stored in a read-only section of the calling program.
1200
 *
1201
 * @return CE_None on success or CE_Failure on an error.
1202
 */
1203
1204
CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1205
1206
0
{
1207
    /* -------------------------------------------------------------------- */
1208
    /*      Validate arguments.                                             */
1209
    /* -------------------------------------------------------------------- */
1210
0
    CPLAssert(pImage != nullptr);
1211
1212
0
    if (!InitBlockInfo())
1213
0
        return CE_Failure;
1214
1215
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1216
0
    {
1217
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1218
0
                    "Illegal nXBlockOff value (%d) in "
1219
0
                    "GDALRasterBand::WriteBlock()\n",
1220
0
                    nXBlockOff);
1221
1222
0
        return (CE_Failure);
1223
0
    }
1224
1225
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1226
0
    {
1227
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1228
0
                    "Illegal nYBlockOff value (%d) in "
1229
0
                    "GDALRasterBand::WriteBlock()\n",
1230
0
                    nYBlockOff);
1231
1232
0
        return (CE_Failure);
1233
0
    }
1234
1235
0
    if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1236
0
    {
1237
0
        return CE_Failure;
1238
0
    }
1239
1240
0
    if (eFlushBlockErr != CE_None)
1241
0
    {
1242
0
        ReportError(eFlushBlockErr, CPLE_AppDefined,
1243
0
                    "An error occurred while writing a dirty block "
1244
0
                    "from GDALRasterBand::WriteBlock");
1245
0
        CPLErr eErr = eFlushBlockErr;
1246
0
        eFlushBlockErr = CE_None;
1247
0
        return eErr;
1248
0
    }
1249
1250
    /* -------------------------------------------------------------------- */
1251
    /*      Invoke underlying implementation method.                        */
1252
    /* -------------------------------------------------------------------- */
1253
1254
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1255
0
    CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1256
0
    if (bCallLeaveReadWrite)
1257
0
        LeaveReadWrite();
1258
1259
0
    return eErr;
1260
0
}
1261
1262
/************************************************************************/
1263
/*                           GDALWriteBlock()                           */
1264
/************************************************************************/
1265
1266
/**
1267
 * \brief Write a block of image data efficiently.
1268
 *
1269
 * @see GDALRasterBand::WriteBlock()
1270
 */
1271
1272
CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1273
                                  void *pData)
1274
1275
0
{
1276
0
    VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1277
1278
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1279
0
    return (poBand->WriteBlock(nXOff, nYOff, pData));
1280
0
}
1281
1282
/************************************************************************/
1283
/*                   EmitErrorMessageIfWriteNotSupported()              */
1284
/************************************************************************/
1285
1286
/**
1287
 * Emit an error message if a write operation to this band is not supported.
1288
 *
1289
 * The base implementation will emit an error message if the access mode is
1290
 * read-only. Derived classes may implement it to provide a custom message.
1291
 *
1292
 * @param pszCaller Calling function.
1293
 * @return true if an error message has been emitted.
1294
 */
1295
bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1296
    const char *pszCaller) const
1297
0
{
1298
0
    if (eAccess == GA_ReadOnly)
1299
0
    {
1300
0
        ReportError(CE_Failure, CPLE_NoWriteAccess,
1301
0
                    "%s: attempt to write to dataset opened in read-only mode.",
1302
0
                    pszCaller);
1303
1304
0
        return true;
1305
0
    }
1306
0
    return false;
1307
0
}
1308
1309
/************************************************************************/
1310
/*                         GetActualBlockSize()                         */
1311
/************************************************************************/
1312
/**
1313
 * \brief Fetch the actual block size for a given block offset.
1314
 *
1315
 * Handles partial blocks at the edges of the raster and returns the true
1316
 * number of pixels
1317
 *
1318
 * @param nXBlockOff the horizontal block offset for which to calculate the
1319
 * number of valid pixels, with zero indicating the left most block, 1 the next
1320
 * block and so forth.
1321
 *
1322
 * @param nYBlockOff the vertical block offset, with zero indicating
1323
 * the top most block, 1 the next block and so forth.
1324
 *
1325
 * @param pnXValid pointer to an integer in which the number of valid pixels in
1326
 * the x direction will be stored
1327
 *
1328
 * @param pnYValid pointer to an integer in which the number of valid pixels in
1329
 * the y direction will be stored
1330
 *
1331
 * @return CE_None if the input parameters are valid, CE_Failure otherwise
1332
 *
1333
 * @since GDAL 2.2
1334
 */
1335
CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1336
                                          int *pnXValid, int *pnYValid) const
1337
0
{
1338
0
    if (nXBlockOff < 0 || nBlockXSize == 0 ||
1339
0
        nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1340
0
        nYBlockOff < 0 || nBlockYSize == 0 ||
1341
0
        nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1342
0
    {
1343
0
        return CE_Failure;
1344
0
    }
1345
1346
0
    const int nXPixelOff = nXBlockOff * nBlockXSize;
1347
0
    const int nYPixelOff = nYBlockOff * nBlockYSize;
1348
1349
0
    *pnXValid = nBlockXSize;
1350
0
    *pnYValid = nBlockYSize;
1351
1352
0
    if (nXPixelOff >= nRasterXSize - nBlockXSize)
1353
0
    {
1354
0
        *pnXValid = nRasterXSize - nXPixelOff;
1355
0
    }
1356
1357
0
    if (nYPixelOff >= nRasterYSize - nBlockYSize)
1358
0
    {
1359
0
        *pnYValid = nRasterYSize - nYPixelOff;
1360
0
    }
1361
1362
0
    return CE_None;
1363
0
}
1364
1365
/************************************************************************/
1366
/*                           GDALGetActualBlockSize()                   */
1367
/************************************************************************/
1368
1369
/**
1370
 * \brief Retrieve the actual block size for a given block offset.
1371
 *
1372
 * @see GDALRasterBand::GetActualBlockSize()
1373
 */
1374
1375
CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1376
                                          int nYBlockOff, int *pnXValid,
1377
                                          int *pnYValid)
1378
1379
0
{
1380
0
    VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1381
1382
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1383
0
    return (
1384
0
        poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1385
0
}
1386
1387
/************************************************************************/
1388
/*                     GetSuggestedBlockAccessPattern()                 */
1389
/************************************************************************/
1390
1391
/**
1392
 * \brief Return the suggested/most efficient access pattern to blocks
1393
 *        (for read operations).
1394
 *
1395
 * While all GDAL drivers have to expose a block size, not all can guarantee
1396
 * efficient random access (GSBAP_RANDOM) to any block.
1397
 * Some drivers for example decompress sequentially a compressed stream from
1398
 * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1399
 * case best performance will be achieved while reading blocks in that order.
1400
 * (accessing blocks in random access in such rasters typically causes the
1401
 * decoding to be re-initialized from the start if accessing blocks in
1402
 * a non-sequential order)
1403
 *
1404
 * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1405
 * returned by drivers that expose a somewhat artificial block size, because
1406
 * they can extract any part of a raster, but in a rather inefficient way.
1407
 *
1408
 * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1409
 * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1410
 * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1411
 * most efficient strategy is to read as many pixels as possible in the less
1412
 * RasterIO() operations.
1413
 *
1414
 * The return of this method is for example used to determine the swath size
1415
 * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1416
 *
1417
 * @since GDAL 3.6
1418
 */
1419
1420
GDALSuggestedBlockAccessPattern
1421
GDALRasterBand::GetSuggestedBlockAccessPattern() const
1422
0
{
1423
0
    return GSBAP_UNKNOWN;
1424
0
}
1425
1426
/************************************************************************/
1427
/*                         GetRasterDataType()                          */
1428
/************************************************************************/
1429
1430
/**
1431
 * \brief Fetch the pixel data type for this band.
1432
 *
1433
 * This method is the same as the C function GDALGetRasterDataType().
1434
 *
1435
 * @return the data type of pixels for this band.
1436
 */
1437
1438
GDALDataType GDALRasterBand::GetRasterDataType() const
1439
1440
0
{
1441
0
    return eDataType;
1442
0
}
1443
1444
/************************************************************************/
1445
/*                       GDALGetRasterDataType()                        */
1446
/************************************************************************/
1447
1448
/**
1449
 * \brief Fetch the pixel data type for this band.
1450
 *
1451
 * @see GDALRasterBand::GetRasterDataType()
1452
 */
1453
1454
GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1455
1456
0
{
1457
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1458
1459
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1460
0
    return poBand->GetRasterDataType();
1461
0
}
1462
1463
/************************************************************************/
1464
/*                            GetBlockSize()                            */
1465
/************************************************************************/
1466
1467
/**
1468
 * \brief Fetch the "natural" block size of this band.
1469
 *
1470
 * GDAL contains a concept of the natural block size of rasters so that
1471
 * applications can organized data access efficiently for some file formats.
1472
 * The natural block size is the block size that is most efficient for
1473
 * accessing the format.  For many formats this is simple a whole scanline
1474
 * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1475
 *
1476
 * However, for tiled images this will typically be the tile size.
1477
 *
1478
 * Note that the X and Y block sizes don't have to divide the image size
1479
 * evenly, meaning that right and bottom edge blocks may be incomplete.
1480
 * See ReadBlock() for an example of code dealing with these issues.
1481
 *
1482
 * This method is the same as the C function GDALGetBlockSize().
1483
 *
1484
 * @param pnXSize integer to put the X block size into or NULL.
1485
 *
1486
 * @param pnYSize integer to put the Y block size into or NULL.
1487
 */
1488
1489
void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1490
1491
0
{
1492
0
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
1493
0
    {
1494
0
        ReportError(CE_Failure, CPLE_AppDefined,
1495
0
                    "Invalid block dimension : %d * %d", nBlockXSize,
1496
0
                    nBlockYSize);
1497
0
        if (pnXSize != nullptr)
1498
0
            *pnXSize = 0;
1499
0
        if (pnYSize != nullptr)
1500
0
            *pnYSize = 0;
1501
0
    }
1502
0
    else
1503
0
    {
1504
0
        if (pnXSize != nullptr)
1505
0
            *pnXSize = nBlockXSize;
1506
0
        if (pnYSize != nullptr)
1507
0
            *pnYSize = nBlockYSize;
1508
0
    }
1509
0
}
1510
1511
/************************************************************************/
1512
/*                          GDALGetBlockSize()                          */
1513
/************************************************************************/
1514
1515
/**
1516
 * \brief Fetch the "natural" block size of this band.
1517
 *
1518
 * @see GDALRasterBand::GetBlockSize()
1519
 */
1520
1521
void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1522
                                  int *pnYSize)
1523
1524
0
{
1525
0
    VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1526
1527
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1528
0
    poBand->GetBlockSize(pnXSize, pnYSize);
1529
0
}
1530
1531
/************************************************************************/
1532
/*                           InitBlockInfo()                            */
1533
/************************************************************************/
1534
1535
//! @cond Doxygen_Suppress
1536
int GDALRasterBand::InitBlockInfo()
1537
1538
0
{
1539
0
    if (poBandBlockCache != nullptr)
1540
0
        return poBandBlockCache->IsInitOK();
1541
1542
    /* Do some validation of raster and block dimensions in case the driver */
1543
    /* would have neglected to do it itself */
1544
0
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
1545
0
    {
1546
0
        ReportError(CE_Failure, CPLE_AppDefined,
1547
0
                    "Invalid block dimension : %d * %d", nBlockXSize,
1548
0
                    nBlockYSize);
1549
0
        return FALSE;
1550
0
    }
1551
1552
0
    if (nRasterXSize <= 0 || nRasterYSize <= 0)
1553
0
    {
1554
0
        ReportError(CE_Failure, CPLE_AppDefined,
1555
0
                    "Invalid raster dimension : %d * %d", nRasterXSize,
1556
0
                    nRasterYSize);
1557
0
        return FALSE;
1558
0
    }
1559
1560
0
    const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1561
0
    if (nDataTypeSize == 0)
1562
0
    {
1563
0
        ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1564
0
        return FALSE;
1565
0
    }
1566
1567
#if SIZEOF_VOIDP == 4
1568
    if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1569
    {
1570
        /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1571
         * multiplication in other cases */
1572
        if (nBlockXSize > INT_MAX / nDataTypeSize ||
1573
            nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1574
        {
1575
            ReportError(CE_Failure, CPLE_NotSupported,
1576
                        "Too big block : %d * %d for 32-bit build", nBlockXSize,
1577
                        nBlockYSize);
1578
            return FALSE;
1579
        }
1580
    }
1581
#endif
1582
1583
0
    nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1584
0
    nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1585
1586
0
    const char *pszBlockStrategy =
1587
0
        CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1588
0
    bool bUseArray = true;
1589
0
    if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1590
0
    {
1591
0
        if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1592
0
                                   GDAL_OF_DEFAULT_BLOCK_ACCESS)
1593
0
        {
1594
0
            GUIntBig nBlockCount =
1595
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1596
0
            if (poDS != nullptr)
1597
0
                nBlockCount *= poDS->GetRasterCount();
1598
0
            bUseArray = (nBlockCount < 1024 * 1024);
1599
0
        }
1600
0
        else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1601
0
                 GDAL_OF_HASHSET_BLOCK_ACCESS)
1602
0
        {
1603
0
            bUseArray = false;
1604
0
        }
1605
0
    }
1606
0
    else if (EQUAL(pszBlockStrategy, "HASHSET"))
1607
0
        bUseArray = false;
1608
0
    else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1609
0
        CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1610
0
                 pszBlockStrategy);
1611
1612
0
    if (bUseArray)
1613
0
        poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1614
0
    else
1615
0
    {
1616
0
        if (nBand == 1)
1617
0
            CPLDebug("GDAL", "Use hashset band block cache");
1618
0
        poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1619
0
    }
1620
0
    if (poBandBlockCache == nullptr)
1621
0
        return FALSE;
1622
0
    return poBandBlockCache->Init();
1623
0
}
1624
1625
//! @endcond
1626
1627
/************************************************************************/
1628
/*                             FlushCache()                             */
1629
/************************************************************************/
1630
1631
/**
1632
 * \brief Flush raster data cache.
1633
 *
1634
 * This call will recover memory used to cache data blocks for this raster
1635
 * band, and ensure that new requests are referred to the underlying driver.
1636
 *
1637
 * This method is the same as the C function GDALFlushRasterCache().
1638
 *
1639
 * @param bAtClosing Whether this is called from a GDALDataset destructor
1640
 * @return CE_None on success.
1641
 */
1642
1643
CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1644
1645
0
{
1646
0
    if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1647
0
        poBandBlockCache)
1648
0
        poBandBlockCache->DisableDirtyBlockWriting();
1649
1650
0
    CPLErr eGlobalErr = eFlushBlockErr;
1651
1652
0
    if (eFlushBlockErr != CE_None)
1653
0
    {
1654
0
        ReportError(
1655
0
            eFlushBlockErr, CPLE_AppDefined,
1656
0
            "An error occurred while writing a dirty block from FlushCache");
1657
0
        eFlushBlockErr = CE_None;
1658
0
    }
1659
1660
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1661
0
        return eGlobalErr;
1662
1663
0
    return poBandBlockCache->FlushCache();
1664
0
}
1665
1666
/************************************************************************/
1667
/*                        GDALFlushRasterCache()                        */
1668
/************************************************************************/
1669
1670
/**
1671
 * \brief Flush raster data cache.
1672
 *
1673
 * @see GDALRasterBand::FlushCache()
1674
 */
1675
1676
CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1677
1678
0
{
1679
0
    VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1680
1681
0
    return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1682
0
}
1683
1684
/************************************************************************/
1685
/*                             DropCache()                              */
1686
/************************************************************************/
1687
1688
/**
1689
* \brief Drop raster data cache : data in cache will be lost.
1690
*
1691
* This call will recover memory used to cache data blocks for this raster
1692
* band, and ensure that new requests are referred to the underlying driver.
1693
*
1694
* This method is the same as the C function GDALDropRasterCache().
1695
*
1696
* @return CE_None on success.
1697
* @since 3.9
1698
*/
1699
1700
CPLErr GDALRasterBand::DropCache()
1701
1702
0
{
1703
0
    CPLErr result = CE_None;
1704
1705
0
    if (poBandBlockCache)
1706
0
        poBandBlockCache->DisableDirtyBlockWriting();
1707
1708
0
    CPLErr eGlobalErr = eFlushBlockErr;
1709
1710
0
    if (eFlushBlockErr != CE_None)
1711
0
    {
1712
0
        ReportError(
1713
0
            eFlushBlockErr, CPLE_AppDefined,
1714
0
            "An error occurred while writing a dirty block from DropCache");
1715
0
        eFlushBlockErr = CE_None;
1716
0
    }
1717
1718
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1719
0
        result = eGlobalErr;
1720
0
    else
1721
0
        result = poBandBlockCache->FlushCache();
1722
1723
0
    if (poBandBlockCache)
1724
0
        poBandBlockCache->EnableDirtyBlockWriting();
1725
1726
0
    return result;
1727
0
}
1728
1729
/************************************************************************/
1730
/*                        GDALDropRasterCache()                         */
1731
/************************************************************************/
1732
1733
/**
1734
* \brief Drop raster data cache.
1735
*
1736
* @see GDALRasterBand::DropCache()
1737
* @since 3.9
1738
*/
1739
1740
CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1741
1742
0
{
1743
0
    VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1744
1745
0
    return GDALRasterBand::FromHandle(hBand)->DropCache();
1746
0
}
1747
1748
/************************************************************************/
1749
/*                        UnreferenceBlock()                            */
1750
/*                                                                      */
1751
/*      Unreference the block from our array of blocks                  */
1752
/*      This method should only be called by                            */
1753
/*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1754
/*      the block cache mutex)                                          */
1755
/************************************************************************/
1756
1757
CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1758
0
{
1759
#ifdef notdef
1760
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1761
    {
1762
        if (poBandBlockCache == nullptr)
1763
            printf("poBandBlockCache == NULL\n"); /*ok*/
1764
        else
1765
            printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1766
        printf("caller = %s\n", pszCaller);            /*ok*/
1767
        printf("GDALRasterBand: %p\n", this);          /*ok*/
1768
        printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
1769
        printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
1770
        printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
1771
        printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
1772
        printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
1773
        poBlock->DumpBlock();
1774
        if (GetDataset() != nullptr)
1775
            printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1776
        GDALRasterBlock::Verify();
1777
        abort();
1778
    }
1779
#endif
1780
0
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1781
0
    return poBandBlockCache->UnreferenceBlock(poBlock);
1782
0
}
1783
1784
/************************************************************************/
1785
/*                        AddBlockToFreeList()                          */
1786
/*                                                                      */
1787
/*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
1788
/*      finished with a block about to be free'd, they pass it to that  */
1789
/*      method.                                                         */
1790
/************************************************************************/
1791
1792
//! @cond Doxygen_Suppress
1793
void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1794
0
{
1795
0
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1796
0
    return poBandBlockCache->AddBlockToFreeList(poBlock);
1797
0
}
1798
1799
//! @endcond
1800
1801
/************************************************************************/
1802
/*                             FlushBlock()                             */
1803
/************************************************************************/
1804
1805
/** Flush a block out of the block cache.
1806
 * @param nXBlockOff block x offset
1807
 * @param nYBlockOff blocky offset
1808
 * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1809
 * @return CE_None in case of success, an error code otherwise.
1810
 */
1811
CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1812
                                  int bWriteDirtyBlock)
1813
1814
0
{
1815
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1816
0
        return (CE_Failure);
1817
1818
    /* -------------------------------------------------------------------- */
1819
    /*      Validate the request                                            */
1820
    /* -------------------------------------------------------------------- */
1821
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1822
0
    {
1823
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1824
0
                    "Illegal nBlockXOff value (%d) in "
1825
0
                    "GDALRasterBand::FlushBlock()\n",
1826
0
                    nXBlockOff);
1827
1828
0
        return (CE_Failure);
1829
0
    }
1830
1831
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1832
0
    {
1833
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1834
0
                    "Illegal nBlockYOff value (%d) in "
1835
0
                    "GDALRasterBand::FlushBlock()\n",
1836
0
                    nYBlockOff);
1837
1838
0
        return (CE_Failure);
1839
0
    }
1840
1841
0
    return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1842
0
                                        bWriteDirtyBlock);
1843
0
}
1844
1845
/************************************************************************/
1846
/*                        TryGetLockedBlockRef()                        */
1847
/************************************************************************/
1848
1849
/**
1850
 * \brief Try fetching block ref.
1851
 *
1852
 * This method will returned the requested block (locked) if it is already
1853
 * in the block cache for the layer.  If not, nullptr is returned.
1854
 *
1855
 * If a non-NULL value is returned, then a lock for the block will have been
1856
 * acquired on behalf of the caller.  It is absolutely imperative that the
1857
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1858
 * severe problems may result.
1859
 *
1860
 * @param nXBlockOff the horizontal block offset, with zero indicating
1861
 * the left most block, 1 the next block and so forth.
1862
 *
1863
 * @param nYBlockOff the vertical block offset, with zero indicating
1864
 * the top most block, 1 the next block and so forth.
1865
 *
1866
 * @return NULL if block not available, or locked block pointer.
1867
 */
1868
1869
GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1870
                                                      int nYBlockOff)
1871
1872
0
{
1873
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1874
0
        return nullptr;
1875
1876
    /* -------------------------------------------------------------------- */
1877
    /*      Validate the request                                            */
1878
    /* -------------------------------------------------------------------- */
1879
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1880
0
    {
1881
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1882
0
                    "Illegal nBlockXOff value (%d) in "
1883
0
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1884
0
                    nXBlockOff);
1885
1886
0
        return (nullptr);
1887
0
    }
1888
1889
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1890
0
    {
1891
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1892
0
                    "Illegal nBlockYOff value (%d) in "
1893
0
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1894
0
                    nYBlockOff);
1895
1896
0
        return (nullptr);
1897
0
    }
1898
1899
0
    return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1900
0
}
1901
1902
/************************************************************************/
1903
/*                         GetLockedBlockRef()                          */
1904
/************************************************************************/
1905
1906
/**
1907
 * \brief Fetch a pointer to an internally cached raster block.
1908
 *
1909
 * This method will returned the requested block (locked) if it is already
1910
 * in the block cache for the layer.  If not, the block will be read from
1911
 * the driver, and placed in the layer block cached, then returned.  If an
1912
 * error occurs reading the block from the driver, a NULL value will be
1913
 * returned.
1914
 *
1915
 * If a non-NULL value is returned, then a lock for the block will have been
1916
 * acquired on behalf of the caller.  It is absolutely imperative that the
1917
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1918
 * severe problems may result.
1919
 *
1920
 * Note that calling GetLockedBlockRef() on a previously uncached band will
1921
 * enable caching.
1922
 *
1923
 * @param nXBlockOff the horizontal block offset, with zero indicating
1924
 * the left most block, 1 the next block and so forth.
1925
 *
1926
 * @param nYBlockOff the vertical block offset, with zero indicating
1927
 * the top most block, 1 the next block and so forth.
1928
 *
1929
 * @param bJustInitialize If TRUE the block will be allocated and initialized,
1930
 * but not actually read from the source.  This is useful when it will just
1931
 * be completely set and written back.
1932
 *
1933
 * @return pointer to the block object, or NULL on failure.
1934
 */
1935
1936
GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1937
                                                   int nYBlockOff,
1938
                                                   int bJustInitialize)
1939
1940
0
{
1941
    /* -------------------------------------------------------------------- */
1942
    /*      Try and fetch from cache.                                       */
1943
    /* -------------------------------------------------------------------- */
1944
0
    GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1945
1946
    /* -------------------------------------------------------------------- */
1947
    /*      If we didn't find it in our memory cache, instantiate a         */
1948
    /*      block (potentially load from disk) and "adopt" it into the      */
1949
    /*      cache.                                                          */
1950
    /* -------------------------------------------------------------------- */
1951
0
    if (poBlock == nullptr)
1952
0
    {
1953
0
        if (!InitBlockInfo())
1954
0
            return (nullptr);
1955
1956
        /* --------------------------------------------------------------------
1957
         */
1958
        /*      Validate the request */
1959
        /* --------------------------------------------------------------------
1960
         */
1961
0
        if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1962
0
        {
1963
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1964
0
                        "Illegal nBlockXOff value (%d) in "
1965
0
                        "GDALRasterBand::GetLockedBlockRef()\n",
1966
0
                        nXBlockOff);
1967
1968
0
            return (nullptr);
1969
0
        }
1970
1971
0
        if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1972
0
        {
1973
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1974
0
                        "Illegal nBlockYOff value (%d) in "
1975
0
                        "GDALRasterBand::GetLockedBlockRef()\n",
1976
0
                        nYBlockOff);
1977
1978
0
            return (nullptr);
1979
0
        }
1980
1981
0
        poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1982
0
        if (poBlock == nullptr)
1983
0
            return nullptr;
1984
1985
0
        poBlock->AddLock();
1986
1987
        /* We need to temporarily drop the read-write lock in the following */
1988
        /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
1989
         */
1990
        /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
1991
        /* block cache fills, T1 might need to flush dirty blocks of D2 in the
1992
         */
1993
        /* below Internalize(), which will cause GDALRasterBlock::Write() to be
1994
         */
1995
        /* called and attempt at taking the lock on T2 (already taken).
1996
         * Similarly */
1997
        /* for T2 with D1, hence a deadlock situation (#6163) */
1998
        /* But this may open the door to other problems... */
1999
0
        if (poDS)
2000
0
            poDS->TemporarilyDropReadWriteLock();
2001
        /* allocate data space */
2002
0
        CPLErr eErr = poBlock->Internalize();
2003
0
        if (poDS)
2004
0
            poDS->ReacquireReadWriteLock();
2005
0
        if (eErr != CE_None)
2006
0
        {
2007
0
            poBlock->DropLock();
2008
0
            delete poBlock;
2009
0
            return nullptr;
2010
0
        }
2011
2012
0
        if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2013
0
        {
2014
0
            poBlock->DropLock();
2015
0
            delete poBlock;
2016
0
            return nullptr;
2017
0
        }
2018
2019
0
        if (!bJustInitialize)
2020
0
        {
2021
0
            const GUInt32 nErrorCounter = CPLGetErrorCounter();
2022
0
            int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2023
0
            eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2024
0
            if (bCallLeaveReadWrite)
2025
0
                LeaveReadWrite();
2026
0
            if (eErr != CE_None)
2027
0
            {
2028
0
                poBlock->DropLock();
2029
0
                FlushBlock(nXBlockOff, nYBlockOff);
2030
0
                ReportError(CE_Failure, CPLE_AppDefined,
2031
0
                            "IReadBlock failed at X offset %d, Y offset %d%s",
2032
0
                            nXBlockOff, nYBlockOff,
2033
0
                            (nErrorCounter != CPLGetErrorCounter())
2034
0
                                ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2035
0
                                : "");
2036
0
                return nullptr;
2037
0
            }
2038
2039
0
            nBlockReads++;
2040
0
            if (static_cast<GIntBig>(nBlockReads) ==
2041
0
                    static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2042
0
                        1 &&
2043
0
                nBand == 1 && poDS != nullptr)
2044
0
            {
2045
0
                CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2046
0
                         poDS->GetDescription());
2047
0
            }
2048
0
        }
2049
0
    }
2050
2051
0
    return poBlock;
2052
0
}
2053
2054
/************************************************************************/
2055
/*                               Fill()                                 */
2056
/************************************************************************/
2057
2058
/**
2059
 * \brief Fill this band with a constant value.
2060
 *
2061
 * GDAL makes no guarantees
2062
 * about what values pixels in newly created files are set to, so this
2063
 * method can be used to clear a band to a specified "default" value.
2064
 * The fill value is passed in as a double but this will be converted
2065
 * to the underlying type before writing to the file. An optional
2066
 * second argument allows the imaginary component of a complex
2067
 * constant value to be specified.
2068
 *
2069
 * This method is the same as the C function GDALFillRaster().
2070
 *
2071
 * @param dfRealValue Real component of fill value
2072
 * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2073
 *
2074
 * @return CE_Failure if the write fails, otherwise CE_None
2075
 */
2076
CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2077
0
{
2078
2079
    // General approach is to construct a source block of the file's
2080
    // native type containing the appropriate value and then copy this
2081
    // to each block in the image via the RasterBlock cache. Using
2082
    // the cache means we avoid file I/O if it is not necessary, at the
2083
    // expense of some extra memcpy's (since we write to the
2084
    // RasterBlock cache, which is then at some point written to the
2085
    // underlying file, rather than simply directly to the underlying
2086
    // file.)
2087
2088
    // Check we can write to the file.
2089
0
    if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2090
0
    {
2091
0
        return CE_Failure;
2092
0
    }
2093
2094
    // Make sure block parameters are set.
2095
0
    if (!InitBlockInfo())
2096
0
        return CE_Failure;
2097
2098
    // Allocate the source block.
2099
0
    auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2100
0
    int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2101
0
    auto blockByteSize = blockSize * elementSize;
2102
0
    unsigned char *srcBlock =
2103
0
        static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2104
0
    if (srcBlock == nullptr)
2105
0
    {
2106
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
2107
0
                    "GDALRasterBand::Fill(): Out of memory "
2108
0
                    "allocating " CPL_FRMT_GUIB " bytes.\n",
2109
0
                    static_cast<GUIntBig>(blockByteSize));
2110
0
        return CE_Failure;
2111
0
    }
2112
2113
    // Initialize the source block.
2114
0
    double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2115
0
    GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2116
0
                    elementSize, blockSize);
2117
2118
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2119
2120
    // Write block to block cache
2121
0
    for (int j = 0; j < nBlocksPerColumn; ++j)
2122
0
    {
2123
0
        for (int i = 0; i < nBlocksPerRow; ++i)
2124
0
        {
2125
0
            GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2126
0
            if (destBlock == nullptr)
2127
0
            {
2128
0
                ReportError(CE_Failure, CPLE_OutOfMemory,
2129
0
                            "GDALRasterBand::Fill(): Error "
2130
0
                            "while retrieving cache block.");
2131
0
                VSIFree(srcBlock);
2132
0
                return CE_Failure;
2133
0
            }
2134
0
            memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2135
0
            destBlock->MarkDirty();
2136
0
            destBlock->DropLock();
2137
0
        }
2138
0
    }
2139
2140
0
    if (bCallLeaveReadWrite)
2141
0
        LeaveReadWrite();
2142
2143
    // Free up the source block
2144
0
    VSIFree(srcBlock);
2145
2146
0
    return CE_None;
2147
0
}
2148
2149
/************************************************************************/
2150
/*                         GDALFillRaster()                             */
2151
/************************************************************************/
2152
2153
/**
2154
 * \brief Fill this band with a constant value.
2155
 *
2156
 * @see GDALRasterBand::Fill()
2157
 */
2158
CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2159
                                  double dfImaginaryValue)
2160
0
{
2161
0
    VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2162
2163
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2164
0
    return poBand->Fill(dfRealValue, dfImaginaryValue);
2165
0
}
2166
2167
/************************************************************************/
2168
/*                             GetAccess()                              */
2169
/************************************************************************/
2170
2171
/**
2172
 * \brief Find out if we have update permission for this band.
2173
 *
2174
 * This method is the same as the C function GDALGetRasterAccess().
2175
 *
2176
 * @return Either GA_Update or GA_ReadOnly.
2177
 */
2178
2179
GDALAccess GDALRasterBand::GetAccess()
2180
2181
0
{
2182
0
    return eAccess;
2183
0
}
2184
2185
/************************************************************************/
2186
/*                        GDALGetRasterAccess()                         */
2187
/************************************************************************/
2188
2189
/**
2190
 * \brief Find out if we have update permission for this band.
2191
 *
2192
 * @see GDALRasterBand::GetAccess()
2193
 */
2194
2195
GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2196
2197
0
{
2198
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2199
2200
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2201
0
    return poBand->GetAccess();
2202
0
}
2203
2204
/************************************************************************/
2205
/*                          GetCategoryNames()                          */
2206
/************************************************************************/
2207
2208
/**
2209
 * \brief Fetch the list of category names for this raster.
2210
 *
2211
 * The return list is a "StringList" in the sense of the CPL functions.
2212
 * That is a NULL terminated array of strings.  Raster values without
2213
 * associated names will have an empty string in the returned list.  The
2214
 * first entry in the list is for raster values of zero, and so on.
2215
 *
2216
 * The returned stringlist should not be altered or freed by the application.
2217
 * It may change on the next GDAL call, so please copy it if it is needed
2218
 * for any period of time.
2219
 *
2220
 * This method is the same as the C function GDALGetRasterCategoryNames().
2221
 *
2222
 * @return list of names, or NULL if none.
2223
 */
2224
2225
char **GDALRasterBand::GetCategoryNames()
2226
2227
0
{
2228
0
    return nullptr;
2229
0
}
2230
2231
/************************************************************************/
2232
/*                     GDALGetRasterCategoryNames()                     */
2233
/************************************************************************/
2234
2235
/**
2236
 * \brief Fetch the list of category names for this raster.
2237
 *
2238
 * @see GDALRasterBand::GetCategoryNames()
2239
 */
2240
2241
char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2242
2243
0
{
2244
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2245
2246
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2247
0
    return poBand->GetCategoryNames();
2248
0
}
2249
2250
/************************************************************************/
2251
/*                          SetCategoryNames()                          */
2252
/************************************************************************/
2253
2254
/**
2255
 * \fn GDALRasterBand::SetCategoryNames(char**)
2256
 * \brief Set the category names for this band.
2257
 *
2258
 * See the GetCategoryNames() method for more on the interpretation of
2259
 * category names.
2260
 *
2261
 * This method is the same as the C function GDALSetRasterCategoryNames().
2262
 *
2263
 * @param papszNames the NULL terminated StringList of category names.  May
2264
 * be NULL to just clear the existing list.
2265
 *
2266
 * @return CE_None on success of CE_Failure on failure.  If unsupported
2267
 * by the driver CE_Failure is returned, but no error message is reported.
2268
 */
2269
2270
/**/
2271
/**/
2272
2273
CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2274
0
{
2275
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2276
0
        ReportError(CE_Failure, CPLE_NotSupported,
2277
0
                    "SetCategoryNames() not supported for this dataset.");
2278
2279
0
    return CE_Failure;
2280
0
}
2281
2282
/************************************************************************/
2283
/*                        GDALSetCategoryNames()                        */
2284
/************************************************************************/
2285
2286
/**
2287
 * \brief Set the category names for this band.
2288
 *
2289
 * @see GDALRasterBand::SetCategoryNames()
2290
 */
2291
2292
CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2293
                                              CSLConstList papszNames)
2294
2295
0
{
2296
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2297
2298
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2299
0
    return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2300
0
}
2301
2302
/************************************************************************/
2303
/*                           GetNoDataValue()                           */
2304
/************************************************************************/
2305
2306
/**
2307
 * \brief Fetch the no data value for this band.
2308
 *
2309
 * If there is no out of data value, an out of range value will generally
2310
 * be returned.  The no data value for a band is generally a special marker
2311
 * value used to mark pixels that are not valid data.  Such pixels should
2312
 * generally not be displayed, nor contribute to analysis operations.
2313
 *
2314
 * The no data value returned is 'raw', meaning that it has no offset and
2315
 * scale applied.
2316
 *
2317
 * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2318
 * lossy if the nodata value cannot exactly been represented by a double.
2319
 * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2320
 *
2321
 * This method is the same as the C function GDALGetRasterNoDataValue().
2322
 *
2323
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2324
 * is actually associated with this layer.  May be NULL (default).
2325
 *
2326
 * @return the nodata value for this band.
2327
 */
2328
2329
double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2330
2331
0
{
2332
0
    if (pbSuccess != nullptr)
2333
0
        *pbSuccess = FALSE;
2334
2335
0
    return -1e10;
2336
0
}
2337
2338
/************************************************************************/
2339
/*                      GDALGetRasterNoDataValue()                      */
2340
/************************************************************************/
2341
2342
/**
2343
 * \brief Fetch the no data value for this band.
2344
 *
2345
 * @see GDALRasterBand::GetNoDataValue()
2346
 */
2347
2348
double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2349
                                            int *pbSuccess)
2350
2351
0
{
2352
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2353
2354
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2355
0
    return poBand->GetNoDataValue(pbSuccess);
2356
0
}
2357
2358
/************************************************************************/
2359
/*                       GetNoDataValueAsInt64()                        */
2360
/************************************************************************/
2361
2362
/**
2363
 * \brief Fetch the no data value for this band.
2364
 *
2365
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2366
 *
2367
 * If there is no out of data value, an out of range value will generally
2368
 * be returned.  The no data value for a band is generally a special marker
2369
 * value used to mark pixels that are not valid data.  Such pixels should
2370
 * generally not be displayed, nor contribute to analysis operations.
2371
 *
2372
 * The no data value returned is 'raw', meaning that it has no offset and
2373
 * scale applied.
2374
 *
2375
 * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2376
 *
2377
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2378
 * is actually associated with this layer.  May be NULL (default).
2379
 *
2380
 * @return the nodata value for this band.
2381
 *
2382
 * @since GDAL 3.5
2383
 */
2384
2385
int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2386
2387
0
{
2388
0
    if (pbSuccess != nullptr)
2389
0
        *pbSuccess = FALSE;
2390
2391
0
    return std::numeric_limits<int64_t>::min();
2392
0
}
2393
2394
/************************************************************************/
2395
/*                   GDALGetRasterNoDataValueAsInt64()                  */
2396
/************************************************************************/
2397
2398
/**
2399
 * \brief Fetch the no data value for this band.
2400
 *
2401
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2402
 *
2403
 * @see GDALRasterBand::GetNoDataValueAsInt64()
2404
 *
2405
 * @since GDAL 3.5
2406
 */
2407
2408
int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2409
                                                    int *pbSuccess)
2410
2411
0
{
2412
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2413
0
                      std::numeric_limits<int64_t>::min());
2414
2415
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2416
0
    return poBand->GetNoDataValueAsInt64(pbSuccess);
2417
0
}
2418
2419
/************************************************************************/
2420
/*                       GetNoDataValueAsUInt64()                        */
2421
/************************************************************************/
2422
2423
/**
2424
 * \brief Fetch the no data value for this band.
2425
 *
2426
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2427
 *
2428
 * If there is no out of data value, an out of range value will generally
2429
 * be returned.  The no data value for a band is generally a special marker
2430
 * value used to mark pixels that are not valid data.  Such pixels should
2431
 * generally not be displayed, nor contribute to analysis operations.
2432
 *
2433
 * The no data value returned is 'raw', meaning that it has no offset and
2434
 * scale applied.
2435
 *
2436
 * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2437
 *
2438
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2439
 * is actually associated with this layer.  May be NULL (default).
2440
 *
2441
 * @return the nodata value for this band.
2442
 *
2443
 * @since GDAL 3.5
2444
 */
2445
2446
uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2447
2448
0
{
2449
0
    if (pbSuccess != nullptr)
2450
0
        *pbSuccess = FALSE;
2451
2452
0
    return std::numeric_limits<uint64_t>::max();
2453
0
}
2454
2455
/************************************************************************/
2456
/*                   GDALGetRasterNoDataValueAsUInt64()                  */
2457
/************************************************************************/
2458
2459
/**
2460
 * \brief Fetch the no data value for this band.
2461
 *
2462
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2463
 *
2464
 * @see GDALRasterBand::GetNoDataValueAsUInt64()
2465
 *
2466
 * @since GDAL 3.5
2467
 */
2468
2469
uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2470
                                                      int *pbSuccess)
2471
2472
0
{
2473
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2474
0
                      std::numeric_limits<uint64_t>::max());
2475
2476
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2477
0
    return poBand->GetNoDataValueAsUInt64(pbSuccess);
2478
0
}
2479
2480
/************************************************************************/
2481
/*                        SetNoDataValueAsString()                      */
2482
/************************************************************************/
2483
2484
/**
2485
 * \brief Set the no data value for this band.
2486
 *
2487
 * Depending on drivers, changing the no data value may or may not have an
2488
 * effect on the pixel values of a raster that has just been created. It is
2489
 * thus advised to explicitly called Fill() if the intent is to initialize
2490
 * the raster to the nodata value.
2491
 * In any case, changing an existing no data value, when one already exists and
2492
 * the dataset exists or has been initialized, has no effect on the pixel whose
2493
 * value matched the previous nodata value.
2494
 *
2495
 * To clear the nodata value, use DeleteNoDataValue().
2496
 *
2497
 * @param pszNoData the value to set.
2498
 * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2499
 *             If the value cannot be exactly represented on the output data
2500
 *             type, *pbCannotBeExactlyRepresented will be set to true.
2501
 *
2502
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2503
 * by the driver, CE_Failure is returned but no error message will have
2504
 * been emitted.
2505
 *
2506
 * @since 3.11
2507
 */
2508
2509
CPLErr
2510
GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2511
                                       bool *pbCannotBeExactlyRepresented)
2512
0
{
2513
0
    if (pbCannotBeExactlyRepresented)
2514
0
        *pbCannotBeExactlyRepresented = false;
2515
0
    if (eDataType == GDT_Int64)
2516
0
    {
2517
0
        if (strchr(pszNoData, '.') ||
2518
0
            CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2519
0
        {
2520
0
            char *endptr = nullptr;
2521
0
            const double dfVal = CPLStrtod(pszNoData, &endptr);
2522
0
            if (endptr == pszNoData + strlen(pszNoData) &&
2523
0
                GDALIsValueExactAs<int64_t>(dfVal))
2524
0
            {
2525
0
                return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2526
0
            }
2527
0
        }
2528
0
        else
2529
0
        {
2530
0
            try
2531
0
            {
2532
0
                const auto val = std::stoll(pszNoData);
2533
0
                return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2534
0
            }
2535
0
            catch (const std::exception &)
2536
0
            {
2537
0
            }
2538
0
        }
2539
0
    }
2540
0
    else if (eDataType == GDT_UInt64)
2541
0
    {
2542
0
        if (strchr(pszNoData, '.') ||
2543
0
            CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2544
0
        {
2545
0
            char *endptr = nullptr;
2546
0
            const double dfVal = CPLStrtod(pszNoData, &endptr);
2547
0
            if (endptr == pszNoData + strlen(pszNoData) &&
2548
0
                GDALIsValueExactAs<uint64_t>(dfVal))
2549
0
            {
2550
0
                return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2551
0
            }
2552
0
        }
2553
0
        else
2554
0
        {
2555
0
            try
2556
0
            {
2557
0
                const auto val = std::stoull(pszNoData);
2558
0
                return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2559
0
            }
2560
0
            catch (const std::exception &)
2561
0
            {
2562
0
            }
2563
0
        }
2564
0
    }
2565
0
    else if (eDataType == GDT_Float32)
2566
0
    {
2567
0
        char *endptr = nullptr;
2568
0
        const float fVal = CPLStrtof(pszNoData, &endptr);
2569
0
        if (endptr == pszNoData + strlen(pszNoData))
2570
0
        {
2571
0
            return SetNoDataValue(fVal);
2572
0
        }
2573
0
    }
2574
0
    else
2575
0
    {
2576
0
        char *endptr = nullptr;
2577
0
        const double dfVal = CPLStrtod(pszNoData, &endptr);
2578
0
        if (endptr == pszNoData + strlen(pszNoData) &&
2579
0
            GDALIsValueExactAs(dfVal, eDataType))
2580
0
        {
2581
0
            return SetNoDataValue(dfVal);
2582
0
        }
2583
0
    }
2584
0
    if (pbCannotBeExactlyRepresented)
2585
0
        *pbCannotBeExactlyRepresented = true;
2586
0
    return CE_Failure;
2587
0
}
2588
2589
/************************************************************************/
2590
/*                           SetNoDataValue()                           */
2591
/************************************************************************/
2592
2593
/**
2594
 * \fn GDALRasterBand::SetNoDataValue(double)
2595
 * \brief Set the no data value for this band.
2596
 *
2597
 * Depending on drivers, changing the no data value may or may not have an
2598
 * effect on the pixel values of a raster that has just been created. It is
2599
 * thus advised to explicitly called Fill() if the intent is to initialize
2600
 * the raster to the nodata value.
2601
 * In any case, changing an existing no data value, when one already exists and
2602
 * the dataset exists or has been initialized, has no effect on the pixel whose
2603
 * value matched the previous nodata value.
2604
 *
2605
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2606
 * be represented by a double, use SetNoDataValueAsInt64() or
2607
 * SetNoDataValueAsUInt64() instead.
2608
 *
2609
 * To clear the nodata value, use DeleteNoDataValue().
2610
 *
2611
 * This method is the same as the C function GDALSetRasterNoDataValue().
2612
 *
2613
 * @param dfNoData the value to set.
2614
 *
2615
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2616
 * by the driver, CE_Failure is returned but no error message will have
2617
 * been emitted.
2618
 */
2619
2620
/**/
2621
/**/
2622
2623
CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2624
2625
0
{
2626
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2627
0
        ReportError(CE_Failure, CPLE_NotSupported,
2628
0
                    "SetNoDataValue() not supported for this dataset.");
2629
2630
0
    return CE_Failure;
2631
0
}
2632
2633
/************************************************************************/
2634
/*                         GDALSetRasterNoDataValue()                   */
2635
/************************************************************************/
2636
2637
/**
2638
 * \brief Set the no data value for this band.
2639
 *
2640
 * Depending on drivers, changing the no data value may or may not have an
2641
 * effect on the pixel values of a raster that has just been created. It is
2642
 * thus advised to explicitly called Fill() if the intent is to initialize
2643
 * the raster to the nodata value.
2644
 * In any case, changing an existing no data value, when one already exists and
2645
 * the dataset exists or has been initialized, has no effect on the pixel whose
2646
 * value matched the previous nodata value.
2647
 *
2648
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2649
 * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2650
 * GDALSetRasterNoDataValueAsUInt64() instead.
2651
 *
2652
 * @see GDALRasterBand::SetNoDataValue()
2653
 */
2654
2655
CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2656
                                            double dfValue)
2657
2658
0
{
2659
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2660
2661
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2662
0
    return poBand->SetNoDataValue(dfValue);
2663
0
}
2664
2665
/************************************************************************/
2666
/*                       SetNoDataValueAsInt64()                        */
2667
/************************************************************************/
2668
2669
/**
2670
 * \brief Set the no data value for this band.
2671
 *
2672
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2673
 *
2674
 * Depending on drivers, changing the no data value may or may not have an
2675
 * effect on the pixel values of a raster that has just been created. It is
2676
 * thus advised to explicitly called Fill() if the intent is to initialize
2677
 * the raster to the nodata value.
2678
 * In ay case, changing an existing no data value, when one already exists and
2679
 * the dataset exists or has been initialized, has no effect on the pixel whose
2680
 * value matched the previous nodata value.
2681
 *
2682
 * To clear the nodata value, use DeleteNoDataValue().
2683
 *
2684
 * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2685
 *
2686
 * @param nNoDataValue the value to set.
2687
 *
2688
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2689
 * by the driver, CE_Failure is returned but no error message will have
2690
 * been emitted.
2691
 *
2692
 * @since GDAL 3.5
2693
 */
2694
2695
CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2696
2697
0
{
2698
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2699
0
        ReportError(CE_Failure, CPLE_NotSupported,
2700
0
                    "SetNoDataValueAsInt64() not supported for this dataset.");
2701
2702
0
    return CE_Failure;
2703
0
}
2704
2705
/************************************************************************/
2706
/*                 GDALSetRasterNoDataValueAsInt64()                    */
2707
/************************************************************************/
2708
2709
/**
2710
 * \brief Set the no data value for this band.
2711
 *
2712
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2713
 *
2714
 * Depending on drivers, changing the no data value may or may not have an
2715
 * effect on the pixel values of a raster that has just been created. It is
2716
 * thus advised to explicitly called Fill() if the intent is to initialize
2717
 * the raster to the nodata value.
2718
 * In ay case, changing an existing no data value, when one already exists and
2719
 * the dataset exists or has been initialized, has no effect on the pixel whose
2720
 * value matched the previous nodata value.
2721
 *
2722
 * @see GDALRasterBand::SetNoDataValueAsInt64()
2723
 *
2724
 * @since GDAL 3.5
2725
 */
2726
2727
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2728
                                                   int64_t nValue)
2729
2730
0
{
2731
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2732
2733
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2734
0
    return poBand->SetNoDataValueAsInt64(nValue);
2735
0
}
2736
2737
/************************************************************************/
2738
/*                       SetNoDataValueAsUInt64()                       */
2739
/************************************************************************/
2740
2741
/**
2742
 * \brief Set the no data value for this band.
2743
 *
2744
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2745
 *
2746
 * Depending on drivers, changing the no data value may or may not have an
2747
 * effect on the pixel values of a raster that has just been created. It is
2748
 * thus advised to explicitly called Fill() if the intent is to initialize
2749
 * the raster to the nodata value.
2750
 * In ay case, changing an existing no data value, when one already exists and
2751
 * the dataset exists or has been initialized, has no effect on the pixel whose
2752
 * value matched the previous nodata value.
2753
 *
2754
 * To clear the nodata value, use DeleteNoDataValue().
2755
 *
2756
 * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2757
 *
2758
 * @param nNoDataValue the value to set.
2759
 *
2760
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2761
 * by the driver, CE_Failure is returned but no error message will have
2762
 * been emitted.
2763
 *
2764
 * @since GDAL 3.5
2765
 */
2766
2767
CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2768
2769
0
{
2770
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2771
0
        ReportError(CE_Failure, CPLE_NotSupported,
2772
0
                    "SetNoDataValueAsUInt64() not supported for this dataset.");
2773
2774
0
    return CE_Failure;
2775
0
}
2776
2777
/************************************************************************/
2778
/*                 GDALSetRasterNoDataValueAsUInt64()                    */
2779
/************************************************************************/
2780
2781
/**
2782
 * \brief Set the no data value for this band.
2783
 *
2784
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2785
 *
2786
 * Depending on drivers, changing the no data value may or may not have an
2787
 * effect on the pixel values of a raster that has just been created. It is
2788
 * thus advised to explicitly called Fill() if the intent is to initialize
2789
 * the raster to the nodata value.
2790
 * In ay case, changing an existing no data value, when one already exists and
2791
 * the dataset exists or has been initialized, has no effect on the pixel whose
2792
 * value matched the previous nodata value.
2793
 *
2794
 * @see GDALRasterBand::SetNoDataValueAsUInt64()
2795
 *
2796
 * @since GDAL 3.5
2797
 */
2798
2799
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2800
                                                    uint64_t nValue)
2801
2802
0
{
2803
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2804
2805
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2806
0
    return poBand->SetNoDataValueAsUInt64(nValue);
2807
0
}
2808
2809
/************************************************************************/
2810
/*                        DeleteNoDataValue()                           */
2811
/************************************************************************/
2812
2813
/**
2814
 * \brief Remove the no data value for this band.
2815
 *
2816
 * This method is the same as the C function GDALDeleteRasterNoDataValue().
2817
 *
2818
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2819
 * by the driver, CE_Failure is returned but no error message will have
2820
 * been emitted.
2821
 *
2822
 * @since GDAL 2.1
2823
 */
2824
2825
CPLErr GDALRasterBand::DeleteNoDataValue()
2826
2827
0
{
2828
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2829
0
        ReportError(CE_Failure, CPLE_NotSupported,
2830
0
                    "DeleteNoDataValue() not supported for this dataset.");
2831
2832
0
    return CE_Failure;
2833
0
}
2834
2835
/************************************************************************/
2836
/*                       GDALDeleteRasterNoDataValue()                  */
2837
/************************************************************************/
2838
2839
/**
2840
 * \brief Remove the no data value for this band.
2841
 *
2842
 * @see GDALRasterBand::DeleteNoDataValue()
2843
 *
2844
 * @since GDAL 2.1
2845
 */
2846
2847
CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2848
2849
0
{
2850
0
    VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2851
2852
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2853
0
    return poBand->DeleteNoDataValue();
2854
0
}
2855
2856
/************************************************************************/
2857
/*                             GetMaximum()                             */
2858
/************************************************************************/
2859
2860
/**
2861
 * \brief Fetch the maximum value for this band.
2862
 *
2863
 * For file formats that don't know this intrinsically, the maximum supported
2864
 * value for the data type will generally be returned.
2865
 *
2866
 * This method is the same as the C function GDALGetRasterMaximum().
2867
 *
2868
 * @param pbSuccess pointer to a boolean to use to indicate if the
2869
 * returned value is a tight maximum or not.  May be NULL (default).
2870
 *
2871
 * @return the maximum raster value (excluding no data pixels)
2872
 */
2873
2874
double GDALRasterBand::GetMaximum(int *pbSuccess)
2875
2876
0
{
2877
0
    const char *pszValue = nullptr;
2878
2879
0
    if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2880
0
    {
2881
0
        if (pbSuccess != nullptr)
2882
0
            *pbSuccess = TRUE;
2883
2884
0
        return CPLAtofM(pszValue);
2885
0
    }
2886
2887
0
    if (pbSuccess != nullptr)
2888
0
        *pbSuccess = FALSE;
2889
2890
0
    switch (eDataType)
2891
0
    {
2892
0
        case GDT_Byte:
2893
0
        {
2894
0
            EnablePixelTypeSignedByteWarning(false);
2895
0
            const char *pszPixelType =
2896
0
                GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2897
0
            EnablePixelTypeSignedByteWarning(true);
2898
0
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2899
0
                return 127;
2900
2901
0
            return 255;
2902
0
        }
2903
2904
0
        case GDT_Int8:
2905
0
            return 127;
2906
2907
0
        case GDT_UInt16:
2908
0
            return 65535;
2909
2910
0
        case GDT_Int16:
2911
0
        case GDT_CInt16:
2912
0
            return 32767;
2913
2914
0
        case GDT_Int32:
2915
0
        case GDT_CInt32:
2916
0
            return 2147483647.0;
2917
2918
0
        case GDT_UInt32:
2919
0
            return 4294967295.0;
2920
2921
0
        case GDT_Int64:
2922
0
            return static_cast<double>(std::numeric_limits<GInt64>::max());
2923
2924
0
        case GDT_UInt64:
2925
0
            return static_cast<double>(std::numeric_limits<GUInt64>::max());
2926
2927
0
        case GDT_Float16:
2928
0
        case GDT_CFloat16:
2929
0
            return 65504.0;
2930
2931
0
        case GDT_Float32:
2932
0
        case GDT_CFloat32:
2933
0
            return 4294967295.0;  // Not actually accurate.
2934
2935
0
        case GDT_Float64:
2936
0
        case GDT_CFloat64:
2937
0
            return 4294967295.0;  // Not actually accurate.
2938
2939
0
        case GDT_Unknown:
2940
0
        case GDT_TypeCount:
2941
0
            break;
2942
0
    }
2943
0
    return 4294967295.0;  // Not actually accurate.
2944
0
}
2945
2946
/************************************************************************/
2947
/*                        GDALGetRasterMaximum()                        */
2948
/************************************************************************/
2949
2950
/**
2951
 * \brief Fetch the maximum value for this band.
2952
 *
2953
 * @see GDALRasterBand::GetMaximum()
2954
 */
2955
2956
double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2957
2958
0
{
2959
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2960
2961
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2962
0
    return poBand->GetMaximum(pbSuccess);
2963
0
}
2964
2965
/************************************************************************/
2966
/*                             GetMinimum()                             */
2967
/************************************************************************/
2968
2969
/**
2970
 * \brief Fetch the minimum value for this band.
2971
 *
2972
 * For file formats that don't know this intrinsically, the minimum supported
2973
 * value for the data type will generally be returned.
2974
 *
2975
 * This method is the same as the C function GDALGetRasterMinimum().
2976
 *
2977
 * @param pbSuccess pointer to a boolean to use to indicate if the
2978
 * returned value is a tight minimum or not.  May be NULL (default).
2979
 *
2980
 * @return the minimum raster value (excluding no data pixels)
2981
 */
2982
2983
double GDALRasterBand::GetMinimum(int *pbSuccess)
2984
2985
0
{
2986
0
    const char *pszValue = nullptr;
2987
2988
0
    if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
2989
0
    {
2990
0
        if (pbSuccess != nullptr)
2991
0
            *pbSuccess = TRUE;
2992
2993
0
        return CPLAtofM(pszValue);
2994
0
    }
2995
2996
0
    if (pbSuccess != nullptr)
2997
0
        *pbSuccess = FALSE;
2998
2999
0
    switch (eDataType)
3000
0
    {
3001
0
        case GDT_Byte:
3002
0
        {
3003
0
            EnablePixelTypeSignedByteWarning(false);
3004
0
            const char *pszPixelType =
3005
0
                GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3006
0
            EnablePixelTypeSignedByteWarning(true);
3007
0
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3008
0
                return -128;
3009
3010
0
            return 0;
3011
0
        }
3012
3013
0
        case GDT_Int8:
3014
0
            return -128;
3015
0
            break;
3016
3017
0
        case GDT_UInt16:
3018
0
            return 0;
3019
3020
0
        case GDT_Int16:
3021
0
        case GDT_CInt16:
3022
0
            return -32768;
3023
3024
0
        case GDT_Int32:
3025
0
        case GDT_CInt32:
3026
0
            return -2147483648.0;
3027
3028
0
        case GDT_UInt32:
3029
0
            return 0;
3030
3031
0
        case GDT_Int64:
3032
0
            return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3033
3034
0
        case GDT_UInt64:
3035
0
            return 0;
3036
3037
0
        case GDT_Float16:
3038
0
        case GDT_CFloat16:
3039
0
            return -65504.0;
3040
3041
0
        case GDT_Float32:
3042
0
        case GDT_CFloat32:
3043
0
            return -4294967295.0;  // Not actually accurate.
3044
3045
0
        case GDT_Float64:
3046
0
        case GDT_CFloat64:
3047
0
            return -4294967295.0;  // Not actually accurate.
3048
3049
0
        case GDT_Unknown:
3050
0
        case GDT_TypeCount:
3051
0
            break;
3052
0
    }
3053
0
    return -4294967295.0;  // Not actually accurate.
3054
0
}
3055
3056
/************************************************************************/
3057
/*                        GDALGetRasterMinimum()                        */
3058
/************************************************************************/
3059
3060
/**
3061
 * \brief Fetch the minimum value for this band.
3062
 *
3063
 * @see GDALRasterBand::GetMinimum()
3064
 */
3065
3066
double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3067
3068
0
{
3069
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3070
3071
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3072
0
    return poBand->GetMinimum(pbSuccess);
3073
0
}
3074
3075
/************************************************************************/
3076
/*                       GetColorInterpretation()                       */
3077
/************************************************************************/
3078
3079
/**
3080
 * \brief How should this band be interpreted as color?
3081
 *
3082
 * GCI_Undefined is returned when the format doesn't know anything
3083
 * about the color interpretation.
3084
 *
3085
 * This method is the same as the C function
3086
 * GDALGetRasterColorInterpretation().
3087
 *
3088
 * @return color interpretation value for band.
3089
 */
3090
3091
GDALColorInterp GDALRasterBand::GetColorInterpretation()
3092
3093
0
{
3094
0
    return GCI_Undefined;
3095
0
}
3096
3097
/************************************************************************/
3098
/*                  GDALGetRasterColorInterpretation()                  */
3099
/************************************************************************/
3100
3101
/**
3102
 * \brief How should this band be interpreted as color?
3103
 *
3104
 * @see GDALRasterBand::GetColorInterpretation()
3105
 */
3106
3107
GDALColorInterp CPL_STDCALL
3108
GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3109
3110
0
{
3111
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3112
3113
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3114
0
    return poBand->GetColorInterpretation();
3115
0
}
3116
3117
/************************************************************************/
3118
/*                       SetColorInterpretation()                       */
3119
/************************************************************************/
3120
3121
/**
3122
 * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3123
 * \brief Set color interpretation of a band.
3124
 *
3125
 * This method is the same as the C function GDALSetRasterColorInterpretation().
3126
 *
3127
 * @param eColorInterp the new color interpretation to apply to this band.
3128
 *
3129
 * @return CE_None on success or CE_Failure if method is unsupported by format.
3130
 */
3131
3132
/**/
3133
/**/
3134
3135
CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3136
3137
0
{
3138
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3139
0
        ReportError(CE_Failure, CPLE_NotSupported,
3140
0
                    "SetColorInterpretation() not supported for this dataset.");
3141
0
    return CE_Failure;
3142
0
}
3143
3144
/************************************************************************/
3145
/*                  GDALSetRasterColorInterpretation()                  */
3146
/************************************************************************/
3147
3148
/**
3149
 * \brief Set color interpretation of a band.
3150
 *
3151
 * @see GDALRasterBand::SetColorInterpretation()
3152
 */
3153
3154
CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3155
    GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3156
3157
0
{
3158
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3159
3160
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3161
0
    return poBand->SetColorInterpretation(eColorInterp);
3162
0
}
3163
3164
/************************************************************************/
3165
/*                           GetColorTable()                            */
3166
/************************************************************************/
3167
3168
/**
3169
 * \brief Fetch the color table associated with band.
3170
 *
3171
 * If there is no associated color table, the return result is NULL.  The
3172
 * returned color table remains owned by the GDALRasterBand, and can't
3173
 * be depended on for long, nor should it ever be modified by the caller.
3174
 *
3175
 * This method is the same as the C function GDALGetRasterColorTable().
3176
 *
3177
 * @return internal color table, or NULL.
3178
 */
3179
3180
GDALColorTable *GDALRasterBand::GetColorTable()
3181
3182
0
{
3183
0
    return nullptr;
3184
0
}
3185
3186
/************************************************************************/
3187
/*                      GDALGetRasterColorTable()                       */
3188
/************************************************************************/
3189
3190
/**
3191
 * \brief Fetch the color table associated with band.
3192
 *
3193
 * @see GDALRasterBand::GetColorTable()
3194
 */
3195
3196
GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3197
3198
0
{
3199
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3200
3201
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3202
0
    return GDALColorTable::ToHandle(poBand->GetColorTable());
3203
0
}
3204
3205
/************************************************************************/
3206
/*                           SetColorTable()                            */
3207
/************************************************************************/
3208
3209
/**
3210
 * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3211
 * \brief Set the raster color table.
3212
 *
3213
 * The driver will make a copy of all desired data in the colortable.  It
3214
 * remains owned by the caller after the call.
3215
 *
3216
 * This method is the same as the C function GDALSetRasterColorTable().
3217
 *
3218
 * @param poCT the color table to apply.  This may be NULL to clear the color
3219
 * table (where supported).
3220
 *
3221
 * @return CE_None on success, or CE_Failure on failure.  If the action is
3222
 * unsupported by the driver, a value of CE_Failure is returned, but no
3223
 * error is issued.
3224
 */
3225
3226
/**/
3227
/**/
3228
3229
CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3230
3231
0
{
3232
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3233
0
        ReportError(CE_Failure, CPLE_NotSupported,
3234
0
                    "SetColorTable() not supported for this dataset.");
3235
0
    return CE_Failure;
3236
0
}
3237
3238
/************************************************************************/
3239
/*                      GDALSetRasterColorTable()                       */
3240
/************************************************************************/
3241
3242
/**
3243
 * \brief Set the raster color table.
3244
 *
3245
 * @see GDALRasterBand::SetColorTable()
3246
 */
3247
3248
CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3249
                                           GDALColorTableH hCT)
3250
3251
0
{
3252
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3253
3254
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3255
0
    return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3256
0
}
3257
3258
/************************************************************************/
3259
/*                       HasArbitraryOverviews()                        */
3260
/************************************************************************/
3261
3262
/**
3263
 * \brief Check for arbitrary overviews.
3264
 *
3265
 * This returns TRUE if the underlying datastore can compute arbitrary
3266
 * overviews efficiently, such as is the case with OGDI over a network.
3267
 * Datastores with arbitrary overviews don't generally have any fixed
3268
 * overviews, but the RasterIO() method can be used in downsampling mode
3269
 * to get overview data efficiently.
3270
 *
3271
 * This method is the same as the C function GDALHasArbitraryOverviews(),
3272
 *
3273
 * @return TRUE if arbitrary overviews available (efficiently), otherwise
3274
 * FALSE.
3275
 */
3276
3277
int GDALRasterBand::HasArbitraryOverviews()
3278
3279
0
{
3280
0
    return FALSE;
3281
0
}
3282
3283
/************************************************************************/
3284
/*                     GDALHasArbitraryOverviews()                      */
3285
/************************************************************************/
3286
3287
/**
3288
 * \brief Check for arbitrary overviews.
3289
 *
3290
 * @see GDALRasterBand::HasArbitraryOverviews()
3291
 */
3292
3293
int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3294
3295
0
{
3296
0
    VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3297
3298
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3299
0
    return poBand->HasArbitraryOverviews();
3300
0
}
3301
3302
/************************************************************************/
3303
/*                          GetOverviewCount()                          */
3304
/************************************************************************/
3305
3306
/**
3307
 * \brief Return the number of overview layers available.
3308
 *
3309
 * This method is the same as the C function GDALGetOverviewCount().
3310
 *
3311
 * @return overview count, zero if none.
3312
 */
3313
3314
int GDALRasterBand::GetOverviewCount()
3315
3316
0
{
3317
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3318
0
        poDS->AreOverviewsEnabled())
3319
0
        return poDS->oOvManager.GetOverviewCount(nBand);
3320
3321
0
    return 0;
3322
0
}
3323
3324
/************************************************************************/
3325
/*                        GDALGetOverviewCount()                        */
3326
/************************************************************************/
3327
3328
/**
3329
 * \brief Return the number of overview layers available.
3330
 *
3331
 * @see GDALRasterBand::GetOverviewCount()
3332
 */
3333
3334
int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3335
3336
0
{
3337
0
    VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3338
3339
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3340
0
    return poBand->GetOverviewCount();
3341
0
}
3342
3343
/************************************************************************/
3344
/*                            GetOverview()                             */
3345
/************************************************************************/
3346
3347
/**
3348
 * \brief Fetch overview raster band object.
3349
 *
3350
 * This method is the same as the C function GDALGetOverview().
3351
 *
3352
 * @param i overview index between 0 and GetOverviewCount()-1.
3353
 *
3354
 * @return overview GDALRasterBand.
3355
 */
3356
3357
GDALRasterBand *GDALRasterBand::GetOverview(int i)
3358
3359
0
{
3360
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3361
0
        poDS->AreOverviewsEnabled())
3362
0
        return poDS->oOvManager.GetOverview(nBand, i);
3363
3364
0
    return nullptr;
3365
0
}
3366
3367
/************************************************************************/
3368
/*                          GDALGetOverview()                           */
3369
/************************************************************************/
3370
3371
/**
3372
 * \brief Fetch overview raster band object.
3373
 *
3374
 * @see GDALRasterBand::GetOverview()
3375
 */
3376
3377
GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3378
3379
0
{
3380
0
    VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3381
3382
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3383
0
    return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3384
0
}
3385
3386
/************************************************************************/
3387
/*                      GetRasterSampleOverview()                       */
3388
/************************************************************************/
3389
3390
/**
3391
 * \brief Fetch best sampling overview.
3392
 *
3393
 * Returns the most reduced overview of the given band that still satisfies
3394
 * the desired number of samples.  This function can be used with zero
3395
 * as the number of desired samples to fetch the most reduced overview.
3396
 * The same band as was passed in will be returned if it has not overviews,
3397
 * or if none of the overviews have enough samples.
3398
 *
3399
 * This method is the same as the C functions GDALGetRasterSampleOverview()
3400
 * and GDALGetRasterSampleOverviewEx().
3401
 *
3402
 * @param nDesiredSamples the returned band will have at least this many
3403
 * pixels.
3404
 *
3405
 * @return optimal overview or the band itself.
3406
 */
3407
3408
GDALRasterBand *
3409
GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3410
3411
0
{
3412
0
    GDALRasterBand *poBestBand = this;
3413
3414
0
    double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3415
3416
0
    for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3417
0
    {
3418
0
        GDALRasterBand *poOBand = GetOverview(iOverview);
3419
3420
0
        if (poOBand == nullptr)
3421
0
            continue;
3422
3423
0
        const double dfOSamples =
3424
0
            poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3425
3426
0
        if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3427
0
        {
3428
0
            dfBestSamples = dfOSamples;
3429
0
            poBestBand = poOBand;
3430
0
        }
3431
0
    }
3432
3433
0
    return poBestBand;
3434
0
}
3435
3436
/************************************************************************/
3437
/*                    GDALGetRasterSampleOverview()                     */
3438
/************************************************************************/
3439
3440
/**
3441
 * \brief Fetch best sampling overview.
3442
 *
3443
 * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3444
 * billion samples.
3445
 *
3446
 * @see GDALRasterBand::GetRasterSampleOverview()
3447
 * @see GDALGetRasterSampleOverviewEx()
3448
 */
3449
3450
GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3451
                                                        int nDesiredSamples)
3452
3453
0
{
3454
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3455
3456
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3457
0
    return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3458
0
        nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3459
0
}
3460
3461
/************************************************************************/
3462
/*                    GDALGetRasterSampleOverviewEx()                   */
3463
/************************************************************************/
3464
3465
/**
3466
 * \brief Fetch best sampling overview.
3467
 *
3468
 * @see GDALRasterBand::GetRasterSampleOverview()
3469
 * @since GDAL 2.0
3470
 */
3471
3472
GDALRasterBandH CPL_STDCALL
3473
GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3474
3475
0
{
3476
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3477
3478
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3479
0
    return GDALRasterBand::ToHandle(
3480
0
        poBand->GetRasterSampleOverview(nDesiredSamples));
3481
0
}
3482
3483
/************************************************************************/
3484
/*                           BuildOverviews()                           */
3485
/************************************************************************/
3486
3487
/**
3488
 * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3489
 * GDALProgressFunc, void*) \brief Build raster overview(s)
3490
 *
3491
 * If the operation is unsupported for the indicated dataset, then
3492
 * CE_Failure is returned, and CPLGetLastErrorNo() will return
3493
 * CPLE_NotSupported.
3494
 *
3495
 * WARNING: Most formats don't support per-band overview computation, but
3496
 * require that overviews are computed for all bands of a dataset, using
3497
 * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3498
 * is the HFA driver which supports this method.
3499
 *
3500
 * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3501
 * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3502
 * applied.
3503
 * @param nOverviews number of overviews to build.
3504
 * @param panOverviewList the list of overview decimation factors to build.
3505
 * @param pfnProgress a function to call to report progress, or NULL.
3506
 * @param pProgressData application data to pass to the progress function.
3507
 * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3508
 *                     key=value pairs, or NULL
3509
 *
3510
 * @return CE_None on success or CE_Failure if the operation doesn't work.
3511
 */
3512
3513
/**/
3514
/**/
3515
3516
CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3517
                                      int /*nOverviews*/,
3518
                                      const int * /*panOverviewList*/,
3519
                                      GDALProgressFunc /*pfnProgress*/,
3520
                                      void * /*pProgressData*/,
3521
                                      CSLConstList /* papszOptions */)
3522
3523
0
{
3524
0
    ReportError(CE_Failure, CPLE_NotSupported,
3525
0
                "BuildOverviews() not supported for this dataset.");
3526
3527
0
    return (CE_Failure);
3528
0
}
3529
3530
/************************************************************************/
3531
/*                             GetOffset()                              */
3532
/************************************************************************/
3533
3534
/**
3535
 * \brief Fetch the raster value offset.
3536
 *
3537
 * This value (in combination with the GetScale() value) can be used to
3538
 * transform raw pixel values into the units returned by GetUnitType().
3539
 * For example this might be used to store elevations in GUInt16 bands
3540
 * with a precision of 0.1, and starting from -100.
3541
 *
3542
 * Units value = (raw value * scale) + offset
3543
 *
3544
 * Note that applying scale and offset is of the responsibility of the user,
3545
 * and is not done by methods such as RasterIO() or ReadBlock().
3546
 *
3547
 * For file formats that don't know this intrinsically a value of zero
3548
 * is returned.
3549
 *
3550
 * This method is the same as the C function GDALGetRasterOffset().
3551
 *
3552
 * @param pbSuccess pointer to a boolean to use to indicate if the
3553
 * returned value is meaningful or not.  May be NULL (default).
3554
 *
3555
 * @return the raster offset.
3556
 */
3557
3558
double GDALRasterBand::GetOffset(int *pbSuccess)
3559
3560
0
{
3561
0
    if (pbSuccess != nullptr)
3562
0
        *pbSuccess = FALSE;
3563
3564
0
    return 0.0;
3565
0
}
3566
3567
/************************************************************************/
3568
/*                        GDALGetRasterOffset()                         */
3569
/************************************************************************/
3570
3571
/**
3572
 * \brief Fetch the raster value offset.
3573
 *
3574
 * @see GDALRasterBand::GetOffset()
3575
 */
3576
3577
double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3578
3579
0
{
3580
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3581
3582
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3583
0
    return poBand->GetOffset(pbSuccess);
3584
0
}
3585
3586
/************************************************************************/
3587
/*                             SetOffset()                              */
3588
/************************************************************************/
3589
3590
/**
3591
 * \fn GDALRasterBand::SetOffset(double)
3592
 * \brief Set scaling offset.
3593
 *
3594
 * Very few formats implement this method.   When not implemented it will
3595
 * issue a CPLE_NotSupported error and return CE_Failure.
3596
 *
3597
 * This method is the same as the C function GDALSetRasterOffset().
3598
 *
3599
 * @param dfNewOffset the new offset.
3600
 *
3601
 * @return CE_None or success or CE_Failure on failure.
3602
 */
3603
3604
/**/
3605
/**/
3606
3607
CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3608
0
{
3609
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3610
0
        ReportError(CE_Failure, CPLE_NotSupported,
3611
0
                    "SetOffset() not supported on this raster band.");
3612
3613
0
    return CE_Failure;
3614
0
}
3615
3616
/************************************************************************/
3617
/*                        GDALSetRasterOffset()                         */
3618
/************************************************************************/
3619
3620
/**
3621
 * \brief Set scaling offset.
3622
 *
3623
 * @see GDALRasterBand::SetOffset()
3624
 */
3625
3626
CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3627
                                       double dfNewOffset)
3628
3629
0
{
3630
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3631
3632
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3633
0
    return poBand->SetOffset(dfNewOffset);
3634
0
}
3635
3636
/************************************************************************/
3637
/*                              GetScale()                              */
3638
/************************************************************************/
3639
3640
/**
3641
 * \brief Fetch the raster value scale.
3642
 *
3643
 * This value (in combination with the GetOffset() value) can be used to
3644
 * transform raw pixel values into the units returned by GetUnitType().
3645
 * For example this might be used to store elevations in GUInt16 bands
3646
 * with a precision of 0.1, and starting from -100.
3647
 *
3648
 * Units value = (raw value * scale) + offset
3649
 *
3650
 * Note that applying scale and offset is of the responsibility of the user,
3651
 * and is not done by methods such as RasterIO() or ReadBlock().
3652
 *
3653
 * For file formats that don't know this intrinsically a value of one
3654
 * is returned.
3655
 *
3656
 * This method is the same as the C function GDALGetRasterScale().
3657
 *
3658
 * @param pbSuccess pointer to a boolean to use to indicate if the
3659
 * returned value is meaningful or not.  May be NULL (default).
3660
 *
3661
 * @return the raster scale.
3662
 */
3663
3664
double GDALRasterBand::GetScale(int *pbSuccess)
3665
3666
0
{
3667
0
    if (pbSuccess != nullptr)
3668
0
        *pbSuccess = FALSE;
3669
3670
0
    return 1.0;
3671
0
}
3672
3673
/************************************************************************/
3674
/*                         GDALGetRasterScale()                         */
3675
/************************************************************************/
3676
3677
/**
3678
 * \brief Fetch the raster value scale.
3679
 *
3680
 * @see GDALRasterBand::GetScale()
3681
 */
3682
3683
double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3684
3685
0
{
3686
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3687
3688
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3689
0
    return poBand->GetScale(pbSuccess);
3690
0
}
3691
3692
/************************************************************************/
3693
/*                              SetScale()                              */
3694
/************************************************************************/
3695
3696
/**
3697
 * \fn GDALRasterBand::SetScale(double)
3698
 * \brief Set scaling ratio.
3699
 *
3700
 * Very few formats implement this method.   When not implemented it will
3701
 * issue a CPLE_NotSupported error and return CE_Failure.
3702
 *
3703
 * This method is the same as the C function GDALSetRasterScale().
3704
 *
3705
 * @param dfNewScale the new scale.
3706
 *
3707
 * @return CE_None or success or CE_Failure on failure.
3708
 */
3709
3710
/**/
3711
/**/
3712
3713
CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3714
3715
0
{
3716
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3717
0
        ReportError(CE_Failure, CPLE_NotSupported,
3718
0
                    "SetScale() not supported on this raster band.");
3719
3720
0
    return CE_Failure;
3721
0
}
3722
3723
/************************************************************************/
3724
/*                        GDALSetRasterScale()                          */
3725
/************************************************************************/
3726
3727
/**
3728
 * \brief Set scaling ratio.
3729
 *
3730
 * @see GDALRasterBand::SetScale()
3731
 */
3732
3733
CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3734
3735
0
{
3736
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3737
3738
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3739
0
    return poBand->SetScale(dfNewOffset);
3740
0
}
3741
3742
/************************************************************************/
3743
/*                            GetUnitType()                             */
3744
/************************************************************************/
3745
3746
/**
3747
 * \brief Return raster unit type.
3748
 *
3749
 * Return a name for the units of this raster's values.  For instance, it
3750
 * might be "m" for an elevation model in meters, or "ft" for feet.  If no
3751
 * units are available, a value of "" will be returned.  The returned string
3752
 * should not be modified, nor freed by the calling application.
3753
 *
3754
 * This method is the same as the C function GDALGetRasterUnitType().
3755
 *
3756
 * @return unit name string.
3757
 */
3758
3759
const char *GDALRasterBand::GetUnitType()
3760
3761
0
{
3762
0
    return "";
3763
0
}
3764
3765
/************************************************************************/
3766
/*                       GDALGetRasterUnitType()                        */
3767
/************************************************************************/
3768
3769
/**
3770
 * \brief Return raster unit type.
3771
 *
3772
 * @see GDALRasterBand::GetUnitType()
3773
 */
3774
3775
const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3776
3777
0
{
3778
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3779
3780
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3781
0
    return poBand->GetUnitType();
3782
0
}
3783
3784
/************************************************************************/
3785
/*                            SetUnitType()                             */
3786
/************************************************************************/
3787
3788
/**
3789
 * \fn GDALRasterBand::SetUnitType(const char*)
3790
 * \brief Set unit type.
3791
 *
3792
 * Set the unit type for a raster band.  Values should be one of
3793
 * "" (the default indicating it is unknown), "m" indicating meters,
3794
 * or "ft" indicating feet, though other nonstandard values are allowed.
3795
 *
3796
 * This method is the same as the C function GDALSetRasterUnitType().
3797
 *
3798
 * @param pszNewValue the new unit type value.
3799
 *
3800
 * @return CE_None on success or CE_Failure if not successful, or
3801
 * unsupported.
3802
 */
3803
3804
/**/
3805
/**/
3806
3807
CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3808
3809
0
{
3810
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3811
0
        ReportError(CE_Failure, CPLE_NotSupported,
3812
0
                    "SetUnitType() not supported on this raster band.");
3813
0
    return CE_Failure;
3814
0
}
3815
3816
/************************************************************************/
3817
/*                       GDALSetRasterUnitType()                        */
3818
/************************************************************************/
3819
3820
/**
3821
 * \brief Set unit type.
3822
 *
3823
 * @see GDALRasterBand::SetUnitType()
3824
 *
3825
 * @since GDAL 1.8.0
3826
 */
3827
3828
CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3829
                                         const char *pszNewValue)
3830
3831
0
{
3832
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3833
3834
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3835
0
    return poBand->SetUnitType(pszNewValue);
3836
0
}
3837
3838
/************************************************************************/
3839
/*                              GetXSize()                              */
3840
/************************************************************************/
3841
3842
/**
3843
 * \brief Fetch XSize of raster.
3844
 *
3845
 * This method is the same as the C function GDALGetRasterBandXSize().
3846
 *
3847
 * @return the width in pixels of this band.
3848
 */
3849
3850
int GDALRasterBand::GetXSize() const
3851
3852
0
{
3853
0
    return nRasterXSize;
3854
0
}
3855
3856
/************************************************************************/
3857
/*                       GDALGetRasterBandXSize()                       */
3858
/************************************************************************/
3859
3860
/**
3861
 * \brief Fetch XSize of raster.
3862
 *
3863
 * @see GDALRasterBand::GetXSize()
3864
 */
3865
3866
int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3867
3868
0
{
3869
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3870
3871
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3872
0
    return poBand->GetXSize();
3873
0
}
3874
3875
/************************************************************************/
3876
/*                              GetYSize()                              */
3877
/************************************************************************/
3878
3879
/**
3880
 * \brief Fetch YSize of raster.
3881
 *
3882
 * This method is the same as the C function GDALGetRasterBandYSize().
3883
 *
3884
 * @return the height in pixels of this band.
3885
 */
3886
3887
int GDALRasterBand::GetYSize() const
3888
3889
0
{
3890
0
    return nRasterYSize;
3891
0
}
3892
3893
/************************************************************************/
3894
/*                       GDALGetRasterBandYSize()                       */
3895
/************************************************************************/
3896
3897
/**
3898
 * \brief Fetch YSize of raster.
3899
 *
3900
 * @see GDALRasterBand::GetYSize()
3901
 */
3902
3903
int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3904
3905
0
{
3906
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3907
3908
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3909
0
    return poBand->GetYSize();
3910
0
}
3911
3912
/************************************************************************/
3913
/*                              GetBand()                               */
3914
/************************************************************************/
3915
3916
/**
3917
 * \brief Fetch the band number.
3918
 *
3919
 * This method returns the band that this GDALRasterBand objects represents
3920
 * within its dataset.  This method may return a value of 0 to indicate
3921
 * GDALRasterBand objects without an apparently relationship to a dataset,
3922
 * such as GDALRasterBands serving as overviews.
3923
 *
3924
 * This method is the same as the C function GDALGetBandNumber().
3925
 *
3926
 * @return band number (1+) or 0 if the band number isn't known.
3927
 */
3928
3929
int GDALRasterBand::GetBand() const
3930
3931
0
{
3932
0
    return nBand;
3933
0
}
3934
3935
/************************************************************************/
3936
/*                         GDALGetBandNumber()                          */
3937
/************************************************************************/
3938
3939
/**
3940
 * \brief Fetch the band number.
3941
 *
3942
 * @see GDALRasterBand::GetBand()
3943
 */
3944
3945
int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3946
3947
0
{
3948
0
    VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3949
3950
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3951
0
    return poBand->GetBand();
3952
0
}
3953
3954
/************************************************************************/
3955
/*                             GetDataset()                             */
3956
/************************************************************************/
3957
3958
/**
3959
 * \brief Fetch the owning dataset handle.
3960
 *
3961
 * Note that some GDALRasterBands are not considered to be a part of a dataset,
3962
 * such as overviews or other "freestanding" bands.
3963
 *
3964
 * This method is the same as the C function GDALGetBandDataset().
3965
 *
3966
 * @return the pointer to the GDALDataset to which this band belongs, or
3967
 * NULL if this cannot be determined.
3968
 */
3969
3970
GDALDataset *GDALRasterBand::GetDataset() const
3971
3972
0
{
3973
0
    return poDS;
3974
0
}
3975
3976
/************************************************************************/
3977
/*                         GDALGetBandDataset()                         */
3978
/************************************************************************/
3979
3980
/**
3981
 * \brief Fetch the owning dataset handle.
3982
 *
3983
 * @see GDALRasterBand::GetDataset()
3984
 */
3985
3986
GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
3987
3988
0
{
3989
0
    VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
3990
3991
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3992
0
    return GDALDataset::ToHandle(poBand->GetDataset());
3993
0
}
3994
3995
/************************************************************************/
3996
/*                        ComputeFloat16NoDataValue()                     */
3997
/************************************************************************/
3998
3999
static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4000
                                             double dfNoDataValue,
4001
                                             int &bGotNoDataValue,
4002
                                             GFloat16 &fNoDataValue,
4003
                                             bool &bGotFloat16NoDataValue)
4004
0
{
4005
0
    if (eDataType == GDT_Float16 && bGotNoDataValue)
4006
0
    {
4007
0
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4008
0
        if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4009
0
        {
4010
0
            fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4011
0
            bGotFloat16NoDataValue = true;
4012
0
            bGotNoDataValue = false;
4013
0
        }
4014
0
    }
4015
0
}
4016
4017
/************************************************************************/
4018
/*                        ComputeFloatNoDataValue()                     */
4019
/************************************************************************/
4020
4021
static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4022
                                           double dfNoDataValue,
4023
                                           int &bGotNoDataValue,
4024
                                           float &fNoDataValue,
4025
                                           bool &bGotFloatNoDataValue)
4026
0
{
4027
0
    if (eDataType == GDT_Float32 && bGotNoDataValue)
4028
0
    {
4029
0
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4030
0
        if (GDALIsValueInRange<float>(dfNoDataValue))
4031
0
        {
4032
0
            fNoDataValue = static_cast<float>(dfNoDataValue);
4033
0
            bGotFloatNoDataValue = true;
4034
0
            bGotNoDataValue = false;
4035
0
        }
4036
0
    }
4037
0
}
4038
4039
/************************************************************************/
4040
/*                        struct GDALNoDataValues                       */
4041
/************************************************************************/
4042
4043
/**
4044
 * \brief No-data-values for all types
4045
 *
4046
 * The functions below pass various no-data-values around. To avoid
4047
 * long argument lists, this struct collects the no-data-values for
4048
 * all types into a single, convenient place.
4049
 **/
4050
4051
struct GDALNoDataValues
4052
{
4053
    int bGotNoDataValue;
4054
    double dfNoDataValue;
4055
4056
    bool bGotFloatNoDataValue;
4057
    float fNoDataValue;
4058
4059
    bool bGotFloat16NoDataValue;
4060
    GFloat16 hfNoDataValue;
4061
4062
    GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4063
0
        : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4064
0
          bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4065
0
          bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4066
0
    {
4067
0
        dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4068
0
        bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4069
4070
0
        ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4071
0
                                fNoDataValue, bGotFloatNoDataValue);
4072
4073
0
        ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4074
0
                                  hfNoDataValue, bGotFloat16NoDataValue);
4075
0
    }
4076
};
4077
4078
/************************************************************************/
4079
/*                            ARE_REAL_EQUAL()                          */
4080
/************************************************************************/
4081
4082
inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4083
0
{
4084
0
    using std::abs;
4085
0
    return dfVal1 == dfVal2 || /* Should cover infinity */
4086
0
           abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4087
0
                                      abs(dfVal1 + dfVal2) * ulp;
4088
0
}
4089
4090
/************************************************************************/
4091
/*                            GetHistogram()                            */
4092
/************************************************************************/
4093
4094
/**
4095
 * \brief Compute raster histogram.
4096
 *
4097
 * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4098
 *
4099
 * For example to compute a simple 256 entry histogram of eight bit data,
4100
 * the following would be suitable.  The unusual bounds are to ensure that
4101
 * bucket boundaries don't fall right on integer values causing possible errors
4102
 * due to rounding after scaling.
4103
\code{.cpp}
4104
    GUIntBig anHistogram[256];
4105
4106
    poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4107
                          GDALDummyProgress, nullptr );
4108
\endcode
4109
 *
4110
 * Note that setting bApproxOK will generally result in a subsampling of the
4111
 * file, and will utilize overviews if available.  It should generally
4112
 * produce a representative histogram for the data that is suitable for use
4113
 * in generating histogram based luts for instance.  Generally bApproxOK is
4114
 * much faster than an exactly computed histogram.
4115
 *
4116
 * This method is the same as the C functions GDALGetRasterHistogram() and
4117
 * GDALGetRasterHistogramEx().
4118
 *
4119
 * @param dfMin the lower bound of the histogram.
4120
 * @param dfMax the upper bound of the histogram.
4121
 * @param nBuckets the number of buckets in panHistogram.
4122
 * @param panHistogram array into which the histogram totals are placed.
4123
 * @param bIncludeOutOfRange if TRUE values below the histogram range will
4124
 * mapped into panHistogram[0], and values above will be mapped into
4125
 * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4126
 * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4127
 * @param pfnProgress function to report progress to completion.
4128
 * @param pProgressData application data to pass to pfnProgress.
4129
 *
4130
 * @return CE_None on success, or CE_Failure if something goes wrong.
4131
 */
4132
4133
CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4134
                                    GUIntBig *panHistogram,
4135
                                    int bIncludeOutOfRange, int bApproxOK,
4136
                                    GDALProgressFunc pfnProgress,
4137
                                    void *pProgressData)
4138
4139
0
{
4140
0
    CPLAssert(nullptr != panHistogram);
4141
4142
0
    if (pfnProgress == nullptr)
4143
0
        pfnProgress = GDALDummyProgress;
4144
4145
    /* -------------------------------------------------------------------- */
4146
    /*      If we have overviews, use them for the histogram.               */
4147
    /* -------------------------------------------------------------------- */
4148
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4149
0
    {
4150
        // FIXME: should we use the most reduced overview here or use some
4151
        // minimum number of samples like GDALRasterBand::ComputeStatistics()
4152
        // does?
4153
0
        GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4154
4155
0
        if (poBestOverview != this)
4156
0
        {
4157
0
            return poBestOverview->GetHistogram(
4158
0
                dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4159
0
                bApproxOK, pfnProgress, pProgressData);
4160
0
        }
4161
0
    }
4162
4163
    /* -------------------------------------------------------------------- */
4164
    /*      Read actual data and build histogram.                           */
4165
    /* -------------------------------------------------------------------- */
4166
0
    if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4167
0
    {
4168
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4169
0
        return CE_Failure;
4170
0
    }
4171
4172
    // Written this way to deal with NaN
4173
0
    if (!(dfMax > dfMin))
4174
0
    {
4175
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4176
0
                    "dfMax should be strictly greater than dfMin");
4177
0
        return CE_Failure;
4178
0
    }
4179
4180
0
    GDALRasterIOExtraArg sExtraArg;
4181
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4182
4183
0
    const double dfScale = nBuckets / (dfMax - dfMin);
4184
0
    if (dfScale == 0 || !std::isfinite(dfScale))
4185
0
    {
4186
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4187
0
                    "dfMin and dfMax should be finite values such that "
4188
0
                    "nBuckets / (dfMax - dfMin) is non-zero");
4189
0
        return CE_Failure;
4190
0
    }
4191
0
    memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4192
4193
0
    GDALNoDataValues sNoDataValues(this, eDataType);
4194
0
    GDALRasterBand *poMaskBand = nullptr;
4195
0
    if (!sNoDataValues.bGotNoDataValue)
4196
0
    {
4197
0
        const int l_nMaskFlags = GetMaskFlags();
4198
0
        if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
4199
0
            GetColorInterpretation() != GCI_AlphaBand)
4200
0
        {
4201
0
            poMaskBand = GetMaskBand();
4202
0
        }
4203
0
    }
4204
4205
0
    bool bSignedByte = false;
4206
0
    if (eDataType == GDT_Byte)
4207
0
    {
4208
0
        EnablePixelTypeSignedByteWarning(false);
4209
0
        const char *pszPixelType =
4210
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4211
0
        EnablePixelTypeSignedByteWarning(true);
4212
0
        bSignedByte =
4213
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4214
0
    }
4215
4216
0
    if (bApproxOK && HasArbitraryOverviews())
4217
0
    {
4218
        /* --------------------------------------------------------------------
4219
         */
4220
        /*      Figure out how much the image should be reduced to get an */
4221
        /*      approximate value. */
4222
        /* --------------------------------------------------------------------
4223
         */
4224
0
        const double dfReduction =
4225
0
            sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4226
0
                 GDALSTAT_APPROX_NUMSAMPLES);
4227
4228
0
        int nXReduced = nRasterXSize;
4229
0
        int nYReduced = nRasterYSize;
4230
0
        if (dfReduction > 1.0)
4231
0
        {
4232
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4233
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4234
4235
            // Catch the case of huge resizing ratios here
4236
0
            if (nXReduced == 0)
4237
0
                nXReduced = 1;
4238
0
            if (nYReduced == 0)
4239
0
                nYReduced = 1;
4240
0
        }
4241
4242
0
        void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4243
0
                                          nXReduced, nYReduced);
4244
0
        if (!pData)
4245
0
            return CE_Failure;
4246
4247
0
        const CPLErr eErr =
4248
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4249
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4250
0
        if (eErr != CE_None)
4251
0
        {
4252
0
            CPLFree(pData);
4253
0
            return eErr;
4254
0
        }
4255
4256
0
        GByte *pabyMaskData = nullptr;
4257
0
        if (poMaskBand)
4258
0
        {
4259
0
            pabyMaskData =
4260
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4261
0
            if (!pabyMaskData)
4262
0
            {
4263
0
                CPLFree(pData);
4264
0
                return CE_Failure;
4265
0
            }
4266
4267
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4268
0
                                     pabyMaskData, nXReduced, nYReduced,
4269
0
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
4270
0
            {
4271
0
                CPLFree(pData);
4272
0
                CPLFree(pabyMaskData);
4273
0
                return CE_Failure;
4274
0
            }
4275
0
        }
4276
4277
        // This isn't the fastest way to do this, but is easier for now.
4278
0
        for (int iY = 0; iY < nYReduced; iY++)
4279
0
        {
4280
0
            for (int iX = 0; iX < nXReduced; iX++)
4281
0
            {
4282
0
                const int iOffset = iX + iY * nXReduced;
4283
0
                double dfValue = 0.0;
4284
4285
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
4286
0
                    continue;
4287
4288
0
                switch (eDataType)
4289
0
                {
4290
0
                    case GDT_Byte:
4291
0
                    {
4292
0
                        if (bSignedByte)
4293
0
                            dfValue =
4294
0
                                static_cast<signed char *>(pData)[iOffset];
4295
0
                        else
4296
0
                            dfValue = static_cast<GByte *>(pData)[iOffset];
4297
0
                        break;
4298
0
                    }
4299
0
                    case GDT_Int8:
4300
0
                        dfValue = static_cast<GInt8 *>(pData)[iOffset];
4301
0
                        break;
4302
0
                    case GDT_UInt16:
4303
0
                        dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4304
0
                        break;
4305
0
                    case GDT_Int16:
4306
0
                        dfValue = static_cast<GInt16 *>(pData)[iOffset];
4307
0
                        break;
4308
0
                    case GDT_UInt32:
4309
0
                        dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4310
0
                        break;
4311
0
                    case GDT_Int32:
4312
0
                        dfValue = static_cast<GInt32 *>(pData)[iOffset];
4313
0
                        break;
4314
0
                    case GDT_UInt64:
4315
0
                        dfValue = static_cast<double>(
4316
0
                            static_cast<GUInt64 *>(pData)[iOffset]);
4317
0
                        break;
4318
0
                    case GDT_Int64:
4319
0
                        dfValue = static_cast<double>(
4320
0
                            static_cast<GInt64 *>(pData)[iOffset]);
4321
0
                        break;
4322
0
                    case GDT_Float16:
4323
0
                    {
4324
0
                        using namespace std;
4325
0
                        const GFloat16 hfValue =
4326
0
                            static_cast<GFloat16 *>(pData)[iOffset];
4327
0
                        if (isnan(hfValue) ||
4328
0
                            (sNoDataValues.bGotFloat16NoDataValue &&
4329
0
                             ARE_REAL_EQUAL(hfValue,
4330
0
                                            sNoDataValues.hfNoDataValue)))
4331
0
                            continue;
4332
0
                        dfValue = hfValue;
4333
0
                        break;
4334
0
                    }
4335
0
                    case GDT_Float32:
4336
0
                    {
4337
0
                        const float fValue =
4338
0
                            static_cast<float *>(pData)[iOffset];
4339
0
                        if (std::isnan(fValue) ||
4340
0
                            (sNoDataValues.bGotFloatNoDataValue &&
4341
0
                             ARE_REAL_EQUAL(fValue,
4342
0
                                            sNoDataValues.fNoDataValue)))
4343
0
                            continue;
4344
0
                        dfValue = fValue;
4345
0
                        break;
4346
0
                    }
4347
0
                    case GDT_Float64:
4348
0
                        dfValue = static_cast<double *>(pData)[iOffset];
4349
0
                        if (std::isnan(dfValue))
4350
0
                            continue;
4351
0
                        break;
4352
0
                    case GDT_CInt16:
4353
0
                    {
4354
0
                        const double dfReal =
4355
0
                            static_cast<GInt16 *>(pData)[iOffset * 2];
4356
0
                        const double dfImag =
4357
0
                            static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4358
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4359
0
                            continue;
4360
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4361
0
                    }
4362
0
                    break;
4363
0
                    case GDT_CInt32:
4364
0
                    {
4365
0
                        const double dfReal =
4366
0
                            static_cast<GInt32 *>(pData)[iOffset * 2];
4367
0
                        const double dfImag =
4368
0
                            static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4369
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4370
0
                            continue;
4371
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4372
0
                    }
4373
0
                    break;
4374
0
                    case GDT_CFloat16:
4375
0
                    {
4376
0
                        const double dfReal =
4377
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2];
4378
0
                        const double dfImag =
4379
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4380
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4381
0
                            continue;
4382
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4383
0
                        break;
4384
0
                    }
4385
0
                    case GDT_CFloat32:
4386
0
                    {
4387
0
                        const double dfReal =
4388
0
                            static_cast<float *>(pData)[iOffset * 2];
4389
0
                        const double dfImag =
4390
0
                            static_cast<float *>(pData)[iOffset * 2 + 1];
4391
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4392
0
                            continue;
4393
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4394
0
                        break;
4395
0
                    }
4396
0
                    case GDT_CFloat64:
4397
0
                    {
4398
0
                        const double dfReal =
4399
0
                            static_cast<double *>(pData)[iOffset * 2];
4400
0
                        const double dfImag =
4401
0
                            static_cast<double *>(pData)[iOffset * 2 + 1];
4402
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4403
0
                            continue;
4404
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4405
0
                        break;
4406
0
                    }
4407
0
                    case GDT_Unknown:
4408
0
                    case GDT_TypeCount:
4409
0
                        CPLAssert(false);
4410
0
                }
4411
4412
0
                if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4413
0
                    sNoDataValues.bGotNoDataValue &&
4414
0
                    ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4415
0
                    continue;
4416
4417
                // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4418
                // finite, the result of the multiplication cannot be NaN
4419
0
                const double dfIndex = floor((dfValue - dfMin) * dfScale);
4420
4421
0
                if (dfIndex < 0)
4422
0
                {
4423
0
                    if (bIncludeOutOfRange)
4424
0
                        panHistogram[0]++;
4425
0
                }
4426
0
                else if (dfIndex >= nBuckets)
4427
0
                {
4428
0
                    if (bIncludeOutOfRange)
4429
0
                        ++panHistogram[nBuckets - 1];
4430
0
                }
4431
0
                else
4432
0
                {
4433
0
                    ++panHistogram[static_cast<int>(dfIndex)];
4434
0
                }
4435
0
            }
4436
0
        }
4437
4438
0
        CPLFree(pData);
4439
0
        CPLFree(pabyMaskData);
4440
0
    }
4441
0
    else  // No arbitrary overviews.
4442
0
    {
4443
0
        if (!InitBlockInfo())
4444
0
            return CE_Failure;
4445
4446
        /* --------------------------------------------------------------------
4447
         */
4448
        /*      Figure out the ratio of blocks we will read to get an */
4449
        /*      approximate value. */
4450
        /* --------------------------------------------------------------------
4451
         */
4452
4453
0
        int nSampleRate = 1;
4454
0
        if (bApproxOK)
4455
0
        {
4456
0
            nSampleRate = static_cast<int>(std::max(
4457
0
                1.0,
4458
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4459
            // We want to avoid probing only the first column of blocks for
4460
            // a square shaped raster, because it is not unlikely that it may
4461
            // be padding only (#6378).
4462
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4463
0
                nSampleRate += 1;
4464
0
        }
4465
4466
0
        GByte *pabyMaskData = nullptr;
4467
0
        if (poMaskBand)
4468
0
        {
4469
0
            pabyMaskData = static_cast<GByte *>(
4470
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4471
0
            if (!pabyMaskData)
4472
0
            {
4473
0
                return CE_Failure;
4474
0
            }
4475
0
        }
4476
4477
        /* --------------------------------------------------------------------
4478
         */
4479
        /*      Read the blocks, and add to histogram. */
4480
        /* --------------------------------------------------------------------
4481
         */
4482
0
        for (GIntBig iSampleBlock = 0;
4483
0
             iSampleBlock <
4484
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4485
0
             iSampleBlock += nSampleRate)
4486
0
        {
4487
0
            if (!pfnProgress(
4488
0
                    static_cast<double>(iSampleBlock) /
4489
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4490
0
                    "Compute Histogram", pProgressData))
4491
0
            {
4492
0
                CPLFree(pabyMaskData);
4493
0
                return CE_Failure;
4494
0
            }
4495
4496
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4497
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4498
4499
0
            GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4500
0
            if (poBlock == nullptr)
4501
0
            {
4502
0
                CPLFree(pabyMaskData);
4503
0
                return CE_Failure;
4504
0
            }
4505
4506
0
            void *pData = poBlock->GetDataRef();
4507
4508
0
            int nXCheck = 0, nYCheck = 0;
4509
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4510
4511
0
            if (poMaskBand &&
4512
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4513
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
4514
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4515
0
                                     0, nBlockXSize, nullptr) != CE_None)
4516
0
            {
4517
0
                CPLFree(pabyMaskData);
4518
0
                poBlock->DropLock();
4519
0
                return CE_Failure;
4520
0
            }
4521
4522
            // this is a special case for a common situation.
4523
0
            if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4524
0
                (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4525
0
                nXCheck == nBlockXSize && nBuckets == 256)
4526
0
            {
4527
0
                const GPtrDiff_t nPixels =
4528
0
                    static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4529
0
                GByte *pabyData = static_cast<GByte *>(pData);
4530
4531
0
                for (GPtrDiff_t i = 0; i < nPixels; i++)
4532
0
                {
4533
0
                    if (pabyMaskData && pabyMaskData[i] == 0)
4534
0
                        continue;
4535
0
                    if (!(sNoDataValues.bGotNoDataValue &&
4536
0
                          (pabyData[i] ==
4537
0
                           static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4538
0
                    {
4539
0
                        panHistogram[pabyData[i]]++;
4540
0
                    }
4541
0
                }
4542
4543
0
                poBlock->DropLock();
4544
0
                continue;  // To next sample block.
4545
0
            }
4546
4547
            // This isn't the fastest way to do this, but is easier for now.
4548
0
            for (int iY = 0; iY < nYCheck; iY++)
4549
0
            {
4550
0
                for (int iX = 0; iX < nXCheck; iX++)
4551
0
                {
4552
0
                    const GPtrDiff_t iOffset =
4553
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4554
4555
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
4556
0
                        continue;
4557
4558
0
                    double dfValue = 0.0;
4559
4560
0
                    switch (eDataType)
4561
0
                    {
4562
0
                        case GDT_Byte:
4563
0
                        {
4564
0
                            if (bSignedByte)
4565
0
                                dfValue =
4566
0
                                    static_cast<signed char *>(pData)[iOffset];
4567
0
                            else
4568
0
                                dfValue = static_cast<GByte *>(pData)[iOffset];
4569
0
                            break;
4570
0
                        }
4571
0
                        case GDT_Int8:
4572
0
                            dfValue = static_cast<GInt8 *>(pData)[iOffset];
4573
0
                            break;
4574
0
                        case GDT_UInt16:
4575
0
                            dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4576
0
                            break;
4577
0
                        case GDT_Int16:
4578
0
                            dfValue = static_cast<GInt16 *>(pData)[iOffset];
4579
0
                            break;
4580
0
                        case GDT_UInt32:
4581
0
                            dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4582
0
                            break;
4583
0
                        case GDT_Int32:
4584
0
                            dfValue = static_cast<GInt32 *>(pData)[iOffset];
4585
0
                            break;
4586
0
                        case GDT_UInt64:
4587
0
                            dfValue = static_cast<double>(
4588
0
                                static_cast<GUInt64 *>(pData)[iOffset]);
4589
0
                            break;
4590
0
                        case GDT_Int64:
4591
0
                            dfValue = static_cast<double>(
4592
0
                                static_cast<GInt64 *>(pData)[iOffset]);
4593
0
                            break;
4594
0
                        case GDT_Float16:
4595
0
                        {
4596
0
                            using namespace std;
4597
0
                            const GFloat16 hfValue =
4598
0
                                static_cast<GFloat16 *>(pData)[iOffset];
4599
0
                            if (isnan(hfValue) ||
4600
0
                                (sNoDataValues.bGotFloat16NoDataValue &&
4601
0
                                 ARE_REAL_EQUAL(hfValue,
4602
0
                                                sNoDataValues.hfNoDataValue)))
4603
0
                                continue;
4604
0
                            dfValue = hfValue;
4605
0
                            break;
4606
0
                        }
4607
0
                        case GDT_Float32:
4608
0
                        {
4609
0
                            const float fValue =
4610
0
                                static_cast<float *>(pData)[iOffset];
4611
0
                            if (std::isnan(fValue) ||
4612
0
                                (sNoDataValues.bGotFloatNoDataValue &&
4613
0
                                 ARE_REAL_EQUAL(fValue,
4614
0
                                                sNoDataValues.fNoDataValue)))
4615
0
                                continue;
4616
0
                            dfValue = fValue;
4617
0
                            break;
4618
0
                        }
4619
0
                        case GDT_Float64:
4620
0
                            dfValue = static_cast<double *>(pData)[iOffset];
4621
0
                            if (std::isnan(dfValue))
4622
0
                                continue;
4623
0
                            break;
4624
0
                        case GDT_CInt16:
4625
0
                        {
4626
0
                            double dfReal =
4627
0
                                static_cast<GInt16 *>(pData)[iOffset * 2];
4628
0
                            double dfImag =
4629
0
                                static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4630
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4631
0
                            break;
4632
0
                        }
4633
0
                        case GDT_CInt32:
4634
0
                        {
4635
0
                            double dfReal =
4636
0
                                static_cast<GInt32 *>(pData)[iOffset * 2];
4637
0
                            double dfImag =
4638
0
                                static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4639
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4640
0
                            break;
4641
0
                        }
4642
0
                        case GDT_CFloat16:
4643
0
                        {
4644
0
                            double dfReal =
4645
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2];
4646
0
                            double dfImag =
4647
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4648
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4649
0
                                continue;
4650
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4651
0
                            break;
4652
0
                        }
4653
0
                        case GDT_CFloat32:
4654
0
                        {
4655
0
                            double dfReal =
4656
0
                                static_cast<float *>(pData)[iOffset * 2];
4657
0
                            double dfImag =
4658
0
                                static_cast<float *>(pData)[iOffset * 2 + 1];
4659
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4660
0
                                continue;
4661
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4662
0
                            break;
4663
0
                        }
4664
0
                        case GDT_CFloat64:
4665
0
                        {
4666
0
                            double dfReal =
4667
0
                                static_cast<double *>(pData)[iOffset * 2];
4668
0
                            double dfImag =
4669
0
                                static_cast<double *>(pData)[iOffset * 2 + 1];
4670
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4671
0
                                continue;
4672
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4673
0
                            break;
4674
0
                        }
4675
0
                        case GDT_Unknown:
4676
0
                        case GDT_TypeCount:
4677
0
                            CPLAssert(false);
4678
0
                            CPLFree(pabyMaskData);
4679
0
                            return CE_Failure;
4680
0
                    }
4681
4682
0
                    if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4683
0
                        sNoDataValues.bGotNoDataValue &&
4684
0
                        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4685
0
                        continue;
4686
4687
                    // Given that dfValue and dfMin are not NaN, and dfScale > 0
4688
                    // and finite, the result of the multiplication cannot be
4689
                    // NaN
4690
0
                    const double dfIndex = floor((dfValue - dfMin) * dfScale);
4691
4692
0
                    if (dfIndex < 0)
4693
0
                    {
4694
0
                        if (bIncludeOutOfRange)
4695
0
                            panHistogram[0]++;
4696
0
                    }
4697
0
                    else if (dfIndex >= nBuckets)
4698
0
                    {
4699
0
                        if (bIncludeOutOfRange)
4700
0
                            ++panHistogram[nBuckets - 1];
4701
0
                    }
4702
0
                    else
4703
0
                    {
4704
0
                        ++panHistogram[static_cast<int>(dfIndex)];
4705
0
                    }
4706
0
                }
4707
0
            }
4708
4709
0
            poBlock->DropLock();
4710
0
        }
4711
4712
0
        CPLFree(pabyMaskData);
4713
0
    }
4714
4715
0
    pfnProgress(1.0, "Compute Histogram", pProgressData);
4716
4717
0
    return CE_None;
4718
0
}
4719
4720
/************************************************************************/
4721
/*                       GDALGetRasterHistogram()                       */
4722
/************************************************************************/
4723
4724
/**
4725
 * \brief Compute raster histogram.
4726
 *
4727
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4728
 * exceeding 2 billion.
4729
 *
4730
 * @see GDALRasterBand::GetHistogram()
4731
 * @see GDALGetRasterHistogramEx()
4732
 */
4733
4734
CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4735
                                          double dfMax, int nBuckets,
4736
                                          int *panHistogram,
4737
                                          int bIncludeOutOfRange, int bApproxOK,
4738
                                          GDALProgressFunc pfnProgress,
4739
                                          void *pProgressData)
4740
4741
0
{
4742
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4743
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4744
4745
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4746
4747
0
    GUIntBig *panHistogramTemp =
4748
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4749
0
    if (panHistogramTemp == nullptr)
4750
0
    {
4751
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4752
0
                            "Out of memory in GDALGetRasterHistogram().");
4753
0
        return CE_Failure;
4754
0
    }
4755
4756
0
    CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4757
0
                                       bIncludeOutOfRange, bApproxOK,
4758
0
                                       pfnProgress, pProgressData);
4759
4760
0
    if (eErr == CE_None)
4761
0
    {
4762
0
        for (int i = 0; i < nBuckets; i++)
4763
0
        {
4764
0
            if (panHistogramTemp[i] > INT_MAX)
4765
0
            {
4766
0
                CPLError(CE_Warning, CPLE_AppDefined,
4767
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
4768
0
                         " exceeds maximum 32 bit value",
4769
0
                         i, panHistogramTemp[i]);
4770
0
                panHistogram[i] = INT_MAX;
4771
0
            }
4772
0
            else
4773
0
            {
4774
0
                panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4775
0
            }
4776
0
        }
4777
0
    }
4778
4779
0
    CPLFree(panHistogramTemp);
4780
4781
0
    return eErr;
4782
0
}
4783
4784
/************************************************************************/
4785
/*                      GDALGetRasterHistogramEx()                      */
4786
/************************************************************************/
4787
4788
/**
4789
 * \brief Compute raster histogram.
4790
 *
4791
 * @see GDALRasterBand::GetHistogram()
4792
 *
4793
 * @since GDAL 2.0
4794
 */
4795
4796
CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4797
    GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4798
    GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4799
    GDALProgressFunc pfnProgress, void *pProgressData)
4800
4801
0
{
4802
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4803
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4804
4805
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4806
4807
0
    return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4808
0
                                bIncludeOutOfRange, bApproxOK, pfnProgress,
4809
0
                                pProgressData);
4810
0
}
4811
4812
/************************************************************************/
4813
/*                        GetDefaultHistogram()                         */
4814
/************************************************************************/
4815
4816
/**
4817
 * \brief Fetch default raster histogram.
4818
 *
4819
 * The default method in GDALRasterBand will compute a default histogram. This
4820
 * method is overridden by derived classes (such as GDALPamRasterBand,
4821
 * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4822
 * stored histogram.
4823
 *
4824
 * This method is the same as the C functions GDALGetDefaultHistogram() and
4825
 * GDALGetDefaultHistogramEx().
4826
 *
4827
 * @param pdfMin pointer to double value that will contain the lower bound of
4828
 * the histogram.
4829
 * @param pdfMax pointer to double value that will contain the upper bound of
4830
 * the histogram.
4831
 * @param pnBuckets pointer to int value that will contain the number of buckets
4832
 * in *ppanHistogram.
4833
 * @param ppanHistogram pointer to array into which the histogram totals are
4834
 * placed. To be freed with VSIFree
4835
 * @param bForce TRUE to force the computation. If FALSE and no default
4836
 * histogram is available, the method will return CE_Warning
4837
 * @param pfnProgress function to report progress to completion.
4838
 * @param pProgressData application data to pass to pfnProgress.
4839
 *
4840
 * @return CE_None on success, CE_Failure if something goes wrong, or
4841
 * CE_Warning if no default histogram is available.
4842
 */
4843
4844
CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4845
                                           int *pnBuckets,
4846
                                           GUIntBig **ppanHistogram, int bForce,
4847
                                           GDALProgressFunc pfnProgress,
4848
                                           void *pProgressData)
4849
4850
0
{
4851
0
    CPLAssert(nullptr != pnBuckets);
4852
0
    CPLAssert(nullptr != ppanHistogram);
4853
0
    CPLAssert(nullptr != pdfMin);
4854
0
    CPLAssert(nullptr != pdfMax);
4855
4856
0
    *pnBuckets = 0;
4857
0
    *ppanHistogram = nullptr;
4858
4859
0
    if (!bForce)
4860
0
        return CE_Warning;
4861
4862
0
    const int nBuckets = 256;
4863
4864
0
    bool bSignedByte = false;
4865
0
    if (eDataType == GDT_Byte)
4866
0
    {
4867
0
        EnablePixelTypeSignedByteWarning(false);
4868
0
        const char *pszPixelType =
4869
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4870
0
        EnablePixelTypeSignedByteWarning(true);
4871
0
        bSignedByte =
4872
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4873
0
    }
4874
4875
0
    if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4876
0
    {
4877
0
        *pdfMin = -0.5;
4878
0
        *pdfMax = 255.5;
4879
0
    }
4880
0
    else
4881
0
    {
4882
4883
0
        const CPLErr eErr =
4884
0
            GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4885
0
        const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4886
0
        *pdfMin -= dfHalfBucket;
4887
0
        *pdfMax += dfHalfBucket;
4888
4889
0
        if (eErr != CE_None)
4890
0
            return eErr;
4891
0
    }
4892
4893
0
    *ppanHistogram =
4894
0
        static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4895
0
    if (*ppanHistogram == nullptr)
4896
0
    {
4897
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
4898
0
                    "Out of memory in InitBlockInfo().");
4899
0
        return CE_Failure;
4900
0
    }
4901
4902
0
    *pnBuckets = nBuckets;
4903
0
    CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4904
0
                               TRUE, FALSE, pfnProgress, pProgressData);
4905
0
    if (eErr != CE_None)
4906
0
    {
4907
0
        *pnBuckets = 0;
4908
0
    }
4909
0
    return eErr;
4910
0
}
4911
4912
/************************************************************************/
4913
/*                      GDALGetDefaultHistogram()                       */
4914
/************************************************************************/
4915
4916
/**
4917
 * \brief Fetch default raster histogram.
4918
 *
4919
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4920
 * exceeding 2 billion.
4921
 *
4922
 * @see GDALRasterBand::GDALGetDefaultHistogram()
4923
 * @see GDALGetRasterHistogramEx()
4924
 */
4925
4926
CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4927
                                           double *pdfMin, double *pdfMax,
4928
                                           int *pnBuckets, int **ppanHistogram,
4929
                                           int bForce,
4930
                                           GDALProgressFunc pfnProgress,
4931
                                           void *pProgressData)
4932
4933
0
{
4934
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4935
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4936
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4937
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4938
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4939
4940
0
    GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4941
0
    GUIntBig *panHistogramTemp = nullptr;
4942
0
    CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
4943
0
                                              &panHistogramTemp, bForce,
4944
0
                                              pfnProgress, pProgressData);
4945
0
    if (eErr == CE_None)
4946
0
    {
4947
0
        const int nBuckets = *pnBuckets;
4948
0
        *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
4949
0
        if (*ppanHistogram == nullptr)
4950
0
        {
4951
0
            poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4952
0
                                "Out of memory in GDALGetDefaultHistogram().");
4953
0
            VSIFree(panHistogramTemp);
4954
0
            return CE_Failure;
4955
0
        }
4956
4957
0
        for (int i = 0; i < nBuckets; ++i)
4958
0
        {
4959
0
            if (panHistogramTemp[i] > INT_MAX)
4960
0
            {
4961
0
                CPLError(CE_Warning, CPLE_AppDefined,
4962
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
4963
0
                         " exceeds maximum 32 bit value",
4964
0
                         i, panHistogramTemp[i]);
4965
0
                (*ppanHistogram)[i] = INT_MAX;
4966
0
            }
4967
0
            else
4968
0
            {
4969
0
                (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
4970
0
            }
4971
0
        }
4972
4973
0
        CPLFree(panHistogramTemp);
4974
0
    }
4975
0
    else
4976
0
    {
4977
0
        *ppanHistogram = nullptr;
4978
0
    }
4979
4980
0
    return eErr;
4981
0
}
4982
4983
/************************************************************************/
4984
/*                      GDALGetDefaultHistogramEx()                     */
4985
/************************************************************************/
4986
4987
/**
4988
 * \brief Fetch default raster histogram.
4989
 *
4990
 * @see GDALRasterBand::GetDefaultHistogram()
4991
 *
4992
 * @since GDAL 2.0
4993
 */
4994
4995
CPLErr CPL_STDCALL
4996
GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
4997
                          int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
4998
                          GDALProgressFunc pfnProgress, void *pProgressData)
4999
5000
0
{
5001
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5002
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5003
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5004
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5005
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5006
5007
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5008
0
    return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5009
0
                                       bForce, pfnProgress, pProgressData);
5010
0
}
5011
5012
/************************************************************************/
5013
/*                             AdviseRead()                             */
5014
/************************************************************************/
5015
5016
/**
5017
 * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5018
 * \brief Advise driver of upcoming read requests.
5019
 *
5020
 * Some GDAL drivers operate more efficiently if they know in advance what
5021
 * set of upcoming read requests will be made.  The AdviseRead() method allows
5022
 * an application to notify the driver of the region of interest,
5023
 * and at what resolution the region will be read.
5024
 *
5025
 * Many drivers just ignore the AdviseRead() call, but it can dramatically
5026
 * accelerate access via some drivers.
5027
 *
5028
 * Depending on call paths, drivers might receive several calls to
5029
 * AdviseRead() with the same parameters.
5030
 *
5031
 * @param nXOff The pixel offset to the top left corner of the region
5032
 * of the band to be accessed.  This would be zero to start from the left side.
5033
 *
5034
 * @param nYOff The line offset to the top left corner of the region
5035
 * of the band to be accessed.  This would be zero to start from the top.
5036
 *
5037
 * @param nXSize The width of the region of the band to be accessed in pixels.
5038
 *
5039
 * @param nYSize The height of the region of the band to be accessed in lines.
5040
 *
5041
 * @param nBufXSize the width of the buffer image into which the desired region
5042
 * is to be read, or from which it is to be written.
5043
 *
5044
 * @param nBufYSize the height of the buffer image into which the desired
5045
 * region is to be read, or from which it is to be written.
5046
 *
5047
 * @param eBufType the type of the pixel values in the pData data buffer.  The
5048
 * pixel values will automatically be translated to/from the GDALRasterBand
5049
 * data type as needed.
5050
 *
5051
 * @param papszOptions a list of name=value strings with special control
5052
 * options.  Normally this is NULL.
5053
 *
5054
 * @return CE_Failure if the request is invalid and CE_None if it works or
5055
 * is ignored.
5056
 */
5057
5058
/**/
5059
/**/
5060
5061
CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5062
                                  int /*nYSize*/, int /*nBufXSize*/,
5063
                                  int /*nBufYSize*/, GDALDataType /*eBufType*/,
5064
                                  char ** /*papszOptions*/)
5065
0
{
5066
0
    return CE_None;
5067
0
}
5068
5069
/************************************************************************/
5070
/*                        GDALRasterAdviseRead()                        */
5071
/************************************************************************/
5072
5073
/**
5074
 * \brief Advise driver of upcoming read requests.
5075
 *
5076
 * @see GDALRasterBand::AdviseRead()
5077
 */
5078
5079
CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5080
                                        int nYOff, int nXSize, int nYSize,
5081
                                        int nBufXSize, int nBufYSize,
5082
                                        GDALDataType eDT,
5083
                                        CSLConstList papszOptions)
5084
5085
0
{
5086
0
    VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5087
5088
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5089
0
    return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5090
0
                              nBufYSize, eDT,
5091
0
                              const_cast<char **>(papszOptions));
5092
0
}
5093
5094
/************************************************************************/
5095
/*                           GetStatistics()                            */
5096
/************************************************************************/
5097
5098
/**
5099
 * \brief Fetch image statistics.
5100
 *
5101
 * Returns the minimum, maximum, mean and standard deviation of all
5102
 * pixel values in this band.  If approximate statistics are sufficient,
5103
 * the bApproxOK flag can be set to true in which case overviews, or a
5104
 * subset of image tiles may be used in computing the statistics.
5105
 *
5106
 * If bForce is FALSE results will only be returned if it can be done
5107
 * quickly (i.e. without scanning the image, typically by using pre-existing
5108
 * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5109
 * returned efficiently, the method will return CE_Warning but no warning will
5110
 * be issued. This is a non-standard use of the CE_Warning return value
5111
 * to indicate "nothing done".
5112
 *
5113
 * If bForce is TRUE, and results are quickly available without scanning the
5114
 * image, they will be used. If bForce is TRUE and results are not quickly
5115
 * available, GetStatistics() forwards the computation to ComputeStatistics(),
5116
 * which will scan the image.
5117
 *
5118
 * To always force recomputation of statistics, use ComputeStatistics() instead
5119
 * of this method.
5120
 *
5121
 * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5122
 * will generally cache statistics in the .pam file allowing fast fetch
5123
 * after the first request.
5124
 *
5125
 * This method is the same as the C function GDALGetRasterStatistics().
5126
 *
5127
 * @param bApproxOK If TRUE statistics may be computed based on overviews
5128
 * or a subset of all tiles.
5129
 *
5130
 * @param bForce If FALSE statistics will only be returned if it can
5131
 * be done without rescanning the image. If TRUE, statistics computation will
5132
 * be forced if pre-existing values are not quickly available.
5133
 *
5134
 * @param pdfMin Location into which to load image minimum (may be NULL).
5135
 *
5136
 * @param pdfMax Location into which to load image maximum (may be NULL).-
5137
 *
5138
 * @param pdfMean Location into which to load image mean (may be NULL).
5139
 *
5140
 * @param pdfStdDev Location into which to load image standard deviation
5141
 * (may be NULL).
5142
 *
5143
 * @return CE_None on success, CE_Warning if no values returned,
5144
 * CE_Failure if an error occurs.
5145
 */
5146
5147
CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5148
                                     double *pdfMax, double *pdfMean,
5149
                                     double *pdfStdDev)
5150
5151
0
{
5152
    /* -------------------------------------------------------------------- */
5153
    /*      Do we already have metadata items for the requested values?     */
5154
    /* -------------------------------------------------------------------- */
5155
0
    if ((pdfMin == nullptr ||
5156
0
         GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5157
0
        (pdfMax == nullptr ||
5158
0
         GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5159
0
        (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5160
0
        (pdfStdDev == nullptr ||
5161
0
         GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5162
0
    {
5163
0
        if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5164
0
        {
5165
0
            if (pdfMin != nullptr)
5166
0
                *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5167
0
            if (pdfMax != nullptr)
5168
0
                *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5169
0
            if (pdfMean != nullptr)
5170
0
                *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5171
0
            if (pdfStdDev != nullptr)
5172
0
                *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5173
5174
0
            return CE_None;
5175
0
        }
5176
0
    }
5177
5178
    /* -------------------------------------------------------------------- */
5179
    /*      Does the driver already know the min/max?                       */
5180
    /* -------------------------------------------------------------------- */
5181
0
    if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5182
0
    {
5183
0
        int bSuccessMin = FALSE;
5184
0
        int bSuccessMax = FALSE;
5185
5186
0
        const double dfMin = GetMinimum(&bSuccessMin);
5187
0
        const double dfMax = GetMaximum(&bSuccessMax);
5188
5189
0
        if (bSuccessMin && bSuccessMax)
5190
0
        {
5191
0
            if (pdfMin != nullptr)
5192
0
                *pdfMin = dfMin;
5193
0
            if (pdfMax != nullptr)
5194
0
                *pdfMax = dfMax;
5195
0
            return CE_None;
5196
0
        }
5197
0
    }
5198
5199
    /* -------------------------------------------------------------------- */
5200
    /*      Either return without results, or force computation.            */
5201
    /* -------------------------------------------------------------------- */
5202
0
    if (!bForce)
5203
0
        return CE_Warning;
5204
0
    else
5205
0
        return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5206
0
                                 GDALDummyProgress, nullptr);
5207
0
}
5208
5209
/************************************************************************/
5210
/*                      GDALGetRasterStatistics()                       */
5211
/************************************************************************/
5212
5213
/**
5214
 * \brief Fetch image statistics.
5215
 *
5216
 * @see GDALRasterBand::GetStatistics()
5217
 */
5218
5219
CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5220
                                           int bForce, double *pdfMin,
5221
                                           double *pdfMax, double *pdfMean,
5222
                                           double *pdfStdDev)
5223
5224
0
{
5225
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5226
5227
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5228
0
    return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5229
0
                                 pdfStdDev);
5230
0
}
5231
5232
/************************************************************************/
5233
/*                         GDALUInt128                                  */
5234
/************************************************************************/
5235
5236
#ifdef HAVE_UINT128_T
5237
class GDALUInt128
5238
{
5239
    __uint128_t val;
5240
5241
0
    explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5242
0
    {
5243
0
    }
5244
5245
  public:
5246
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5247
0
    {
5248
        // Evaluates to just a single mul on x86_64
5249
0
        return GDALUInt128(static_cast<__uint128_t>(first) * second);
5250
0
    }
5251
5252
    GDALUInt128 operator-(const GDALUInt128 &other) const
5253
0
    {
5254
0
        return GDALUInt128(val - other.val);
5255
0
    }
5256
5257
    operator double() const
5258
0
    {
5259
0
        return static_cast<double>(val);
5260
0
    }
5261
};
5262
#else
5263
5264
#if defined(_MSC_VER) && defined(_M_X64)
5265
#include <intrin.h>
5266
#endif
5267
5268
class GDALUInt128
5269
{
5270
    GUIntBig low, high;
5271
5272
    GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5273
    {
5274
    }
5275
5276
  public:
5277
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5278
    {
5279
#if defined(_MSC_VER) && defined(_M_X64)
5280
        GUIntBig highRes;
5281
        GUIntBig lowRes = _umul128(first, second, &highRes);
5282
        return GDALUInt128(lowRes, highRes);
5283
#else
5284
        const GUInt32 firstLow = static_cast<GUInt32>(first);
5285
        const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5286
        const GUInt32 secondLow = static_cast<GUInt32>(second);
5287
        const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5288
        GUIntBig highRes = 0;
5289
        const GUIntBig firstLowSecondHigh =
5290
            static_cast<GUIntBig>(firstLow) * secondHigh;
5291
        const GUIntBig firstHighSecondLow =
5292
            static_cast<GUIntBig>(firstHigh) * secondLow;
5293
        const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5294
        if (middleTerm < firstLowSecondHigh)  // check for overflow
5295
            highRes += static_cast<GUIntBig>(1) << 32;
5296
        const GUIntBig firstLowSecondLow =
5297
            static_cast<GUIntBig>(firstLow) * secondLow;
5298
        GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5299
        if (lowRes < firstLowSecondLow)  // check for overflow
5300
            highRes++;
5301
        highRes +=
5302
            (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5303
        return GDALUInt128(lowRes, highRes);
5304
#endif
5305
    }
5306
5307
    GDALUInt128 operator-(const GDALUInt128 &other) const
5308
    {
5309
        GUIntBig highRes = high - other.high;
5310
        GUIntBig lowRes = low - other.low;
5311
        if (lowRes > low)  // check for underflow
5312
            --highRes;
5313
        return GDALUInt128(lowRes, highRes);
5314
    }
5315
5316
    operator double() const
5317
    {
5318
        const double twoPow64 = 18446744073709551616.0;
5319
        return high * twoPow64 + low;
5320
    }
5321
};
5322
#endif
5323
5324
/************************************************************************/
5325
/*                    ComputeStatisticsInternal()                       */
5326
/************************************************************************/
5327
5328
// Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5329
// not needed.
5330
0
#define static_cast_for_coverity_scan static_cast
5331
5332
// The rationale for below optimizations is detailed in statistics.txt
5333
5334
// Use with T = GByte or GUInt16 only !
5335
template <class T, bool COMPUTE_OTHER_STATS>
5336
struct ComputeStatisticsInternalGeneric
5337
{
5338
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5339
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5340
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5341
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5342
0
    {
5343
0
        static_assert(std::is_same<T, GByte>::value ||
5344
0
                          std::is_same<T, GUInt16>::value,
5345
0
                      "bad type for T");
5346
0
        if (bHasNoData)
5347
0
        {
5348
            // General case
5349
0
            for (int iY = 0; iY < nYCheck; iY++)
5350
0
            {
5351
0
                for (int iX = 0; iX < nXCheck; iX++)
5352
0
                {
5353
0
                    const GPtrDiff_t iOffset =
5354
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5355
0
                    const GUInt32 nValue = pData[iOffset];
5356
0
                    if (nValue == nNoDataValue)
5357
0
                        continue;
5358
0
                    if (nValue < nMin)
5359
0
                        nMin = nValue;
5360
0
                    if (nValue > nMax)
5361
0
                        nMax = nValue;
5362
                    if constexpr (COMPUTE_OTHER_STATS)
5363
0
                    {
5364
0
                        nValidCount++;
5365
0
                        nSum += nValue;
5366
0
                        nSumSquare +=
5367
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5368
0
                            nValue;
5369
0
                    }
5370
0
                }
5371
0
            }
5372
            if constexpr (COMPUTE_OTHER_STATS)
5373
0
            {
5374
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5375
0
            }
5376
0
        }
5377
0
        else if (nMin == std::numeric_limits<T>::lowest() &&
5378
0
                 nMax == std::numeric_limits<T>::max())
5379
0
        {
5380
            if constexpr (COMPUTE_OTHER_STATS)
5381
0
            {
5382
                // Optimization when there is no nodata and we know we have already
5383
                // reached the min and max
5384
0
                for (int iY = 0; iY < nYCheck; iY++)
5385
0
                {
5386
0
                    int iX;
5387
0
                    for (iX = 0; iX + 3 < nXCheck; iX += 4)
5388
0
                    {
5389
0
                        const GPtrDiff_t iOffset =
5390
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5391
0
                        const GUIntBig nValue = pData[iOffset];
5392
0
                        const GUIntBig nValue2 = pData[iOffset + 1];
5393
0
                        const GUIntBig nValue3 = pData[iOffset + 2];
5394
0
                        const GUIntBig nValue4 = pData[iOffset + 3];
5395
0
                        nSum += nValue;
5396
0
                        nSumSquare += nValue * nValue;
5397
0
                        nSum += nValue2;
5398
0
                        nSumSquare += nValue2 * nValue2;
5399
0
                        nSum += nValue3;
5400
0
                        nSumSquare += nValue3 * nValue3;
5401
0
                        nSum += nValue4;
5402
0
                        nSumSquare += nValue4 * nValue4;
5403
0
                    }
5404
0
                    for (; iX < nXCheck; ++iX)
5405
0
                    {
5406
0
                        const GPtrDiff_t iOffset =
5407
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5408
0
                        const GUIntBig nValue = pData[iOffset];
5409
0
                        nSum += nValue;
5410
0
                        nSumSquare += nValue * nValue;
5411
0
                    }
5412
0
                }
5413
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5414
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5415
0
            }
5416
0
        }
5417
0
        else
5418
0
        {
5419
0
            for (int iY = 0; iY < nYCheck; iY++)
5420
0
            {
5421
0
                int iX;
5422
0
                for (iX = 0; iX + 1 < nXCheck; iX += 2)
5423
0
                {
5424
0
                    const GPtrDiff_t iOffset =
5425
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5426
0
                    const GUInt32 nValue = pData[iOffset];
5427
0
                    const GUInt32 nValue2 = pData[iOffset + 1];
5428
0
                    if (nValue < nValue2)
5429
0
                    {
5430
0
                        if (nValue < nMin)
5431
0
                            nMin = nValue;
5432
0
                        if (nValue2 > nMax)
5433
0
                            nMax = nValue2;
5434
0
                    }
5435
0
                    else
5436
0
                    {
5437
0
                        if (nValue2 < nMin)
5438
0
                            nMin = nValue2;
5439
0
                        if (nValue > nMax)
5440
0
                            nMax = nValue;
5441
0
                    }
5442
                    if constexpr (COMPUTE_OTHER_STATS)
5443
0
                    {
5444
0
                        nSum += nValue;
5445
0
                        nSumSquare +=
5446
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5447
0
                            nValue;
5448
0
                        nSum += nValue2;
5449
0
                        nSumSquare +=
5450
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5451
0
                            nValue2;
5452
0
                    }
5453
0
                }
5454
0
                if (iX < nXCheck)
5455
0
                {
5456
0
                    const GPtrDiff_t iOffset =
5457
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5458
0
                    const GUInt32 nValue = pData[iOffset];
5459
0
                    if (nValue < nMin)
5460
0
                        nMin = nValue;
5461
0
                    if (nValue > nMax)
5462
0
                        nMax = nValue;
5463
0
                    if (COMPUTE_OTHER_STATS)
5464
0
                    {
5465
0
                        nSum += nValue;
5466
0
                        nSumSquare +=
5467
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5468
0
                            nValue;
5469
0
                    }
5470
0
                }
5471
0
            }
5472
            if constexpr (COMPUTE_OTHER_STATS)
5473
0
            {
5474
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5475
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5476
0
            }
5477
0
        }
5478
0
    }
Unexecuted instantiation: ComputeStatisticsInternalGeneric<unsigned short, false>::f(int, int, int, unsigned short const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: ComputeStatisticsInternalGeneric<unsigned short, true>::f(int, int, int, unsigned short const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
5479
};
5480
5481
// Specialization for Byte that is mostly 32 bit friendly as it avoids
5482
// using 64bit accumulators in internal loops. This also slightly helps in
5483
// 64bit mode.
5484
template <bool COMPUTE_OTHER_STATS>
5485
struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5486
{
5487
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5488
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5489
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5490
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5491
0
    {
5492
0
        int nOuterLoops = nXCheck / 65536;
5493
0
        if (nXCheck % 65536)
5494
0
            nOuterLoops++;
5495
5496
0
        if (bHasNoData)
5497
0
        {
5498
            // General case
5499
0
            for (int iY = 0; iY < nYCheck; iY++)
5500
0
            {
5501
0
                int iX = 0;
5502
0
                for (int k = 0; k < nOuterLoops; k++)
5503
0
                {
5504
0
                    int iMax = iX + 65536;
5505
0
                    if (iMax > nXCheck)
5506
0
                        iMax = nXCheck;
5507
0
                    GUInt32 nSum32bit = 0;
5508
0
                    GUInt32 nSumSquare32bit = 0;
5509
0
                    GUInt32 nValidCount32bit = 0;
5510
0
                    GUInt32 nSampleCount32bit = 0;
5511
0
                    for (; iX < iMax; iX++)
5512
0
                    {
5513
0
                        const GPtrDiff_t iOffset =
5514
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5515
0
                        const GUInt32 nValue = pData[iOffset];
5516
5517
0
                        nSampleCount32bit++;
5518
0
                        if (nValue == nNoDataValue)
5519
0
                            continue;
5520
0
                        if (nValue < nMin)
5521
0
                            nMin = nValue;
5522
0
                        if (nValue > nMax)
5523
0
                            nMax = nValue;
5524
                        if constexpr (COMPUTE_OTHER_STATS)
5525
0
                        {
5526
0
                            nValidCount32bit++;
5527
0
                            nSum32bit += nValue;
5528
0
                            nSumSquare32bit += nValue * nValue;
5529
0
                        }
5530
0
                    }
5531
                    if constexpr (COMPUTE_OTHER_STATS)
5532
0
                    {
5533
0
                        nSampleCount += nSampleCount32bit;
5534
0
                        nValidCount += nValidCount32bit;
5535
0
                        nSum += nSum32bit;
5536
0
                        nSumSquare += nSumSquare32bit;
5537
0
                    }
5538
0
                }
5539
0
            }
5540
0
        }
5541
0
        else if (nMin == 0 && nMax == 255)
5542
0
        {
5543
            if constexpr (COMPUTE_OTHER_STATS)
5544
0
            {
5545
                // Optimization when there is no nodata and we know we have already
5546
                // reached the min and max
5547
0
                for (int iY = 0; iY < nYCheck; iY++)
5548
0
                {
5549
0
                    int iX = 0;
5550
0
                    for (int k = 0; k < nOuterLoops; k++)
5551
0
                    {
5552
0
                        int iMax = iX + 65536;
5553
0
                        if (iMax > nXCheck)
5554
0
                            iMax = nXCheck;
5555
0
                        GUInt32 nSum32bit = 0;
5556
0
                        GUInt32 nSumSquare32bit = 0;
5557
0
                        for (; iX + 3 < iMax; iX += 4)
5558
0
                        {
5559
0
                            const GPtrDiff_t iOffset =
5560
0
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5561
0
                            const GUInt32 nValue = pData[iOffset];
5562
0
                            const GUInt32 nValue2 = pData[iOffset + 1];
5563
0
                            const GUInt32 nValue3 = pData[iOffset + 2];
5564
0
                            const GUInt32 nValue4 = pData[iOffset + 3];
5565
0
                            nSum32bit += nValue;
5566
0
                            nSumSquare32bit += nValue * nValue;
5567
0
                            nSum32bit += nValue2;
5568
0
                            nSumSquare32bit += nValue2 * nValue2;
5569
0
                            nSum32bit += nValue3;
5570
0
                            nSumSquare32bit += nValue3 * nValue3;
5571
0
                            nSum32bit += nValue4;
5572
0
                            nSumSquare32bit += nValue4 * nValue4;
5573
0
                        }
5574
0
                        nSum += nSum32bit;
5575
0
                        nSumSquare += nSumSquare32bit;
5576
0
                    }
5577
0
                    for (; iX < nXCheck; ++iX)
5578
0
                    {
5579
0
                        const GPtrDiff_t iOffset =
5580
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5581
0
                        const GUIntBig nValue = pData[iOffset];
5582
0
                        nSum += nValue;
5583
0
                        nSumSquare += nValue * nValue;
5584
0
                    }
5585
0
                }
5586
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5587
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5588
0
            }
5589
0
        }
5590
0
        else
5591
0
        {
5592
0
            for (int iY = 0; iY < nYCheck; iY++)
5593
0
            {
5594
0
                int iX = 0;
5595
0
                for (int k = 0; k < nOuterLoops; k++)
5596
0
                {
5597
0
                    int iMax = iX + 65536;
5598
0
                    if (iMax > nXCheck)
5599
0
                        iMax = nXCheck;
5600
0
                    GUInt32 nSum32bit = 0;
5601
0
                    GUInt32 nSumSquare32bit = 0;
5602
0
                    for (; iX + 1 < iMax; iX += 2)
5603
0
                    {
5604
0
                        const GPtrDiff_t iOffset =
5605
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5606
0
                        const GUInt32 nValue = pData[iOffset];
5607
0
                        const GUInt32 nValue2 = pData[iOffset + 1];
5608
0
                        if (nValue < nValue2)
5609
0
                        {
5610
0
                            if (nValue < nMin)
5611
0
                                nMin = nValue;
5612
0
                            if (nValue2 > nMax)
5613
0
                                nMax = nValue2;
5614
0
                        }
5615
0
                        else
5616
0
                        {
5617
0
                            if (nValue2 < nMin)
5618
0
                                nMin = nValue2;
5619
0
                            if (nValue > nMax)
5620
0
                                nMax = nValue;
5621
0
                        }
5622
                        if constexpr (COMPUTE_OTHER_STATS)
5623
0
                        {
5624
0
                            nSum32bit += nValue;
5625
0
                            nSumSquare32bit += nValue * nValue;
5626
0
                            nSum32bit += nValue2;
5627
0
                            nSumSquare32bit += nValue2 * nValue2;
5628
0
                        }
5629
0
                    }
5630
                    if constexpr (COMPUTE_OTHER_STATS)
5631
0
                    {
5632
0
                        nSum += nSum32bit;
5633
0
                        nSumSquare += nSumSquare32bit;
5634
0
                    }
5635
0
                }
5636
0
                if (iX < nXCheck)
5637
0
                {
5638
0
                    const GPtrDiff_t iOffset =
5639
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5640
0
                    const GUInt32 nValue = pData[iOffset];
5641
0
                    if (nValue < nMin)
5642
0
                        nMin = nValue;
5643
0
                    if (nValue > nMax)
5644
0
                        nMax = nValue;
5645
                    if constexpr (COMPUTE_OTHER_STATS)
5646
0
                    {
5647
0
                        nSum += nValue;
5648
0
                        nSumSquare +=
5649
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5650
0
                            nValue;
5651
0
                    }
5652
0
                }
5653
0
            }
5654
            if constexpr (COMPUTE_OTHER_STATS)
5655
0
            {
5656
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5657
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5658
0
            }
5659
0
        }
5660
0
    }
Unexecuted instantiation: ComputeStatisticsInternalGeneric<unsigned char, false>::f(int, int, int, unsigned char const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: ComputeStatisticsInternalGeneric<unsigned char, true>::f(int, int, int, unsigned char const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
5661
};
5662
5663
template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5664
{
5665
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5666
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5667
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5668
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5669
    {
5670
        ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5671
            nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5672
            nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5673
    }
5674
};
5675
5676
#if (defined(__x86_64__) || defined(_M_X64)) &&                                \
5677
    (defined(__GNUC__) || defined(_MSC_VER))
5678
5679
#include "gdal_avx2_emulation.hpp"
5680
5681
0
#define ZERO256 GDALmm256_setzero_si256()
5682
5683
template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5684
static void
5685
ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5686
                              // assumed to be aligned on 256 bits
5687
                              const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5688
                              GUIntBig &nSum, GUIntBig &nSumSquare,
5689
                              GUIntBig &nSampleCount, GUIntBig &nValidCount)
5690
0
{
5691
    // 32-byte alignment may not be enforced by linker, so do it at hand
5692
0
    GByte
5693
0
        aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5694
0
    GByte *paby32ByteAligned =
5695
0
        aby32ByteUnaligned +
5696
0
        (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5697
0
    GByte *pabyMin = paby32ByteAligned;
5698
0
    GByte *pabyMax = paby32ByteAligned + 32;
5699
0
    GUInt32 *panSum =
5700
0
        COMPUTE_OTHER_STATS
5701
0
            ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5702
0
            : nullptr;
5703
0
    GUInt32 *panSumSquare =
5704
0
        COMPUTE_OTHER_STATS
5705
0
            ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5706
0
            : nullptr;
5707
5708
0
    CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5709
5710
0
    GPtrDiff_t i = 0;
5711
    // Make sure that sumSquare can fit on uint32
5712
    // * 8 since we can hold 8 sums per vector register
5713
0
    const int nMaxIterationsPerInnerLoop =
5714
0
        8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5715
0
    GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5716
0
    if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5717
0
        nOuterLoops++;
5718
5719
0
    GDALm256i ymm_min =
5720
0
        GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5721
0
    GDALm256i ymm_max = ymm_min;
5722
0
    [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5723
5724
0
    for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5725
0
    {
5726
0
        const auto iMax =
5727
0
            std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5728
5729
        // holds 4 uint32 sums in [0], [2], [4] and [6]
5730
0
        [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5731
0
        [[maybe_unused]] GDALm256i ymm_sumsquare =
5732
0
            ZERO256;  // holds 8 uint32 sums
5733
0
        for (; i + 31 < iMax; i += 32)
5734
0
        {
5735
0
            const GDALm256i ymm = GDALmm256_load_si256(
5736
0
                reinterpret_cast<const GDALm256i *>(pData + i));
5737
0
            if (COMPUTE_MIN)
5738
0
            {
5739
0
                ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5740
0
            }
5741
0
            if (COMPUTE_MAX)
5742
0
            {
5743
0
                ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5744
0
            }
5745
5746
            if constexpr (COMPUTE_OTHER_STATS)
5747
0
            {
5748
                // Extract even-8bit values
5749
0
                const GDALm256i ymm_even =
5750
0
                    GDALmm256_and_si256(ymm, ymm_mask_8bits);
5751
                // Compute square of those 16 values as 32 bit result
5752
                // and add adjacent pairs
5753
0
                const GDALm256i ymm_even_square =
5754
0
                    GDALmm256_madd_epi16(ymm_even, ymm_even);
5755
                // Add to the sumsquare accumulator
5756
0
                ymm_sumsquare =
5757
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5758
5759
                // Extract odd-8bit values
5760
0
                const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5761
0
                const GDALm256i ymm_odd_square =
5762
0
                    GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5763
0
                ymm_sumsquare =
5764
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5765
5766
                // Now compute the sums
5767
0
                ymm_sum = GDALmm256_add_epi32(ymm_sum,
5768
0
                                              GDALmm256_sad_epu8(ymm, ZERO256));
5769
0
            }
5770
0
        }
5771
5772
        if constexpr (COMPUTE_OTHER_STATS)
5773
0
        {
5774
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5775
0
                                  ymm_sum);
5776
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5777
0
                                  ymm_sumsquare);
5778
5779
0
            nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5780
0
            nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5781
0
                          panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5782
0
                          panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5783
0
                          panSumSquare[7];
5784
0
        }
5785
0
    }
5786
5787
    if constexpr (COMPUTE_MIN)
5788
0
    {
5789
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5790
0
    }
5791
    if constexpr (COMPUTE_MAX)
5792
0
    {
5793
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5794
0
    }
5795
    if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5796
0
    {
5797
0
        for (int j = 0; j < 32; j++)
5798
0
        {
5799
            if constexpr (COMPUTE_MIN)
5800
0
            {
5801
0
                if (pabyMin[j] < nMin)
5802
0
                    nMin = pabyMin[j];
5803
0
            }
5804
            if constexpr (COMPUTE_MAX)
5805
0
            {
5806
0
                if (pabyMax[j] > nMax)
5807
0
                    nMax = pabyMax[j];
5808
0
            }
5809
0
        }
5810
0
    }
5811
5812
0
    for (; i < nBlockPixels; i++)
5813
0
    {
5814
0
        const GUInt32 nValue = pData[i];
5815
        if constexpr (COMPUTE_MIN)
5816
0
        {
5817
0
            if (nValue < nMin)
5818
0
                nMin = nValue;
5819
0
        }
5820
        if constexpr (COMPUTE_MAX)
5821
0
        {
5822
0
            if (nValue > nMax)
5823
0
                nMax = nValue;
5824
0
        }
5825
        if constexpr (COMPUTE_OTHER_STATS)
5826
0
        {
5827
0
            nSum += nValue;
5828
0
            nSumSquare +=
5829
0
                static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5830
0
        }
5831
0
    }
5832
5833
    if constexpr (COMPUTE_OTHER_STATS)
5834
0
    {
5835
0
        nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5836
0
        nValidCount += static_cast<GUIntBig>(nBlockPixels);
5837
0
    }
5838
0
}
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<true, true, false>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<true, false, false>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<false, true, false>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<false, false, false>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<true, true, true>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<true, false, true>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<false, true, true>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<false, false, true>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
5839
5840
// SSE2/AVX2 optimization for GByte case
5841
// In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5842
// penaly in using the emulation, because, given the mm256 intrinsics used here,
5843
// there are strictly equivalent to 2 parallel SSE2 streams.
5844
template <bool COMPUTE_OTHER_STATS>
5845
struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5846
{
5847
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
5848
                  // assumed to be aligned on 256 bits
5849
                  const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5850
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5851
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5852
                  GUIntBig &nValidCount)
5853
0
    {
5854
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5855
0
        if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5856
0
            nMin <= nMax)
5857
0
        {
5858
            // 32-byte alignment may not be enforced by linker, so do it at hand
5859
0
            GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5860
0
            GByte *paby32ByteAligned =
5861
0
                aby32ByteUnaligned +
5862
0
                (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5863
0
            GByte *pabyMin = paby32ByteAligned;
5864
0
            GByte *pabyMax = paby32ByteAligned + 32;
5865
0
            GUInt32 *panSum =
5866
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5867
0
            GUInt32 *panSumSquare =
5868
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5869
5870
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5871
5872
0
            GPtrDiff_t i = 0;
5873
            // Make sure that sumSquare can fit on uint32
5874
            // * 8 since we can hold 8 sums per vector register
5875
0
            const int nMaxIterationsPerInnerLoop =
5876
0
                8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5877
0
            auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5878
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5879
0
                nOuterLoops++;
5880
5881
0
            const GDALm256i ymm_nodata =
5882
0
                GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5883
            // any non noData value in [min,max] would do.
5884
0
            const GDALm256i ymm_neutral =
5885
0
                GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5886
0
            GDALm256i ymm_min = ymm_neutral;
5887
0
            GDALm256i ymm_max = ymm_neutral;
5888
0
            [[maybe_unused]] const auto ymm_mask_8bits =
5889
0
                GDALmm256_set1_epi16(0xFF);
5890
5891
0
            const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5892
0
            const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5893
0
            const bool bComputeMinMax =
5894
0
                nMin > nMinThreshold || nMax < nMaxThreshold;
5895
5896
0
            for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5897
0
            {
5898
0
                const auto iMax =
5899
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5900
5901
                // holds 4 uint32 sums in [0], [2], [4] and [6]
5902
0
                [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5903
                // holds 8 uint32 sums
5904
0
                [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5905
                // holds 4 uint32 sums in [0], [2], [4] and [6]
5906
0
                [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5907
0
                const auto iInit = i;
5908
0
                for (; i + 31 < iMax; i += 32)
5909
0
                {
5910
0
                    const GDALm256i ymm = GDALmm256_load_si256(
5911
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
5912
5913
                    // Check which values are nodata
5914
0
                    const GDALm256i ymm_eq_nodata =
5915
0
                        GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5916
                    if constexpr (COMPUTE_OTHER_STATS)
5917
0
                    {
5918
                        // Count how many values are nodata (due to cmpeq
5919
                        // putting 255 when condition is met, this will actually
5920
                        // be 255 times the number of nodata value, spread in 4
5921
                        // 64 bits words). We can use add_epi32 as the counter
5922
                        // will not overflow uint32
5923
0
                        ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5924
0
                            ymm_count_nodata_mul_255,
5925
0
                            GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5926
0
                    }
5927
                    // Replace all nodata values by zero for the purpose of sum
5928
                    // and sumquare.
5929
0
                    const GDALm256i ymm_nodata_by_zero =
5930
0
                        GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5931
0
                    if (bComputeMinMax)
5932
0
                    {
5933
                        // Replace all nodata values by a neutral value for the
5934
                        // purpose of min and max.
5935
0
                        const GDALm256i ymm_nodata_by_neutral =
5936
0
                            GDALmm256_or_si256(
5937
0
                                GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5938
0
                                ymm_nodata_by_zero);
5939
5940
0
                        ymm_min =
5941
0
                            GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5942
0
                        ymm_max =
5943
0
                            GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
5944
0
                    }
5945
5946
                    if constexpr (COMPUTE_OTHER_STATS)
5947
0
                    {
5948
                        // Extract even-8bit values
5949
0
                        const GDALm256i ymm_even = GDALmm256_and_si256(
5950
0
                            ymm_nodata_by_zero, ymm_mask_8bits);
5951
                        // Compute square of those 16 values as 32 bit result
5952
                        // and add adjacent pairs
5953
0
                        const GDALm256i ymm_even_square =
5954
0
                            GDALmm256_madd_epi16(ymm_even, ymm_even);
5955
                        // Add to the sumsquare accumulator
5956
0
                        ymm_sumsquare =
5957
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5958
5959
                        // Extract odd-8bit values
5960
0
                        const GDALm256i ymm_odd =
5961
0
                            GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
5962
0
                        const GDALm256i ymm_odd_square =
5963
0
                            GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5964
0
                        ymm_sumsquare =
5965
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5966
5967
                        // Now compute the sums
5968
0
                        ymm_sum = GDALmm256_add_epi32(
5969
0
                            ymm_sum,
5970
0
                            GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
5971
0
                    }
5972
0
                }
5973
5974
                if constexpr (COMPUTE_OTHER_STATS)
5975
0
                {
5976
0
                    GUInt32 *panCoutNoDataMul255 = panSum;
5977
0
                    GDALmm256_store_si256(
5978
0
                        reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
5979
0
                        ymm_count_nodata_mul_255);
5980
5981
0
                    nSampleCount += (i - iInit);
5982
5983
0
                    nValidCount +=
5984
0
                        (i - iInit) -
5985
0
                        (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
5986
0
                         panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
5987
0
                            255;
5988
5989
0
                    GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5990
0
                                          ymm_sum);
5991
0
                    GDALmm256_store_si256(
5992
0
                        reinterpret_cast<GDALm256i *>(panSumSquare),
5993
0
                        ymm_sumsquare);
5994
0
                    nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5995
0
                    nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5996
0
                                  panSumSquare[1] + panSumSquare[2] +
5997
0
                                  panSumSquare[3] + panSumSquare[4] +
5998
0
                                  panSumSquare[5] + panSumSquare[6] +
5999
0
                                  panSumSquare[7];
6000
0
                }
6001
0
            }
6002
6003
0
            if (bComputeMinMax)
6004
0
            {
6005
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6006
0
                                      ymm_min);
6007
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6008
0
                                      ymm_max);
6009
0
                for (int j = 0; j < 32; j++)
6010
0
                {
6011
0
                    if (pabyMin[j] < nMin)
6012
0
                        nMin = pabyMin[j];
6013
0
                    if (pabyMax[j] > nMax)
6014
0
                        nMax = pabyMax[j];
6015
0
                }
6016
0
            }
6017
6018
            if constexpr (COMPUTE_OTHER_STATS)
6019
0
            {
6020
0
                nSampleCount += nBlockPixels - i;
6021
0
            }
6022
0
            for (; i < nBlockPixels; i++)
6023
0
            {
6024
0
                const GUInt32 nValue = pData[i];
6025
0
                if (nValue == nNoDataValue)
6026
0
                    continue;
6027
0
                if (nValue < nMin)
6028
0
                    nMin = nValue;
6029
0
                if (nValue > nMax)
6030
0
                    nMax = nValue;
6031
                if constexpr (COMPUTE_OTHER_STATS)
6032
0
                {
6033
0
                    nValidCount++;
6034
0
                    nSum += nValue;
6035
0
                    nSumSquare +=
6036
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6037
0
                        nValue;
6038
0
                }
6039
0
            }
6040
0
        }
6041
0
        else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6042
0
        {
6043
0
            if (nMin > 0)
6044
0
            {
6045
0
                if (nMax < 255)
6046
0
                {
6047
0
                    ComputeStatisticsByteNoNodata<true, true,
6048
0
                                                  COMPUTE_OTHER_STATS>(
6049
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6050
0
                        nSampleCount, nValidCount);
6051
0
                }
6052
0
                else
6053
0
                {
6054
0
                    ComputeStatisticsByteNoNodata<true, false,
6055
0
                                                  COMPUTE_OTHER_STATS>(
6056
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6057
0
                        nSampleCount, nValidCount);
6058
0
                }
6059
0
            }
6060
0
            else
6061
0
            {
6062
0
                if (nMax < 255)
6063
0
                {
6064
0
                    ComputeStatisticsByteNoNodata<false, true,
6065
0
                                                  COMPUTE_OTHER_STATS>(
6066
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6067
0
                        nSampleCount, nValidCount);
6068
0
                }
6069
0
                else
6070
0
                {
6071
0
                    ComputeStatisticsByteNoNodata<false, false,
6072
0
                                                  COMPUTE_OTHER_STATS>(
6073
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6074
0
                        nSampleCount, nValidCount);
6075
0
                }
6076
0
            }
6077
0
        }
6078
0
        else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6079
0
                 (nBlockXSize % 32) == 0)
6080
0
        {
6081
0
            for (int iY = 0; iY < nYCheck; iY++)
6082
0
            {
6083
0
                ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6084
0
                    nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6085
0
                    nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6086
0
            }
6087
0
        }
6088
0
        else
6089
0
        {
6090
0
            ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6091
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6092
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6093
0
        }
6094
0
    }
Unexecuted instantiation: ComputeStatisticsInternal<unsigned char, false>::f(int, int, int, unsigned char const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: ComputeStatisticsInternal<unsigned char, true>::f(int, int, int, unsigned char const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
6095
};
6096
6097
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6098
static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6099
                             GUIntBig i)
6100
0
{
6101
0
    nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6102
0
}
6103
6104
// AVX2/SSE2 optimization for GUInt16 case
6105
template <bool COMPUTE_OTHER_STATS>
6106
struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6107
{
6108
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
6109
                  // assumed to be aligned on 128 bits
6110
                  const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6111
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6112
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6113
                  GUIntBig &nValidCount)
6114
0
    {
6115
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6116
0
        if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6117
0
        {
6118
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6119
6120
0
            GPtrDiff_t i = 0;
6121
            // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6122
            // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6123
            // Furthermore the shift is also needed to use madd_epi16
6124
0
            const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6125
0
            GDALm256i ymm_min = GDALmm256_load_si256(
6126
0
                reinterpret_cast<const GDALm256i *>(pData + i));
6127
0
            ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6128
0
            GDALm256i ymm_max = ymm_min;
6129
0
            [[maybe_unused]] GDALm256i ymm_sumsquare =
6130
0
                ZERO256;  // holds 4 uint64 sums
6131
6132
            // Make sure that sum can fit on uint32
6133
            // * 8 since we can hold 8 sums per vector register
6134
0
            const int nMaxIterationsPerInnerLoop =
6135
0
                8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6136
0
            GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6137
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6138
0
                nOuterLoops++;
6139
6140
0
            const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6141
0
            [[maybe_unused]] const auto ymm_mask_16bits =
6142
0
                GDALmm256_set1_epi32(0xFFFF);
6143
0
            [[maybe_unused]] const auto ymm_mask_32bits =
6144
0
                GDALmm256_set1_epi64x(0xFFFFFFFF);
6145
6146
0
            GUIntBig nSumThis = 0;
6147
0
            for (int k = 0; k < nOuterLoops; k++)
6148
0
            {
6149
0
                const auto iMax =
6150
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6151
6152
0
                [[maybe_unused]] GDALm256i ymm_sum =
6153
0
                    ZERO256;  // holds 8 uint32 sums
6154
0
                for (; i + 15 < iMax; i += 16)
6155
0
                {
6156
0
                    const GDALm256i ymm = GDALmm256_load_si256(
6157
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
6158
0
                    const GDALm256i ymm_shifted =
6159
0
                        GDALmm256_add_epi16(ymm, ymm_m32768);
6160
0
                    if (bComputeMinMax)
6161
0
                    {
6162
0
                        ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6163
0
                        ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6164
0
                    }
6165
6166
                    if constexpr (COMPUTE_OTHER_STATS)
6167
0
                    {
6168
                        // Note: the int32 range can overflow for (0-32768)^2 +
6169
                        // (0-32768)^2 = 0x80000000, but as we know the result
6170
                        // is positive, this is OK as we interpret is a uint32.
6171
0
                        const GDALm256i ymm_square =
6172
0
                            GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6173
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6174
0
                            ymm_sumsquare,
6175
0
                            GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6176
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6177
0
                            ymm_sumsquare,
6178
0
                            GDALmm256_srli_epi64(ymm_square, 32));
6179
6180
                        // Now compute the sums
6181
0
                        ymm_sum = GDALmm256_add_epi32(
6182
0
                            ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6183
0
                        ymm_sum = GDALmm256_add_epi32(
6184
0
                            ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6185
0
                    }
6186
0
                }
6187
6188
                if constexpr (COMPUTE_OTHER_STATS)
6189
0
                {
6190
0
                    GUInt32 anSum[8];
6191
0
                    GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6192
0
                                           ymm_sum);
6193
0
                    nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6194
0
                                anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6195
0
                                anSum[6] + anSum[7];
6196
0
                }
6197
0
            }
6198
6199
0
            if (bComputeMinMax)
6200
0
            {
6201
0
                GUInt16 anMin[16];
6202
0
                GUInt16 anMax[16];
6203
6204
                // Unshift the result
6205
0
                ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6206
0
                ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6207
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6208
0
                                       ymm_min);
6209
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6210
0
                                       ymm_max);
6211
0
                for (int j = 0; j < 16; j++)
6212
0
                {
6213
0
                    if (anMin[j] < nMin)
6214
0
                        nMin = anMin[j];
6215
0
                    if (anMax[j] > nMax)
6216
0
                        nMax = anMax[j];
6217
0
                }
6218
0
            }
6219
6220
            if constexpr (COMPUTE_OTHER_STATS)
6221
0
            {
6222
0
                GUIntBig anSumSquare[4];
6223
0
                GDALmm256_storeu_si256(
6224
0
                    reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6225
0
                nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6226
0
                              anSumSquare[3];
6227
6228
                // Unshift the sum of squares
6229
0
                UnshiftSumSquare(nSumSquare, nSumThis,
6230
0
                                 static_cast<GUIntBig>(i));
6231
6232
0
                nSum += nSumThis;
6233
6234
0
                for (; i < nBlockPixels; i++)
6235
0
                {
6236
0
                    const GUInt32 nValue = pData[i];
6237
0
                    if (nValue < nMin)
6238
0
                        nMin = nValue;
6239
0
                    if (nValue > nMax)
6240
0
                        nMax = nValue;
6241
0
                    nSum += nValue;
6242
0
                    nSumSquare +=
6243
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6244
0
                        nValue;
6245
0
                }
6246
6247
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6248
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6249
0
            }
6250
0
        }
6251
0
        else
6252
0
        {
6253
0
            ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6254
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6255
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6256
0
        }
6257
0
    }
Unexecuted instantiation: ComputeStatisticsInternal<unsigned short, false>::f(int, int, int, unsigned short const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: ComputeStatisticsInternal<unsigned short, true>::f(int, int, int, unsigned short const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
6258
};
6259
6260
#endif
6261
// (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6262
// defined(_MSC_VER))
6263
6264
/************************************************************************/
6265
/*                          GetPixelValue()                             */
6266
/************************************************************************/
6267
6268
static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6269
                                   const void *pData, GPtrDiff_t iOffset,
6270
                                   const GDALNoDataValues &sNoDataValues,
6271
                                   bool &bValid)
6272
0
{
6273
0
    bValid = true;
6274
0
    double dfValue = 0;
6275
0
    switch (eDataType)
6276
0
    {
6277
0
        case GDT_Byte:
6278
0
        {
6279
0
            if (bSignedByte)
6280
0
                dfValue = static_cast<const signed char *>(pData)[iOffset];
6281
0
            else
6282
0
                dfValue = static_cast<const GByte *>(pData)[iOffset];
6283
0
            break;
6284
0
        }
6285
0
        case GDT_Int8:
6286
0
            dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6287
0
            break;
6288
0
        case GDT_UInt16:
6289
0
            dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6290
0
            break;
6291
0
        case GDT_Int16:
6292
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6293
0
            break;
6294
0
        case GDT_UInt32:
6295
0
            dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6296
0
            break;
6297
0
        case GDT_Int32:
6298
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6299
0
            break;
6300
0
        case GDT_UInt64:
6301
0
            dfValue = static_cast<double>(
6302
0
                static_cast<const std::uint64_t *>(pData)[iOffset]);
6303
0
            break;
6304
0
        case GDT_Int64:
6305
0
            dfValue = static_cast<double>(
6306
0
                static_cast<const std::int64_t *>(pData)[iOffset]);
6307
0
            break;
6308
0
        case GDT_Float16:
6309
0
        {
6310
0
            using namespace std;
6311
0
            const GFloat16 hfValue =
6312
0
                static_cast<const GFloat16 *>(pData)[iOffset];
6313
0
            if (isnan(hfValue) ||
6314
0
                (sNoDataValues.bGotFloat16NoDataValue &&
6315
0
                 ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6316
0
            {
6317
0
                bValid = false;
6318
0
                return 0.0;
6319
0
            }
6320
0
            dfValue = hfValue;
6321
0
            return dfValue;
6322
0
        }
6323
0
        case GDT_Float32:
6324
0
        {
6325
0
            const float fValue = static_cast<const float *>(pData)[iOffset];
6326
0
            if (std::isnan(fValue) ||
6327
0
                (sNoDataValues.bGotFloatNoDataValue &&
6328
0
                 ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6329
0
            {
6330
0
                bValid = false;
6331
0
                return 0.0;
6332
0
            }
6333
0
            dfValue = fValue;
6334
0
            return dfValue;
6335
0
        }
6336
0
        case GDT_Float64:
6337
0
            dfValue = static_cast<const double *>(pData)[iOffset];
6338
0
            if (std::isnan(dfValue))
6339
0
            {
6340
0
                bValid = false;
6341
0
                return 0.0;
6342
0
            }
6343
0
            break;
6344
0
        case GDT_CInt16:
6345
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6346
0
            break;
6347
0
        case GDT_CInt32:
6348
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6349
0
            break;
6350
0
        case GDT_CFloat16:
6351
0
            dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6352
0
            if (std::isnan(dfValue))
6353
0
            {
6354
0
                bValid = false;
6355
0
                return 0.0;
6356
0
            }
6357
0
            break;
6358
0
        case GDT_CFloat32:
6359
0
            dfValue = static_cast<const float *>(pData)[iOffset * 2];
6360
0
            if (std::isnan(dfValue))
6361
0
            {
6362
0
                bValid = false;
6363
0
                return 0.0;
6364
0
            }
6365
0
            break;
6366
0
        case GDT_CFloat64:
6367
0
            dfValue = static_cast<const double *>(pData)[iOffset * 2];
6368
0
            if (std::isnan(dfValue))
6369
0
            {
6370
0
                bValid = false;
6371
0
                return 0.0;
6372
0
            }
6373
0
            break;
6374
0
        case GDT_Unknown:
6375
0
        case GDT_TypeCount:
6376
0
            CPLAssert(false);
6377
0
            break;
6378
0
    }
6379
6380
0
    if (sNoDataValues.bGotNoDataValue &&
6381
0
        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6382
0
    {
6383
0
        bValid = false;
6384
0
        return 0.0;
6385
0
    }
6386
0
    return dfValue;
6387
0
}
6388
6389
/************************************************************************/
6390
/*                         SetValidPercent()                            */
6391
/************************************************************************/
6392
6393
//! @cond Doxygen_Suppress
6394
/**
6395
 * \brief Set percentage of valid (not nodata) pixels.
6396
 *
6397
 * Stores the percentage of valid pixels in the metadata item
6398
 * STATISTICS_VALID_PERCENT
6399
 *
6400
 * @param nSampleCount Number of sampled pixels.
6401
 *
6402
 * @param nValidCount Number of valid pixels.
6403
 */
6404
6405
void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6406
                                     GUIntBig nValidCount)
6407
0
{
6408
0
    if (nValidCount == 0)
6409
0
    {
6410
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6411
0
    }
6412
0
    else if (nValidCount == nSampleCount)
6413
0
    {
6414
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6415
0
    }
6416
0
    else /* nValidCount < nSampleCount */
6417
0
    {
6418
0
        char szValue[128] = {0};
6419
6420
        /* percentage is only an indicator: limit precision */
6421
0
        CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6422
0
                    100. * static_cast<double>(nValidCount) / nSampleCount);
6423
6424
0
        if (EQUAL(szValue, "100"))
6425
0
        {
6426
            /* don't set 100 percent valid
6427
             * because some of the sampled pixels were nodata */
6428
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6429
0
        }
6430
0
        else
6431
0
        {
6432
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6433
0
        }
6434
0
    }
6435
0
}
6436
6437
//! @endcond
6438
6439
/************************************************************************/
6440
/*                         ComputeStatistics()                          */
6441
/************************************************************************/
6442
6443
/**
6444
 * \brief Compute image statistics.
6445
 *
6446
 * Returns the minimum, maximum, mean and standard deviation of all
6447
 * pixel values in this band.  If approximate statistics are sufficient,
6448
 * the bApproxOK flag can be set to true in which case overviews, or a
6449
 * subset of image tiles may be used in computing the statistics.
6450
 *
6451
 * Once computed, the statistics will generally be "set" back on the
6452
 * raster band using SetStatistics().
6453
 *
6454
 * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6455
 *
6456
 * This method is the same as the C function GDALComputeRasterStatistics().
6457
 *
6458
 * @param bApproxOK If TRUE statistics may be computed based on overviews
6459
 * or a subset of all tiles.
6460
 *
6461
 * @param pdfMin Location into which to load image minimum (may be NULL).
6462
 *
6463
 * @param pdfMax Location into which to load image maximum (may be NULL).-
6464
 *
6465
 * @param pdfMean Location into which to load image mean (may be NULL).
6466
 *
6467
 * @param pdfStdDev Location into which to load image standard deviation
6468
 * (may be NULL).
6469
 *
6470
 * @param pfnProgress a function to call to report progress, or NULL.
6471
 *
6472
 * @param pProgressData application data to pass to the progress function.
6473
 *
6474
 * @return CE_None on success, or CE_Failure if an error occurs or processing
6475
 * is terminated by the user.
6476
 */
6477
6478
CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6479
                                         double *pdfMax, double *pdfMean,
6480
                                         double *pdfStdDev,
6481
                                         GDALProgressFunc pfnProgress,
6482
                                         void *pProgressData)
6483
6484
0
{
6485
0
    if (pfnProgress == nullptr)
6486
0
        pfnProgress = GDALDummyProgress;
6487
6488
    /* -------------------------------------------------------------------- */
6489
    /*      If we have overview bands, use them for statistics.             */
6490
    /* -------------------------------------------------------------------- */
6491
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6492
0
    {
6493
0
        GDALRasterBand *poBand =
6494
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6495
6496
0
        if (poBand != this)
6497
0
        {
6498
0
            CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6499
0
                                                    pdfMean, pdfStdDev,
6500
0
                                                    pfnProgress, pProgressData);
6501
0
            if (eErr == CE_None)
6502
0
            {
6503
0
                if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6504
0
                {
6505
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6506
0
                    SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6507
0
                }
6508
6509
                /* transfer metadata from overview band to this */
6510
0
                const char *pszPercentValid =
6511
0
                    poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6512
6513
0
                if (pszPercentValid != nullptr)
6514
0
                {
6515
0
                    SetMetadataItem("STATISTICS_VALID_PERCENT",
6516
0
                                    pszPercentValid);
6517
0
                }
6518
0
            }
6519
0
            return eErr;
6520
0
        }
6521
0
    }
6522
6523
0
    if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6524
0
    {
6525
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6526
0
        return CE_Failure;
6527
0
    }
6528
6529
    /* -------------------------------------------------------------------- */
6530
    /*      Read actual data and compute statistics.                        */
6531
    /* -------------------------------------------------------------------- */
6532
    // Using Welford algorithm:
6533
    // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6534
    // to compute standard deviation in a more numerically robust way than
6535
    // the difference of the sum of square values with the square of the sum.
6536
    // dfMean and dfM2 are updated at each sample.
6537
    // dfM2 is the sum of square of differences to the current mean.
6538
0
    double dfMin = std::numeric_limits<double>::infinity();
6539
0
    double dfMax = -std::numeric_limits<double>::infinity();
6540
0
    double dfMean = 0.0;
6541
0
    double dfM2 = 0.0;
6542
6543
0
    GDALRasterIOExtraArg sExtraArg;
6544
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6545
6546
0
    GDALNoDataValues sNoDataValues(this, eDataType);
6547
0
    GDALRasterBand *poMaskBand = nullptr;
6548
0
    if (!sNoDataValues.bGotNoDataValue)
6549
0
    {
6550
0
        const int l_nMaskFlags = GetMaskFlags();
6551
0
        if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
6552
0
            GetColorInterpretation() != GCI_AlphaBand)
6553
0
        {
6554
0
            poMaskBand = GetMaskBand();
6555
0
        }
6556
0
    }
6557
6558
0
    bool bSignedByte = false;
6559
0
    if (eDataType == GDT_Byte)
6560
0
    {
6561
0
        EnablePixelTypeSignedByteWarning(false);
6562
0
        const char *pszPixelType =
6563
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6564
0
        EnablePixelTypeSignedByteWarning(true);
6565
0
        bSignedByte =
6566
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6567
0
    }
6568
6569
0
    GUIntBig nSampleCount = 0;
6570
0
    GUIntBig nValidCount = 0;
6571
6572
0
    if (bApproxOK && HasArbitraryOverviews())
6573
0
    {
6574
        /* --------------------------------------------------------------------
6575
         */
6576
        /*      Figure out how much the image should be reduced to get an */
6577
        /*      approximate value. */
6578
        /* --------------------------------------------------------------------
6579
         */
6580
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6581
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6582
6583
0
        int nXReduced = nRasterXSize;
6584
0
        int nYReduced = nRasterYSize;
6585
0
        if (dfReduction > 1.0)
6586
0
        {
6587
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6588
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6589
6590
            // Catch the case of huge resizing ratios here
6591
0
            if (nXReduced == 0)
6592
0
                nXReduced = 1;
6593
0
            if (nYReduced == 0)
6594
0
                nYReduced = 1;
6595
0
        }
6596
6597
0
        void *pData = CPLMalloc(cpl::fits_on<int>(
6598
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6599
6600
0
        const CPLErr eErr =
6601
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6602
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6603
0
        if (eErr != CE_None)
6604
0
        {
6605
0
            CPLFree(pData);
6606
0
            return eErr;
6607
0
        }
6608
6609
0
        GByte *pabyMaskData = nullptr;
6610
0
        if (poMaskBand)
6611
0
        {
6612
0
            pabyMaskData =
6613
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6614
0
            if (!pabyMaskData)
6615
0
            {
6616
0
                CPLFree(pData);
6617
0
                return CE_Failure;
6618
0
            }
6619
6620
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6621
0
                                     pabyMaskData, nXReduced, nYReduced,
6622
0
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
6623
0
            {
6624
0
                CPLFree(pData);
6625
0
                CPLFree(pabyMaskData);
6626
0
                return CE_Failure;
6627
0
            }
6628
0
        }
6629
6630
        /* this isn't the fastest way to do this, but is easier for now */
6631
0
        for (int iY = 0; iY < nYReduced; iY++)
6632
0
        {
6633
0
            for (int iX = 0; iX < nXReduced; iX++)
6634
0
            {
6635
0
                const int iOffset = iX + iY * nXReduced;
6636
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
6637
0
                    continue;
6638
6639
0
                bool bValid = true;
6640
0
                double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
6641
0
                                               iOffset, sNoDataValues, bValid);
6642
0
                if (!bValid)
6643
0
                    continue;
6644
6645
0
                dfMin = std::min(dfMin, dfValue);
6646
0
                dfMax = std::max(dfMax, dfValue);
6647
6648
0
                nValidCount++;
6649
0
                if (dfMin == dfMax)
6650
0
                {
6651
0
                    if (nValidCount == 1)
6652
0
                        dfMean = dfMin;
6653
0
                }
6654
0
                else
6655
0
                {
6656
0
                    const double dfDelta = dfValue - dfMean;
6657
0
                    dfMean += dfDelta / nValidCount;
6658
0
                    dfM2 += dfDelta * (dfValue - dfMean);
6659
0
                }
6660
0
            }
6661
0
        }
6662
6663
0
        nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6664
6665
0
        CPLFree(pData);
6666
0
        CPLFree(pabyMaskData);
6667
0
    }
6668
6669
0
    else  // No arbitrary overviews.
6670
0
    {
6671
0
        if (!InitBlockInfo())
6672
0
            return CE_Failure;
6673
6674
        /* --------------------------------------------------------------------
6675
         */
6676
        /*      Figure out the ratio of blocks we will read to get an */
6677
        /*      approximate value. */
6678
        /* --------------------------------------------------------------------
6679
         */
6680
0
        int nSampleRate = 1;
6681
0
        if (bApproxOK)
6682
0
        {
6683
0
            nSampleRate = static_cast<int>(std::max(
6684
0
                1.0,
6685
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6686
            // We want to avoid probing only the first column of blocks for
6687
            // a square shaped raster, because it is not unlikely that it may
6688
            // be padding only (#6378)
6689
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6690
0
                nSampleRate += 1;
6691
0
        }
6692
0
        if (nSampleRate == 1)
6693
0
            bApproxOK = false;
6694
6695
        // Particular case for GDT_Byte that only use integral types for all
6696
        // intermediate computations. Only possible if the number of pixels
6697
        // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6698
        // can fit on a uint64. Should be 99.99999% of cases.
6699
        // For GUInt16, this limits to raster of 4 giga pixels
6700
0
        if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6701
0
             static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6702
0
                     nSampleRate <
6703
0
                 GUINTBIG_MAX / (255U * 255U) /
6704
0
                     (static_cast<GUInt64>(nBlockXSize) *
6705
0
                      static_cast<GUInt64>(nBlockYSize))) ||
6706
0
            (eDataType == GDT_UInt16 &&
6707
0
             static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6708
0
                     nSampleRate <
6709
0
                 GUINTBIG_MAX / (65535U * 65535U) /
6710
0
                     (static_cast<GUInt64>(nBlockXSize) *
6711
0
                      static_cast<GUInt64>(nBlockYSize))))
6712
0
        {
6713
0
            const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6714
0
            GUInt32 nMin = nMaxValueType;
6715
0
            GUInt32 nMax = 0;
6716
0
            GUIntBig nSum = 0;
6717
0
            GUIntBig nSumSquare = 0;
6718
            // If no valid nodata, map to invalid value (256 for Byte)
6719
0
            const GUInt32 nNoDataValue =
6720
0
                (sNoDataValues.bGotNoDataValue &&
6721
0
                 sNoDataValues.dfNoDataValue >= 0 &&
6722
0
                 sNoDataValues.dfNoDataValue <= nMaxValueType &&
6723
0
                 fabs(sNoDataValues.dfNoDataValue -
6724
0
                      static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
6725
0
                                           1e-10)) < 1e-10)
6726
0
                    ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
6727
0
                    : nMaxValueType + 1;
6728
6729
0
            for (GIntBig iSampleBlock = 0;
6730
0
                 iSampleBlock <
6731
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6732
0
                 iSampleBlock += nSampleRate)
6733
0
            {
6734
0
                const int iYBlock =
6735
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
6736
0
                const int iXBlock =
6737
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
6738
6739
0
                GDALRasterBlock *const poBlock =
6740
0
                    GetLockedBlockRef(iXBlock, iYBlock);
6741
0
                if (poBlock == nullptr)
6742
0
                    return CE_Failure;
6743
6744
0
                void *const pData = poBlock->GetDataRef();
6745
6746
0
                int nXCheck = 0, nYCheck = 0;
6747
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6748
6749
0
                if (eDataType == GDT_Byte)
6750
0
                {
6751
0
                    ComputeStatisticsInternal<
6752
0
                        GByte, /* COMPUTE_OTHER_STATS = */ true>::
6753
0
                        f(nXCheck, nBlockXSize, nYCheck,
6754
0
                          static_cast<const GByte *>(pData),
6755
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6756
0
                          nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6757
0
                }
6758
0
                else
6759
0
                {
6760
0
                    ComputeStatisticsInternal<
6761
0
                        GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6762
0
                        f(nXCheck, nBlockXSize, nYCheck,
6763
0
                          static_cast<const GUInt16 *>(pData),
6764
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6765
0
                          nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6766
0
                }
6767
6768
0
                poBlock->DropLock();
6769
6770
0
                if (!pfnProgress(static_cast<double>(iSampleBlock) /
6771
0
                                     (static_cast<double>(nBlocksPerRow) *
6772
0
                                      nBlocksPerColumn),
6773
0
                                 "Compute Statistics", pProgressData))
6774
0
                {
6775
0
                    ReportError(CE_Failure, CPLE_UserInterrupt,
6776
0
                                "User terminated");
6777
0
                    return CE_Failure;
6778
0
                }
6779
0
            }
6780
6781
0
            if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6782
0
            {
6783
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6784
0
                return CE_Failure;
6785
0
            }
6786
6787
            /* --------------------------------------------------------------------
6788
             */
6789
            /*      Save computed information. */
6790
            /* --------------------------------------------------------------------
6791
             */
6792
0
            if (nValidCount)
6793
0
                dfMean = static_cast<double>(nSum) / nValidCount;
6794
6795
            // To avoid potential precision issues when doing the difference,
6796
            // we need to do that computation on 128 bit rather than casting
6797
            // to double
6798
0
            const GDALUInt128 nTmpForStdDev(
6799
0
                GDALUInt128::Mul(nSumSquare, nValidCount) -
6800
0
                GDALUInt128::Mul(nSum, nSum));
6801
0
            const double dfStdDev =
6802
0
                nValidCount > 0
6803
0
                    ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6804
0
                    : 0.0;
6805
6806
0
            if (nValidCount > 0)
6807
0
            {
6808
0
                if (bApproxOK)
6809
0
                {
6810
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6811
0
                }
6812
0
                else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6813
0
                {
6814
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6815
0
                }
6816
0
                SetStatistics(nMin, nMax, dfMean, dfStdDev);
6817
0
            }
6818
6819
0
            SetValidPercent(nSampleCount, nValidCount);
6820
6821
            /* --------------------------------------------------------------------
6822
             */
6823
            /*      Record results. */
6824
            /* --------------------------------------------------------------------
6825
             */
6826
0
            if (pdfMin != nullptr)
6827
0
                *pdfMin = nValidCount ? nMin : 0;
6828
0
            if (pdfMax != nullptr)
6829
0
                *pdfMax = nValidCount ? nMax : 0;
6830
6831
0
            if (pdfMean != nullptr)
6832
0
                *pdfMean = dfMean;
6833
6834
0
            if (pdfStdDev != nullptr)
6835
0
                *pdfStdDev = dfStdDev;
6836
6837
0
            if (nValidCount > 0)
6838
0
                return CE_None;
6839
6840
0
            ReportError(CE_Failure, CPLE_AppDefined,
6841
0
                        "Failed to compute statistics, no valid pixels found "
6842
0
                        "in sampling.");
6843
0
            return CE_Failure;
6844
0
        }
6845
6846
0
        GByte *pabyMaskData = nullptr;
6847
0
        if (poMaskBand)
6848
0
        {
6849
0
            pabyMaskData = static_cast<GByte *>(
6850
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6851
0
            if (!pabyMaskData)
6852
0
            {
6853
0
                return CE_Failure;
6854
0
            }
6855
0
        }
6856
6857
0
        for (GIntBig iSampleBlock = 0;
6858
0
             iSampleBlock <
6859
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6860
0
             iSampleBlock += nSampleRate)
6861
0
        {
6862
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6863
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6864
6865
0
            GDALRasterBlock *const poBlock =
6866
0
                GetLockedBlockRef(iXBlock, iYBlock);
6867
0
            if (poBlock == nullptr)
6868
0
            {
6869
0
                CPLFree(pabyMaskData);
6870
0
                return CE_Failure;
6871
0
            }
6872
6873
0
            void *const pData = poBlock->GetDataRef();
6874
6875
0
            int nXCheck = 0, nYCheck = 0;
6876
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6877
6878
0
            if (poMaskBand &&
6879
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6880
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
6881
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6882
0
                                     0, nBlockXSize, nullptr) != CE_None)
6883
0
            {
6884
0
                CPLFree(pabyMaskData);
6885
0
                poBlock->DropLock();
6886
0
                return CE_Failure;
6887
0
            }
6888
6889
            // This isn't the fastest way to do this, but is easier for now.
6890
0
            for (int iY = 0; iY < nYCheck; iY++)
6891
0
            {
6892
0
                for (int iX = 0; iX < nXCheck; iX++)
6893
0
                {
6894
0
                    const GPtrDiff_t iOffset =
6895
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6896
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
6897
0
                        continue;
6898
6899
0
                    bool bValid = true;
6900
0
                    double dfValue =
6901
0
                        GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6902
0
                                      sNoDataValues, bValid);
6903
6904
0
                    if (!bValid)
6905
0
                        continue;
6906
6907
0
                    dfMin = std::min(dfMin, dfValue);
6908
0
                    dfMax = std::max(dfMax, dfValue);
6909
6910
0
                    nValidCount++;
6911
0
                    if (dfMin == dfMax)
6912
0
                    {
6913
0
                        if (nValidCount == 1)
6914
0
                            dfMean = dfMin;
6915
0
                    }
6916
0
                    else
6917
0
                    {
6918
0
                        const double dfDelta = dfValue - dfMean;
6919
0
                        dfMean += dfDelta / nValidCount;
6920
0
                        dfM2 += dfDelta * (dfValue - dfMean);
6921
0
                    }
6922
0
                }
6923
0
            }
6924
6925
0
            nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6926
6927
0
            poBlock->DropLock();
6928
6929
0
            if (!pfnProgress(
6930
0
                    static_cast<double>(iSampleBlock) /
6931
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6932
0
                    "Compute Statistics", pProgressData))
6933
0
            {
6934
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6935
0
                CPLFree(pabyMaskData);
6936
0
                return CE_Failure;
6937
0
            }
6938
0
        }
6939
6940
0
        CPLFree(pabyMaskData);
6941
0
    }
6942
6943
0
    if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6944
0
    {
6945
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6946
0
        return CE_Failure;
6947
0
    }
6948
6949
    /* -------------------------------------------------------------------- */
6950
    /*      Save computed information.                                      */
6951
    /* -------------------------------------------------------------------- */
6952
0
    const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
6953
6954
0
    if (nValidCount > 0)
6955
0
    {
6956
0
        if (bApproxOK)
6957
0
        {
6958
0
            SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6959
0
        }
6960
0
        else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6961
0
        {
6962
0
            SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6963
0
        }
6964
0
        SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6965
0
    }
6966
0
    else
6967
0
    {
6968
0
        dfMin = 0.0;
6969
0
        dfMax = 0.0;
6970
0
    }
6971
6972
0
    SetValidPercent(nSampleCount, nValidCount);
6973
6974
    /* -------------------------------------------------------------------- */
6975
    /*      Record results.                                                 */
6976
    /* -------------------------------------------------------------------- */
6977
0
    if (pdfMin != nullptr)
6978
0
        *pdfMin = dfMin;
6979
0
    if (pdfMax != nullptr)
6980
0
        *pdfMax = dfMax;
6981
6982
0
    if (pdfMean != nullptr)
6983
0
        *pdfMean = dfMean;
6984
6985
0
    if (pdfStdDev != nullptr)
6986
0
        *pdfStdDev = dfStdDev;
6987
6988
0
    if (nValidCount > 0)
6989
0
        return CE_None;
6990
6991
0
    ReportError(
6992
0
        CE_Failure, CPLE_AppDefined,
6993
0
        "Failed to compute statistics, no valid pixels found in sampling.");
6994
0
    return CE_Failure;
6995
0
}
6996
6997
/************************************************************************/
6998
/*                    GDALComputeRasterStatistics()                     */
6999
/************************************************************************/
7000
7001
/**
7002
 * \brief Compute image statistics.
7003
 *
7004
 * @see GDALRasterBand::ComputeStatistics()
7005
 */
7006
7007
CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7008
                                               int bApproxOK, double *pdfMin,
7009
                                               double *pdfMax, double *pdfMean,
7010
                                               double *pdfStdDev,
7011
                                               GDALProgressFunc pfnProgress,
7012
                                               void *pProgressData)
7013
7014
0
{
7015
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7016
7017
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7018
7019
0
    return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7020
0
                                     pdfStdDev, pfnProgress, pProgressData);
7021
0
}
7022
7023
/************************************************************************/
7024
/*                           SetStatistics()                            */
7025
/************************************************************************/
7026
7027
/**
7028
 * \brief Set statistics on band.
7029
 *
7030
 * This method can be used to store min/max/mean/standard deviation
7031
 * statistics on a raster band.
7032
 *
7033
 * The default implementation stores them as metadata, and will only work
7034
 * on formats that can save arbitrary metadata.  This method cannot detect
7035
 * whether metadata will be properly saved and so may return CE_None even
7036
 * if the statistics will never be saved.
7037
 *
7038
 * This method is the same as the C function GDALSetRasterStatistics().
7039
 *
7040
 * @param dfMin minimum pixel value.
7041
 *
7042
 * @param dfMax maximum pixel value.
7043
 *
7044
 * @param dfMean mean (average) of all pixel values.
7045
 *
7046
 * @param dfStdDev Standard deviation of all pixel values.
7047
 *
7048
 * @return CE_None on success or CE_Failure on failure.
7049
 */
7050
7051
CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7052
                                     double dfStdDev)
7053
7054
0
{
7055
0
    char szValue[128] = {0};
7056
7057
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7058
0
    SetMetadataItem("STATISTICS_MINIMUM", szValue);
7059
7060
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7061
0
    SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7062
7063
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7064
0
    SetMetadataItem("STATISTICS_MEAN", szValue);
7065
7066
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7067
0
    SetMetadataItem("STATISTICS_STDDEV", szValue);
7068
7069
0
    return CE_None;
7070
0
}
7071
7072
/************************************************************************/
7073
/*                      GDALSetRasterStatistics()                       */
7074
/************************************************************************/
7075
7076
/**
7077
 * \brief Set statistics on band.
7078
 *
7079
 * @see GDALRasterBand::SetStatistics()
7080
 */
7081
7082
CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7083
                                           double dfMax, double dfMean,
7084
                                           double dfStdDev)
7085
7086
0
{
7087
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7088
7089
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7090
0
    return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7091
0
}
7092
7093
/************************************************************************/
7094
/*                        ComputeRasterMinMax()                         */
7095
/************************************************************************/
7096
7097
template <class T, bool HAS_NODATA>
7098
static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7099
                          T *pMax)
7100
0
{
7101
0
    T min0 = *pMin;
7102
0
    T max0 = *pMax;
7103
0
    T min1 = *pMin;
7104
0
    T max1 = *pMax;
7105
0
    size_t i;
7106
0
    for (i = 0; i + 1 < nElts; i += 2)
7107
0
    {
7108
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
7109
0
        {
7110
0
            min0 = std::min(min0, buffer[i]);
7111
0
            max0 = std::max(max0, buffer[i]);
7112
0
        }
7113
0
        if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7114
0
        {
7115
0
            min1 = std::min(min1, buffer[i + 1]);
7116
0
            max1 = std::max(max1, buffer[i + 1]);
7117
0
        }
7118
0
    }
7119
0
    T min = std::min(min0, min1);
7120
0
    T max = std::max(max0, max1);
7121
0
    if (i < nElts)
7122
0
    {
7123
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
7124
0
        {
7125
0
            min = std::min(min, buffer[i]);
7126
0
            max = std::max(max, buffer[i]);
7127
0
        }
7128
0
    }
7129
0
    *pMin = min;
7130
0
    *pMax = max;
7131
0
}
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMax<short, true>(short const*, unsigned long, short, short*, short*)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMax<short, false>(short const*, unsigned long, short, short*, short*)
7132
7133
template <GDALDataType eDataType, bool bSignedByte>
7134
static void
7135
ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7136
                     int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7137
                     const GByte *pabyMaskData, double &dfMin, double &dfMax)
7138
0
{
7139
0
    double dfLocalMin = dfMin;
7140
0
    double dfLocalMax = dfMax;
7141
7142
0
    for (int iY = 0; iY < nYCheck; iY++)
7143
0
    {
7144
0
        for (int iX = 0; iX < nXCheck; iX++)
7145
0
        {
7146
0
            const GPtrDiff_t iOffset =
7147
0
                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7148
0
            if (pabyMaskData && pabyMaskData[iOffset] == 0)
7149
0
                continue;
7150
0
            bool bValid = true;
7151
0
            double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7152
0
                                           iOffset, sNoDataValues, bValid);
7153
0
            if (!bValid)
7154
0
                continue;
7155
7156
0
            dfLocalMin = std::min(dfLocalMin, dfValue);
7157
0
            dfLocalMax = std::max(dfLocalMax, dfValue);
7158
0
        }
7159
0
    }
7160
7161
0
    dfMin = dfLocalMin;
7162
0
    dfMax = dfLocalMax;
7163
0
}
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)1, true>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)1, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)14, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)2, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)3, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)4, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)5, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)12, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)13, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)15, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)6, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)7, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)8, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)9, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)16, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)10, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)11, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
7164
7165
static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
7166
                                 bool bSignedByte, int nXCheck, int nYCheck,
7167
                                 int nBlockXSize,
7168
                                 const GDALNoDataValues &sNoDataValues,
7169
                                 const GByte *pabyMaskData, double &dfMin,
7170
                                 double &dfMax)
7171
0
{
7172
0
    switch (eDataType)
7173
0
    {
7174
0
        case GDT_Unknown:
7175
0
            CPLAssert(false);
7176
0
            break;
7177
0
        case GDT_Byte:
7178
0
            if (bSignedByte)
7179
0
            {
7180
0
                ComputeMinMaxGeneric<GDT_Byte, true>(
7181
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7182
0
                    pabyMaskData, dfMin, dfMax);
7183
0
            }
7184
0
            else
7185
0
            {
7186
0
                ComputeMinMaxGeneric<GDT_Byte, false>(
7187
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7188
0
                    pabyMaskData, dfMin, dfMax);
7189
0
            }
7190
0
            break;
7191
0
        case GDT_Int8:
7192
0
            ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
7193
0
                                                  nBlockXSize, sNoDataValues,
7194
0
                                                  pabyMaskData, dfMin, dfMax);
7195
0
            break;
7196
0
        case GDT_UInt16:
7197
0
            ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
7198
0
                                                    nBlockXSize, sNoDataValues,
7199
0
                                                    pabyMaskData, dfMin, dfMax);
7200
0
            break;
7201
0
        case GDT_Int16:
7202
0
            ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
7203
0
                                                   nBlockXSize, sNoDataValues,
7204
0
                                                   pabyMaskData, dfMin, dfMax);
7205
0
            break;
7206
0
        case GDT_UInt32:
7207
0
            ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
7208
0
                                                    nBlockXSize, sNoDataValues,
7209
0
                                                    pabyMaskData, dfMin, dfMax);
7210
0
            break;
7211
0
        case GDT_Int32:
7212
0
            ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
7213
0
                                                   nBlockXSize, sNoDataValues,
7214
0
                                                   pabyMaskData, dfMin, dfMax);
7215
0
            break;
7216
0
        case GDT_UInt64:
7217
0
            ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
7218
0
                                                    nBlockXSize, sNoDataValues,
7219
0
                                                    pabyMaskData, dfMin, dfMax);
7220
0
            break;
7221
0
        case GDT_Int64:
7222
0
            ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
7223
0
                                                   nBlockXSize, sNoDataValues,
7224
0
                                                   pabyMaskData, dfMin, dfMax);
7225
0
            break;
7226
0
        case GDT_Float16:
7227
0
            ComputeMinMaxGeneric<GDT_Float16, false>(
7228
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7229
0
                pabyMaskData, dfMin, dfMax);
7230
0
            break;
7231
0
        case GDT_Float32:
7232
0
            ComputeMinMaxGeneric<GDT_Float32, false>(
7233
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7234
0
                pabyMaskData, dfMin, dfMax);
7235
0
            break;
7236
0
        case GDT_Float64:
7237
0
            ComputeMinMaxGeneric<GDT_Float64, false>(
7238
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7239
0
                pabyMaskData, dfMin, dfMax);
7240
0
            break;
7241
0
        case GDT_CInt16:
7242
0
            ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
7243
0
                                                    nBlockXSize, sNoDataValues,
7244
0
                                                    pabyMaskData, dfMin, dfMax);
7245
0
            break;
7246
0
        case GDT_CInt32:
7247
0
            ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
7248
0
                                                    nBlockXSize, sNoDataValues,
7249
0
                                                    pabyMaskData, dfMin, dfMax);
7250
0
            break;
7251
0
        case GDT_CFloat16:
7252
0
            ComputeMinMaxGeneric<GDT_CFloat16, false>(
7253
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7254
0
                pabyMaskData, dfMin, dfMax);
7255
0
            break;
7256
0
        case GDT_CFloat32:
7257
0
            ComputeMinMaxGeneric<GDT_CFloat32, false>(
7258
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7259
0
                pabyMaskData, dfMin, dfMax);
7260
0
            break;
7261
0
        case GDT_CFloat64:
7262
0
            ComputeMinMaxGeneric<GDT_CFloat64, false>(
7263
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7264
0
                pabyMaskData, dfMin, dfMax);
7265
0
            break;
7266
0
        case GDT_TypeCount:
7267
0
            CPLAssert(false);
7268
0
            break;
7269
0
    }
7270
0
}
7271
7272
static bool ComputeMinMaxGenericIterBlocks(
7273
    GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
7274
    GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
7275
    const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
7276
    double &dfMin, double &dfMax)
7277
7278
0
{
7279
0
    GByte *pabyMaskData = nullptr;
7280
0
    int nBlockXSize, nBlockYSize;
7281
0
    poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7282
7283
0
    if (poMaskBand)
7284
0
    {
7285
0
        pabyMaskData =
7286
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7287
0
        if (!pabyMaskData)
7288
0
        {
7289
0
            return false;
7290
0
        }
7291
0
    }
7292
7293
0
    for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7294
0
         iSampleBlock += nSampleRate)
7295
0
    {
7296
0
        const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7297
0
        const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7298
7299
0
        GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7300
0
        if (poBlock == nullptr)
7301
0
        {
7302
0
            CPLFree(pabyMaskData);
7303
0
            return false;
7304
0
        }
7305
7306
0
        void *const pData = poBlock->GetDataRef();
7307
7308
0
        int nXCheck = 0, nYCheck = 0;
7309
0
        poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7310
7311
0
        if (poMaskBand &&
7312
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7313
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
7314
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7315
0
                                 nBlockXSize, nullptr) != CE_None)
7316
0
        {
7317
0
            poBlock->DropLock();
7318
0
            CPLFree(pabyMaskData);
7319
0
            return false;
7320
0
        }
7321
7322
0
        ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7323
0
                             nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
7324
0
                             dfMax);
7325
7326
0
        poBlock->DropLock();
7327
0
    }
7328
7329
0
    CPLFree(pabyMaskData);
7330
0
    return true;
7331
0
}
7332
7333
/**
7334
 * \brief Compute the min/max values for a band.
7335
 *
7336
 * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7337
 * be trusted.  If it doesn't work, a subsample of blocks will be read to
7338
 * get an approximate min/max.  If the band has a nodata value it will
7339
 * be excluded from the minimum and maximum.
7340
 *
7341
 * If bApprox is FALSE, then all pixels will be read and used to compute
7342
 * an exact range.
7343
 *
7344
 * This method is the same as the C function GDALComputeRasterMinMax().
7345
 *
7346
 * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7347
 * FALSE.
7348
 * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7349
 * maximum (adfMinMax[1]) are returned.
7350
 *
7351
 * @return CE_None on success or CE_Failure on failure.
7352
 */
7353
7354
CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7355
0
{
7356
    /* -------------------------------------------------------------------- */
7357
    /*      Does the driver already know the min/max?                       */
7358
    /* -------------------------------------------------------------------- */
7359
0
    if (bApproxOK)
7360
0
    {
7361
0
        int bSuccessMin = FALSE;
7362
0
        int bSuccessMax = FALSE;
7363
7364
0
        double dfMin = GetMinimum(&bSuccessMin);
7365
0
        double dfMax = GetMaximum(&bSuccessMax);
7366
7367
0
        if (bSuccessMin && bSuccessMax)
7368
0
        {
7369
0
            adfMinMax[0] = dfMin;
7370
0
            adfMinMax[1] = dfMax;
7371
0
            return CE_None;
7372
0
        }
7373
0
    }
7374
7375
    /* -------------------------------------------------------------------- */
7376
    /*      If we have overview bands, use them for min/max.                */
7377
    /* -------------------------------------------------------------------- */
7378
    // cppcheck-suppress knownConditionTrueFalse
7379
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7380
0
    {
7381
0
        GDALRasterBand *poBand =
7382
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7383
7384
0
        if (poBand != this)
7385
0
            return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7386
0
    }
7387
7388
    /* -------------------------------------------------------------------- */
7389
    /*      Read actual data and compute minimum and maximum.               */
7390
    /* -------------------------------------------------------------------- */
7391
0
    GDALNoDataValues sNoDataValues(this, eDataType);
7392
0
    GDALRasterBand *poMaskBand = nullptr;
7393
0
    if (!sNoDataValues.bGotNoDataValue)
7394
0
    {
7395
0
        const int l_nMaskFlags = GetMaskFlags();
7396
0
        if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7397
0
            GetColorInterpretation() != GCI_AlphaBand)
7398
0
        {
7399
0
            poMaskBand = GetMaskBand();
7400
0
        }
7401
0
    }
7402
7403
0
    bool bSignedByte = false;
7404
0
    if (eDataType == GDT_Byte)
7405
0
    {
7406
0
        EnablePixelTypeSignedByteWarning(false);
7407
0
        const char *pszPixelType =
7408
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7409
0
        EnablePixelTypeSignedByteWarning(true);
7410
0
        bSignedByte =
7411
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7412
0
    }
7413
7414
0
    GDALRasterIOExtraArg sExtraArg;
7415
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7416
7417
0
    GUInt32 nMin = (eDataType == GDT_Byte)
7418
0
                       ? 255
7419
0
                       : 65535;  // used for GByte & GUInt16 cases
7420
0
    GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
7421
0
    GInt16 nMinInt16 =
7422
0
        std::numeric_limits<GInt16>::max();  // used for GInt16 case
7423
0
    GInt16 nMaxInt16 =
7424
0
        std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
7425
0
    double dfMin =
7426
0
        std::numeric_limits<double>::infinity();  // used for generic code path
7427
0
    double dfMax =
7428
0
        -std::numeric_limits<double>::infinity();  // used for generic code path
7429
0
    const bool bUseOptimizedPath =
7430
0
        !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7431
0
                        eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7432
7433
0
    const auto ComputeMinMaxForBlock =
7434
0
        [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
7435
0
         &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
7436
0
                     int nYCheck)
7437
0
    {
7438
0
        if (eDataType == GDT_Byte && !bSignedByte)
7439
0
        {
7440
0
            const bool bHasNoData =
7441
0
                sNoDataValues.bGotNoDataValue &&
7442
0
                GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
7443
0
                static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
7444
0
                    sNoDataValues.dfNoDataValue;
7445
0
            const GUInt32 nNoDataValue =
7446
0
                bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
7447
0
                           : 0;
7448
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
7449
0
            ComputeStatisticsInternal<GByte,
7450
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
7451
0
                f(nXCheck, nBufferWidth, nYCheck,
7452
0
                  static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7453
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7454
0
        }
7455
0
        else if (eDataType == GDT_UInt16)
7456
0
        {
7457
0
            const bool bHasNoData =
7458
0
                sNoDataValues.bGotNoDataValue &&
7459
0
                GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
7460
0
                static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
7461
0
                    sNoDataValues.dfNoDataValue;
7462
0
            const GUInt32 nNoDataValue =
7463
0
                bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
7464
0
                           : 0;
7465
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
7466
0
            ComputeStatisticsInternal<GUInt16,
7467
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
7468
0
                f(nXCheck, nBufferWidth, nYCheck,
7469
0
                  static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7470
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7471
0
        }
7472
0
        else if (eDataType == GDT_Int16)
7473
0
        {
7474
0
            const bool bHasNoData =
7475
0
                sNoDataValues.bGotNoDataValue &&
7476
0
                GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
7477
0
                static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
7478
0
                    sNoDataValues.dfNoDataValue;
7479
0
            if (bHasNoData)
7480
0
            {
7481
0
                const int16_t nNoDataValue =
7482
0
                    static_cast<int16_t>(sNoDataValues.dfNoDataValue);
7483
0
                for (int iY = 0; iY < nYCheck; iY++)
7484
0
                {
7485
0
                    ComputeMinMax<int16_t, true>(
7486
0
                        static_cast<const int16_t *>(pData) +
7487
0
                            static_cast<size_t>(iY) * nBufferWidth,
7488
0
                        nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7489
0
                }
7490
0
            }
7491
0
            else
7492
0
            {
7493
0
                for (int iY = 0; iY < nYCheck; iY++)
7494
0
                {
7495
0
                    ComputeMinMax<int16_t, false>(
7496
0
                        static_cast<const int16_t *>(pData) +
7497
0
                            static_cast<size_t>(iY) * nBufferWidth,
7498
0
                        nXCheck, 0, &nMinInt16, &nMaxInt16);
7499
0
                }
7500
0
            }
7501
0
        }
7502
0
    };
7503
7504
0
    if (bApproxOK && HasArbitraryOverviews())
7505
0
    {
7506
        /* --------------------------------------------------------------------
7507
         */
7508
        /*      Figure out how much the image should be reduced to get an */
7509
        /*      approximate value. */
7510
        /* --------------------------------------------------------------------
7511
         */
7512
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7513
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7514
7515
0
        int nXReduced = nRasterXSize;
7516
0
        int nYReduced = nRasterYSize;
7517
0
        if (dfReduction > 1.0)
7518
0
        {
7519
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7520
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7521
7522
            // Catch the case of huge resizing ratios here
7523
0
            if (nXReduced == 0)
7524
0
                nXReduced = 1;
7525
0
            if (nYReduced == 0)
7526
0
                nYReduced = 1;
7527
0
        }
7528
7529
0
        void *const pData = CPLMalloc(cpl::fits_on<int>(
7530
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7531
7532
0
        const CPLErr eErr =
7533
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7534
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7535
0
        if (eErr != CE_None)
7536
0
        {
7537
0
            CPLFree(pData);
7538
0
            return eErr;
7539
0
        }
7540
7541
0
        GByte *pabyMaskData = nullptr;
7542
0
        if (poMaskBand)
7543
0
        {
7544
0
            pabyMaskData =
7545
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7546
0
            if (!pabyMaskData)
7547
0
            {
7548
0
                CPLFree(pData);
7549
0
                return CE_Failure;
7550
0
            }
7551
7552
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7553
0
                                     pabyMaskData, nXReduced, nYReduced,
7554
0
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
7555
0
            {
7556
0
                CPLFree(pData);
7557
0
                CPLFree(pabyMaskData);
7558
0
                return CE_Failure;
7559
0
            }
7560
0
        }
7561
7562
0
        if (bUseOptimizedPath)
7563
0
        {
7564
0
            ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7565
0
        }
7566
0
        else
7567
0
        {
7568
0
            ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
7569
0
                                 nYReduced, nXReduced, sNoDataValues,
7570
0
                                 pabyMaskData, dfMin, dfMax);
7571
0
        }
7572
7573
0
        CPLFree(pData);
7574
0
        CPLFree(pabyMaskData);
7575
0
    }
7576
7577
0
    else  // No arbitrary overviews
7578
0
    {
7579
0
        if (!InitBlockInfo())
7580
0
            return CE_Failure;
7581
7582
        /* --------------------------------------------------------------------
7583
         */
7584
        /*      Figure out the ratio of blocks we will read to get an */
7585
        /*      approximate value. */
7586
        /* --------------------------------------------------------------------
7587
         */
7588
0
        int nSampleRate = 1;
7589
7590
0
        if (bApproxOK)
7591
0
        {
7592
0
            nSampleRate = static_cast<int>(std::max(
7593
0
                1.0,
7594
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7595
            // We want to avoid probing only the first column of blocks for
7596
            // a square shaped raster, because it is not unlikely that it may
7597
            // be padding only (#6378).
7598
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7599
0
                nSampleRate += 1;
7600
0
        }
7601
7602
0
        if (bUseOptimizedPath)
7603
0
        {
7604
0
            for (GIntBig iSampleBlock = 0;
7605
0
                 iSampleBlock <
7606
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7607
0
                 iSampleBlock += nSampleRate)
7608
0
            {
7609
0
                const int iYBlock =
7610
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
7611
0
                const int iXBlock =
7612
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
7613
7614
0
                GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7615
0
                if (poBlock == nullptr)
7616
0
                    return CE_Failure;
7617
7618
0
                void *const pData = poBlock->GetDataRef();
7619
7620
0
                int nXCheck = 0, nYCheck = 0;
7621
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7622
7623
0
                ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7624
7625
0
                poBlock->DropLock();
7626
7627
0
                if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7628
0
                    nMax == 255)
7629
0
                    break;
7630
0
            }
7631
0
        }
7632
0
        else
7633
0
        {
7634
0
            const GIntBig nTotalBlocks =
7635
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7636
0
            if (!ComputeMinMaxGenericIterBlocks(
7637
0
                    this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7638
0
                    nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
7639
0
            {
7640
0
                return CE_Failure;
7641
0
            }
7642
0
        }
7643
0
    }
7644
7645
0
    if (bUseOptimizedPath)
7646
0
    {
7647
0
        if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7648
0
        {
7649
0
            dfMin = nMin;
7650
0
            dfMax = nMax;
7651
0
        }
7652
0
        else if (eDataType == GDT_Int16)
7653
0
        {
7654
0
            dfMin = nMinInt16;
7655
0
            dfMax = nMaxInt16;
7656
0
        }
7657
0
    }
7658
7659
0
    if (dfMin > dfMax)
7660
0
    {
7661
0
        adfMinMax[0] = 0;
7662
0
        adfMinMax[1] = 0;
7663
0
        ReportError(
7664
0
            CE_Failure, CPLE_AppDefined,
7665
0
            "Failed to compute min/max, no valid pixels found in sampling.");
7666
0
        return CE_Failure;
7667
0
    }
7668
7669
0
    adfMinMax[0] = dfMin;
7670
0
    adfMinMax[1] = dfMax;
7671
7672
0
    return CE_None;
7673
0
}
7674
7675
/************************************************************************/
7676
/*                      GDALComputeRasterMinMax()                       */
7677
/************************************************************************/
7678
7679
/**
7680
 * \brief Compute the min/max values for a band.
7681
 *
7682
 * @see GDALRasterBand::ComputeRasterMinMax()
7683
 *
7684
 * @note Prior to GDAL 3.6, this function returned void
7685
 */
7686
7687
CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7688
                                           double adfMinMax[2])
7689
7690
0
{
7691
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7692
7693
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7694
0
    return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7695
0
}
7696
7697
/************************************************************************/
7698
/*                    ComputeRasterMinMaxLocation()                     */
7699
/************************************************************************/
7700
7701
/**
7702
 * \brief Compute the min/max values for a band, and their location.
7703
 *
7704
 * Pixels whose value matches the nodata value or are masked by the mask
7705
 * band are ignored.
7706
 *
7707
 * If the minimum or maximum value is hit in several locations, it is not
7708
 * specified which one will be returned.
7709
 *
7710
 * @param[out] pdfMin Pointer to the minimum value.
7711
 * @param[out] pdfMax Pointer to the maximum value.
7712
 * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7713
 * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7714
 * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7715
 * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7716
 *
7717
 * @return CE_None in case of success, CE_Warning if there are no valid values,
7718
 *         CE_Failure in case of error.
7719
 *
7720
 * @since GDAL 3.11
7721
 */
7722
7723
CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7724
                                                   double *pdfMax, int *pnMinX,
7725
                                                   int *pnMinY, int *pnMaxX,
7726
                                                   int *pnMaxY)
7727
0
{
7728
0
    int nMinX = -1;
7729
0
    int nMinY = -1;
7730
0
    int nMaxX = -1;
7731
0
    int nMaxY = -1;
7732
0
    double dfMin = std::numeric_limits<double>::infinity();
7733
0
    double dfMax = -std::numeric_limits<double>::infinity();
7734
0
    if (pdfMin)
7735
0
        *pdfMin = dfMin;
7736
0
    if (pdfMax)
7737
0
        *pdfMax = dfMax;
7738
0
    if (pnMinX)
7739
0
        *pnMinX = nMinX;
7740
0
    if (pnMinY)
7741
0
        *pnMinY = nMinY;
7742
0
    if (pnMaxX)
7743
0
        *pnMaxX = nMaxX;
7744
0
    if (pnMaxY)
7745
0
        *pnMaxY = nMaxY;
7746
7747
0
    if (GDALDataTypeIsComplex(eDataType))
7748
0
    {
7749
0
        CPLError(CE_Failure, CPLE_NotSupported,
7750
0
                 "Complex data type not supported");
7751
0
        return CE_Failure;
7752
0
    }
7753
7754
0
    if (!InitBlockInfo())
7755
0
        return CE_Failure;
7756
7757
0
    GDALNoDataValues sNoDataValues(this, eDataType);
7758
0
    GDALRasterBand *poMaskBand = nullptr;
7759
0
    if (!sNoDataValues.bGotNoDataValue)
7760
0
    {
7761
0
        const int l_nMaskFlags = GetMaskFlags();
7762
0
        if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
7763
0
            GetColorInterpretation() != GCI_AlphaBand)
7764
0
        {
7765
0
            poMaskBand = GetMaskBand();
7766
0
        }
7767
0
    }
7768
7769
0
    bool bSignedByte = false;
7770
0
    if (eDataType == GDT_Byte)
7771
0
    {
7772
0
        EnablePixelTypeSignedByteWarning(false);
7773
0
        const char *pszPixelType =
7774
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7775
0
        EnablePixelTypeSignedByteWarning(true);
7776
0
        bSignedByte =
7777
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7778
0
    }
7779
7780
0
    GByte *pabyMaskData = nullptr;
7781
0
    if (poMaskBand)
7782
0
    {
7783
0
        pabyMaskData =
7784
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7785
0
        if (!pabyMaskData)
7786
0
        {
7787
0
            return CE_Failure;
7788
0
        }
7789
0
    }
7790
7791
0
    const GIntBig nTotalBlocks =
7792
0
        static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7793
0
    bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7794
0
    bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7795
0
    for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7796
0
    {
7797
0
        const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7798
0
        const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7799
7800
0
        GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7801
0
        if (poBlock == nullptr)
7802
0
        {
7803
0
            CPLFree(pabyMaskData);
7804
0
            return CE_Failure;
7805
0
        }
7806
7807
0
        void *const pData = poBlock->GetDataRef();
7808
7809
0
        int nXCheck = 0, nYCheck = 0;
7810
0
        GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7811
7812
0
        if (poMaskBand &&
7813
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7814
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
7815
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7816
0
                                 nBlockXSize, nullptr) != CE_None)
7817
0
        {
7818
0
            poBlock->DropLock();
7819
0
            CPLFree(pabyMaskData);
7820
0
            return CE_Failure;
7821
0
        }
7822
7823
0
        if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7824
0
        {
7825
0
            for (int iY = 0; iY < nYCheck; ++iY)
7826
0
            {
7827
0
                for (int iX = 0; iX < nXCheck; ++iX)
7828
0
                {
7829
0
                    const GPtrDiff_t iOffset =
7830
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7831
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
7832
0
                        continue;
7833
0
                    bool bValid = true;
7834
0
                    double dfValue =
7835
0
                        GetPixelValue(eDataType, bSignedByte, pData, iOffset,
7836
0
                                      sNoDataValues, bValid);
7837
0
                    if (!bValid)
7838
0
                        continue;
7839
0
                    if (dfValue < dfMin)
7840
0
                    {
7841
0
                        dfMin = dfValue;
7842
0
                        nMinX = iXBlock * nBlockXSize + iX;
7843
0
                        nMinY = iYBlock * nBlockYSize + iY;
7844
0
                    }
7845
0
                    if (dfValue > dfMax)
7846
0
                    {
7847
0
                        dfMax = dfValue;
7848
0
                        nMaxX = iXBlock * nBlockXSize + iX;
7849
0
                        nMaxY = iYBlock * nBlockYSize + iY;
7850
0
                    }
7851
0
                }
7852
0
            }
7853
0
        }
7854
0
        else
7855
0
        {
7856
0
            size_t pos_min = 0;
7857
0
            size_t pos_max = 0;
7858
0
            const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7859
0
            if (bNeedsMin && bNeedsMax)
7860
0
            {
7861
0
                std::tie(pos_min, pos_max) = gdal::minmax_element(
7862
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7863
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
7864
0
                    sNoDataValues.dfNoDataValue);
7865
0
            }
7866
0
            else if (bNeedsMin)
7867
0
            {
7868
0
                pos_min = gdal::min_element(
7869
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7870
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
7871
0
                    sNoDataValues.dfNoDataValue);
7872
0
            }
7873
0
            else if (bNeedsMax)
7874
0
            {
7875
0
                pos_max = gdal::max_element(
7876
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7877
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
7878
0
                    sNoDataValues.dfNoDataValue);
7879
0
            }
7880
7881
0
            if (bNeedsMin)
7882
0
            {
7883
0
                const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7884
0
                const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7885
0
                bool bValid = true;
7886
0
                const double dfMinValueBlock =
7887
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_min,
7888
0
                                  sNoDataValues, bValid);
7889
0
                if (bValid && dfMinValueBlock < dfMin)
7890
0
                {
7891
0
                    dfMin = dfMinValueBlock;
7892
0
                    nMinX = iXBlock * nBlockXSize + nMinXBlock;
7893
0
                    nMinY = iYBlock * nBlockYSize + nMinYBlock;
7894
0
                }
7895
0
            }
7896
7897
0
            if (bNeedsMax)
7898
0
            {
7899
0
                const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7900
0
                const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7901
0
                bool bValid = true;
7902
0
                const double dfMaxValueBlock =
7903
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_max,
7904
0
                                  sNoDataValues, bValid);
7905
0
                if (bValid && dfMaxValueBlock > dfMax)
7906
0
                {
7907
0
                    dfMax = dfMaxValueBlock;
7908
0
                    nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7909
0
                    nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7910
0
                }
7911
0
            }
7912
0
        }
7913
7914
0
        poBlock->DropLock();
7915
7916
0
        if (eDataType == GDT_Byte)
7917
0
        {
7918
0
            if (bNeedsMin && dfMin == 0)
7919
0
            {
7920
0
                bNeedsMin = false;
7921
0
            }
7922
0
            if (bNeedsMax && dfMax == 255)
7923
0
            {
7924
0
                bNeedsMax = false;
7925
0
            }
7926
0
            if (!bNeedsMin && !bNeedsMax)
7927
0
            {
7928
0
                break;
7929
0
            }
7930
0
        }
7931
0
    }
7932
7933
0
    CPLFree(pabyMaskData);
7934
7935
0
    if (pdfMin)
7936
0
        *pdfMin = dfMin;
7937
0
    if (pdfMax)
7938
0
        *pdfMax = dfMax;
7939
0
    if (pnMinX)
7940
0
        *pnMinX = nMinX;
7941
0
    if (pnMinY)
7942
0
        *pnMinY = nMinY;
7943
0
    if (pnMaxX)
7944
0
        *pnMaxX = nMaxX;
7945
0
    if (pnMaxY)
7946
0
        *pnMaxY = nMaxY;
7947
0
    return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
7948
0
                                                                  : CE_None;
7949
0
}
7950
7951
/************************************************************************/
7952
/*                    GDALComputeRasterMinMaxLocation()                 */
7953
/************************************************************************/
7954
7955
/**
7956
 * \brief Compute the min/max values for a band, and their location.
7957
 *
7958
 * @see GDALRasterBand::ComputeRasterMinMax()
7959
 * @since GDAL 3.11
7960
 */
7961
7962
CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
7963
                                       double *pdfMax, int *pnMinX, int *pnMinY,
7964
                                       int *pnMaxX, int *pnMaxY)
7965
7966
0
{
7967
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
7968
7969
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7970
0
    return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
7971
0
                                               pnMaxX, pnMaxY);
7972
0
}
7973
7974
/************************************************************************/
7975
/*                        SetDefaultHistogram()                         */
7976
/************************************************************************/
7977
7978
/* FIXME : add proper documentation */
7979
/**
7980
 * \brief Set default histogram.
7981
 *
7982
 * This method is the same as the C function GDALSetDefaultHistogram() and
7983
 * GDALSetDefaultHistogramEx()
7984
 */
7985
CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
7986
                                           double /* dfMax */,
7987
                                           int /* nBuckets */,
7988
                                           GUIntBig * /* panHistogram */)
7989
7990
0
{
7991
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
7992
0
        ReportError(CE_Failure, CPLE_NotSupported,
7993
0
                    "SetDefaultHistogram() not implemented for this format.");
7994
7995
0
    return CE_Failure;
7996
0
}
7997
7998
/************************************************************************/
7999
/*                      GDALSetDefaultHistogram()                       */
8000
/************************************************************************/
8001
8002
/**
8003
 * \brief Set default histogram.
8004
 *
8005
 * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8006
 * 2 billion.
8007
 *
8008
 * @see GDALRasterBand::SetDefaultHistogram()
8009
 * @see GDALSetRasterHistogramEx()
8010
 */
8011
8012
CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8013
                                           double dfMax, int nBuckets,
8014
                                           int *panHistogram)
8015
8016
0
{
8017
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8018
8019
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8020
8021
0
    GUIntBig *panHistogramTemp =
8022
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8023
0
    if (panHistogramTemp == nullptr)
8024
0
    {
8025
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8026
0
                            "Out of memory in GDALSetDefaultHistogram().");
8027
0
        return CE_Failure;
8028
0
    }
8029
8030
0
    for (int i = 0; i < nBuckets; ++i)
8031
0
    {
8032
0
        panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8033
0
    }
8034
8035
0
    const CPLErr eErr =
8036
0
        poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8037
8038
0
    CPLFree(panHistogramTemp);
8039
8040
0
    return eErr;
8041
0
}
8042
8043
/************************************************************************/
8044
/*                     GDALSetDefaultHistogramEx()                      */
8045
/************************************************************************/
8046
8047
/**
8048
 * \brief Set default histogram.
8049
 *
8050
 * @see GDALRasterBand::SetDefaultHistogram()
8051
 *
8052
 * @since GDAL 2.0
8053
 */
8054
8055
CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8056
                                             double dfMin, double dfMax,
8057
                                             int nBuckets,
8058
                                             GUIntBig *panHistogram)
8059
8060
0
{
8061
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8062
8063
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8064
0
    return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8065
0
}
8066
8067
/************************************************************************/
8068
/*                           GetDefaultRAT()                            */
8069
/************************************************************************/
8070
8071
/**
8072
 * \brief Fetch default Raster Attribute Table.
8073
 *
8074
 * A RAT will be returned if there is a default one associated with the
8075
 * band, otherwise NULL is returned.  The returned RAT is owned by the
8076
 * band and should not be deleted by the application.
8077
 *
8078
 * This method is the same as the C function GDALGetDefaultRAT().
8079
 *
8080
 * @return NULL, or a pointer to an internal RAT owned by the band.
8081
 */
8082
8083
GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8084
8085
0
{
8086
0
    return nullptr;
8087
0
}
8088
8089
/************************************************************************/
8090
/*                         GDALGetDefaultRAT()                          */
8091
/************************************************************************/
8092
8093
/**
8094
 * \brief Fetch default Raster Attribute Table.
8095
 *
8096
 * @see GDALRasterBand::GetDefaultRAT()
8097
 */
8098
8099
GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8100
8101
0
{
8102
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8103
8104
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8105
0
    return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8106
0
}
8107
8108
/************************************************************************/
8109
/*                           SetDefaultRAT()                            */
8110
/************************************************************************/
8111
8112
/**
8113
 * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8114
 * \brief Set default Raster Attribute Table.
8115
 *
8116
 * Associates a default RAT with the band.  If not implemented for the
8117
 * format a CPLE_NotSupported error will be issued.  If successful a copy
8118
 * of the RAT is made, the original remains owned by the caller.
8119
 *
8120
 * This method is the same as the C function GDALSetDefaultRAT().
8121
 *
8122
 * @param poRAT the RAT to assign to the band.
8123
 *
8124
 * @return CE_None on success or CE_Failure if unsupported or otherwise
8125
 * failing.
8126
 */
8127
8128
/**/
8129
/**/
8130
8131
CPLErr
8132
GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8133
0
{
8134
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8135
0
    {
8136
0
        CPLPushErrorHandler(CPLQuietErrorHandler);
8137
0
        ReportError(CE_Failure, CPLE_NotSupported,
8138
0
                    "SetDefaultRAT() not implemented for this format.");
8139
0
        CPLPopErrorHandler();
8140
0
    }
8141
0
    return CE_Failure;
8142
0
}
8143
8144
/************************************************************************/
8145
/*                         GDALSetDefaultRAT()                          */
8146
/************************************************************************/
8147
8148
/**
8149
 * \brief Set default Raster Attribute Table.
8150
 *
8151
 * @see GDALRasterBand::GDALSetDefaultRAT()
8152
 */
8153
8154
CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
8155
                                     GDALRasterAttributeTableH hRAT)
8156
8157
0
{
8158
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
8159
8160
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8161
8162
0
    return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
8163
0
}
8164
8165
/************************************************************************/
8166
/*                            GetMaskBand()                             */
8167
/************************************************************************/
8168
8169
/**
8170
 * \brief Return the mask band associated with the band.
8171
 *
8172
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
8173
 * that returns one of four default implementations :
8174
 * <ul>
8175
 * <li>If a corresponding .msk file exists it will be used for the mask band.
8176
 * </li>
8177
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8178
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8179
 * GMF_NODATA | GMF_PER_DATASET.
8180
 * </li>
8181
 * <li>If the band has a nodata value set, an instance of the new
8182
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8183
 * GMF_NODATA.
8184
 * </li>
8185
 * <li>If there is no nodata value, but the dataset has an alpha band that seems
8186
 * to apply to this band (specific rules yet to be determined) and that is of
8187
 * type GDT_Byte then that alpha band will be returned, and the flags
8188
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8189
 * </li>
8190
 * <li>If neither of the above apply, an instance of the new
8191
 * GDALAllValidRasterBand class will be returned that has 255 values for all
8192
 * pixels. The null flags will return GMF_ALL_VALID.
8193
 * </li>
8194
 * </ul>
8195
 *
8196
 * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
8197
 * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
8198
 *
8199
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8200
 * dataset, with the same name as the main dataset and suffixed with .msk,
8201
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8202
 * main dataset.
8203
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8204
 * level, where xx matches the band number of a band of the main dataset. The
8205
 * value of those items is a combination of the flags GMF_ALL_VALID,
8206
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8207
 * a band, then the other rules explained above will be used to generate a
8208
 * on-the-fly mask band.
8209
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8210
 *
8211
 * This method is the same as the C function GDALGetMaskBand().
8212
 *
8213
 * @return a valid mask band.
8214
 *
8215
 * @since GDAL 1.5.0
8216
 *
8217
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8218
 *
8219
 */
8220
GDALRasterBand *GDALRasterBand::GetMaskBand()
8221
8222
0
{
8223
0
    const auto HasNoData = [this]()
8224
0
    {
8225
0
        int bHaveNoDataRaw = FALSE;
8226
0
        bool bHaveNoData = false;
8227
0
        if (eDataType == GDT_Int64)
8228
0
        {
8229
0
            CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
8230
0
            bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8231
0
        }
8232
0
        else if (eDataType == GDT_UInt64)
8233
0
        {
8234
0
            CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
8235
0
            bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8236
0
        }
8237
0
        else
8238
0
        {
8239
0
            const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
8240
0
            if (bHaveNoDataRaw &&
8241
0
                GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
8242
0
            {
8243
0
                bHaveNoData = true;
8244
0
            }
8245
0
        }
8246
0
        return bHaveNoData;
8247
0
    };
8248
8249
0
    if (poMask != nullptr)
8250
0
    {
8251
0
        if (poMask.IsOwned())
8252
0
        {
8253
0
            if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
8254
0
            {
8255
0
                if (HasNoData())
8256
0
                {
8257
0
                    InvalidateMaskBand();
8258
0
                }
8259
0
            }
8260
0
            else if (auto poNoDataMaskBand =
8261
0
                         dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
8262
0
            {
8263
0
                int bHaveNoDataRaw = FALSE;
8264
0
                bool bIsSame = false;
8265
0
                if (eDataType == GDT_Int64)
8266
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
8267
0
                                  GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
8268
0
                              bHaveNoDataRaw;
8269
0
                else if (eDataType == GDT_UInt64)
8270
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8271
0
                                  GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8272
0
                              bHaveNoDataRaw;
8273
0
                else
8274
0
                {
8275
0
                    const double dfNoDataValue =
8276
0
                        GetNoDataValue(&bHaveNoDataRaw);
8277
0
                    if (bHaveNoDataRaw)
8278
0
                    {
8279
0
                        bIsSame =
8280
0
                            std::isnan(dfNoDataValue)
8281
0
                                ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8282
0
                                : poNoDataMaskBand->m_dfNoDataValue ==
8283
0
                                      dfNoDataValue;
8284
0
                    }
8285
0
                }
8286
0
                if (!bIsSame)
8287
0
                    InvalidateMaskBand();
8288
0
            }
8289
0
        }
8290
8291
0
        if (poMask)
8292
0
            return poMask.get();
8293
0
    }
8294
8295
    /* -------------------------------------------------------------------- */
8296
    /*      Check for a mask in a .msk file.                                */
8297
    /* -------------------------------------------------------------------- */
8298
0
    if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8299
0
    {
8300
0
        poMask.reset(poDS->oOvManager.GetMaskBand(nBand), false);
8301
0
        if (poMask != nullptr)
8302
0
        {
8303
0
            nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8304
0
            return poMask.get();
8305
0
        }
8306
0
    }
8307
8308
    /* -------------------------------------------------------------------- */
8309
    /*      Check for NODATA_VALUES metadata.                               */
8310
    /* -------------------------------------------------------------------- */
8311
0
    if (poDS != nullptr)
8312
0
    {
8313
0
        const char *pszGDALNoDataValues =
8314
0
            poDS->GetMetadataItem("NODATA_VALUES");
8315
0
        if (pszGDALNoDataValues != nullptr)
8316
0
        {
8317
0
            char **papszGDALNoDataValues = CSLTokenizeStringComplex(
8318
0
                pszGDALNoDataValues, " ", FALSE, FALSE);
8319
8320
            // Make sure we have as many values as bands.
8321
0
            if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
8322
0
                poDS->GetRasterCount() != 0)
8323
0
            {
8324
                // Make sure that all bands have the same data type
8325
                // This is clearly not a fundamental condition, just a
8326
                // condition to make implementation easier.
8327
0
                GDALDataType eDT = GDT_Unknown;
8328
0
                int i = 0;  // Used after for.
8329
0
                for (; i < poDS->GetRasterCount(); ++i)
8330
0
                {
8331
0
                    if (i == 0)
8332
0
                        eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8333
0
                    else if (eDT !=
8334
0
                             poDS->GetRasterBand(i + 1)->GetRasterDataType())
8335
0
                    {
8336
0
                        break;
8337
0
                    }
8338
0
                }
8339
0
                if (i == poDS->GetRasterCount())
8340
0
                {
8341
0
                    nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8342
0
                    try
8343
0
                    {
8344
0
                        poMask.reset(new GDALNoDataValuesMaskBand(poDS), true);
8345
0
                    }
8346
0
                    catch (const std::bad_alloc &)
8347
0
                    {
8348
0
                        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8349
0
                        poMask.reset();
8350
0
                    }
8351
0
                    CSLDestroy(papszGDALNoDataValues);
8352
0
                    return poMask.get();
8353
0
                }
8354
0
                else
8355
0
                {
8356
0
                    ReportError(CE_Warning, CPLE_AppDefined,
8357
0
                                "All bands should have the same type in "
8358
0
                                "order the NODATA_VALUES metadata item "
8359
0
                                "to be used as a mask.");
8360
0
                }
8361
0
            }
8362
0
            else
8363
0
            {
8364
0
                ReportError(
8365
0
                    CE_Warning, CPLE_AppDefined,
8366
0
                    "NODATA_VALUES metadata item doesn't have the same number "
8367
0
                    "of values as the number of bands.  "
8368
0
                    "Ignoring it for mask.");
8369
0
            }
8370
8371
0
            CSLDestroy(papszGDALNoDataValues);
8372
0
        }
8373
0
    }
8374
8375
    /* -------------------------------------------------------------------- */
8376
    /*      Check for nodata case.                                          */
8377
    /* -------------------------------------------------------------------- */
8378
0
    if (HasNoData())
8379
0
    {
8380
0
        nMaskFlags = GMF_NODATA;
8381
0
        try
8382
0
        {
8383
0
            poMask.reset(new GDALNoDataMaskBand(this), true);
8384
0
        }
8385
0
        catch (const std::bad_alloc &)
8386
0
        {
8387
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8388
0
            poMask.reset();
8389
0
        }
8390
0
        return poMask.get();
8391
0
    }
8392
8393
    /* -------------------------------------------------------------------- */
8394
    /*      Check for alpha case.                                           */
8395
    /* -------------------------------------------------------------------- */
8396
0
    if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8397
0
        this == poDS->GetRasterBand(1) &&
8398
0
        poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8399
0
    {
8400
0
        if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8401
0
        {
8402
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8403
0
            poMask.reset(poDS->GetRasterBand(2), false);
8404
0
            return poMask.get();
8405
0
        }
8406
0
        else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8407
0
        {
8408
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8409
0
            try
8410
0
            {
8411
0
                poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(2)),
8412
0
                             true);
8413
0
            }
8414
0
            catch (const std::bad_alloc &)
8415
0
            {
8416
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8417
0
                poMask.reset();
8418
0
            }
8419
0
            return poMask.get();
8420
0
        }
8421
0
    }
8422
8423
0
    if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8424
0
        (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8425
0
         this == poDS->GetRasterBand(3)) &&
8426
0
        poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8427
0
    {
8428
0
        if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8429
0
        {
8430
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8431
0
            poMask.reset(poDS->GetRasterBand(4), false);
8432
0
            return poMask.get();
8433
0
        }
8434
0
        else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8435
0
        {
8436
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8437
0
            try
8438
0
            {
8439
0
                poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(4)),
8440
0
                             true);
8441
0
            }
8442
0
            catch (const std::bad_alloc &)
8443
0
            {
8444
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8445
0
                poMask.reset();
8446
0
            }
8447
0
            return poMask.get();
8448
0
        }
8449
0
    }
8450
8451
    /* -------------------------------------------------------------------- */
8452
    /*      Fallback to all valid case.                                     */
8453
    /* -------------------------------------------------------------------- */
8454
0
    nMaskFlags = GMF_ALL_VALID;
8455
0
    try
8456
0
    {
8457
0
        poMask.reset(new GDALAllValidMaskBand(this), true);
8458
0
    }
8459
0
    catch (const std::bad_alloc &)
8460
0
    {
8461
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8462
0
        poMask.reset();
8463
0
    }
8464
8465
0
    return poMask.get();
8466
0
}
8467
8468
/************************************************************************/
8469
/*                          GDALGetMaskBand()                           */
8470
/************************************************************************/
8471
8472
/**
8473
 * \brief Return the mask band associated with the band.
8474
 *
8475
 * @see GDALRasterBand::GetMaskBand()
8476
 */
8477
8478
GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8479
8480
0
{
8481
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8482
8483
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8484
0
    return poBand->GetMaskBand();
8485
0
}
8486
8487
/************************************************************************/
8488
/*                            GetMaskFlags()                            */
8489
/************************************************************************/
8490
8491
/**
8492
 * \brief Return the status flags of the mask band associated with the band.
8493
 *
8494
 * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8495
 * the following available definitions that may be extended in the future:
8496
 * <ul>
8497
 * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8498
 * 255. When used this will normally be the only flag set.
8499
 * </li>
8500
 * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8501
 * dataset.
8502
 * </li>
8503
 * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8504
 * and may have values other than 0 and 255.
8505
 * </li>
8506
 * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8507
 * nodata values. (mutually exclusive of GMF_ALPHA)
8508
 * </li>
8509
 * </ul>
8510
 *
8511
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
8512
 * that returns one of four default implementations:
8513
 * <ul>
8514
 * <li>If a corresponding .msk file exists it will be used for the mask band.
8515
 * </li>
8516
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8517
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8518
 * GMF_NODATA | GMF_PER_DATASET.
8519
 * </li>
8520
 * <li>If the band has a nodata value set, an instance of the new
8521
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8522
 * GMF_NODATA.
8523
 * </li>
8524
 * <li>If there is no nodata value, but the dataset has an alpha band that
8525
 * seems to apply to this band (specific rules yet to be determined) and that is
8526
 * of type GDT_Byte then that alpha band will be returned, and the flags
8527
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8528
 * </li>
8529
 * <li>If neither of the above apply, an instance of the new
8530
 * GDALAllValidRasterBand class will be returned that has 255 values for all
8531
 * pixels. The null flags will return GMF_ALL_VALID.
8532
 * </li>
8533
 * </ul>
8534
 *
8535
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8536
 * dataset, with the same name as the main dataset and suffixed with .msk,
8537
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8538
 * main dataset.
8539
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8540
 * level, where xx matches the band number of a band of the main dataset. The
8541
 * value of those items is a combination of the flags GMF_ALL_VALID,
8542
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8543
 * a band, then the other rules explained above will be used to generate a
8544
 * on-the-fly mask band.
8545
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8546
 *
8547
 * This method is the same as the C function GDALGetMaskFlags().
8548
 *
8549
 * @since GDAL 1.5.0
8550
 *
8551
 * @return a valid mask band.
8552
 *
8553
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8554
 *
8555
 */
8556
int GDALRasterBand::GetMaskFlags()
8557
8558
0
{
8559
    // If we don't have a band yet, force this now so that the masks value
8560
    // will be initialized.
8561
8562
0
    if (poMask == nullptr)
8563
0
        GetMaskBand();
8564
8565
0
    return nMaskFlags;
8566
0
}
8567
8568
/************************************************************************/
8569
/*                          GDALGetMaskFlags()                          */
8570
/************************************************************************/
8571
8572
/**
8573
 * \brief Return the status flags of the mask band associated with the band.
8574
 *
8575
 * @see GDALRasterBand::GetMaskFlags()
8576
 */
8577
8578
int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8579
8580
0
{
8581
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8582
8583
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8584
0
    return poBand->GetMaskFlags();
8585
0
}
8586
8587
/************************************************************************/
8588
/*                         InvalidateMaskBand()                         */
8589
/************************************************************************/
8590
8591
//! @cond Doxygen_Suppress
8592
void GDALRasterBand::InvalidateMaskBand()
8593
0
{
8594
0
    poMask.reset();
8595
0
    nMaskFlags = 0;
8596
0
}
8597
8598
//! @endcond
8599
8600
/************************************************************************/
8601
/*                           CreateMaskBand()                           */
8602
/************************************************************************/
8603
8604
/**
8605
 * \brief Adds a mask band to the current band
8606
 *
8607
 * The default implementation of the CreateMaskBand() method is implemented
8608
 * based on similar rules to the .ovr handling implemented using the
8609
 * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8610
 * be created with the same basename as the original file, and it will have
8611
 * as many bands as the original image (or just one for GMF_PER_DATASET).
8612
 * The mask images will be deflate compressed tiled images with the same
8613
 * block size as the original image if possible.
8614
 * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8615
 * level, where xx matches the band number of a band of the main dataset. The
8616
 * value of those items will be the one of the nFlagsIn parameter.
8617
 *
8618
 * Note that if you got a mask band with a previous call to GetMaskBand(),
8619
 * it might be invalidated by CreateMaskBand(). So you have to call
8620
 * GetMaskBand() again.
8621
 *
8622
 * This method is the same as the C function GDALCreateMaskBand().
8623
 *
8624
 * @since GDAL 1.5.0
8625
 *
8626
 * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8627
 *
8628
 * @return CE_None on success or CE_Failure on an error.
8629
 *
8630
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8631
 * @see GDALDataset::CreateMaskBand()
8632
 *
8633
 */
8634
8635
CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8636
8637
0
{
8638
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8639
0
    {
8640
0
        const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8641
0
        if (eErr != CE_None)
8642
0
            return eErr;
8643
8644
0
        InvalidateMaskBand();
8645
8646
0
        return CE_None;
8647
0
    }
8648
8649
0
    ReportError(CE_Failure, CPLE_NotSupported,
8650
0
                "CreateMaskBand() not supported for this band.");
8651
8652
0
    return CE_Failure;
8653
0
}
8654
8655
/************************************************************************/
8656
/*                         GDALCreateMaskBand()                         */
8657
/************************************************************************/
8658
8659
/**
8660
 * \brief Adds a mask band to the current band
8661
 *
8662
 * @see GDALRasterBand::CreateMaskBand()
8663
 */
8664
8665
CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8666
8667
0
{
8668
0
    VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8669
8670
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8671
0
    return poBand->CreateMaskBand(nFlags);
8672
0
}
8673
8674
/************************************************************************/
8675
/*                            IsMaskBand()                              */
8676
/************************************************************************/
8677
8678
/**
8679
 * \brief Returns whether a band is a mask band.
8680
 *
8681
 * Mask band must be understood in the broad term: it can be a per-dataset
8682
 * mask band, an alpha band, or an implicit mask band.
8683
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8684
 *
8685
 * This method is the same as the C function GDALIsMaskBand().
8686
 *
8687
 * @return true if the band is a mask band.
8688
 *
8689
 * @see GDALDataset::CreateMaskBand()
8690
 *
8691
 * @since GDAL 3.5.0
8692
 *
8693
 */
8694
8695
bool GDALRasterBand::IsMaskBand() const
8696
0
{
8697
    // The GeoTIFF driver, among others, override this method to
8698
    // also handle external .msk bands.
8699
0
    return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8700
0
           GCI_AlphaBand;
8701
0
}
8702
8703
/************************************************************************/
8704
/*                            GDALIsMaskBand()                          */
8705
/************************************************************************/
8706
8707
/**
8708
 * \brief Returns whether a band is a mask band.
8709
 *
8710
 * Mask band must be understood in the broad term: it can be a per-dataset
8711
 * mask band, an alpha band, or an implicit mask band.
8712
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8713
 *
8714
 * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8715
 *
8716
 * @return true if the band is a mask band.
8717
 *
8718
 * @see GDALRasterBand::IsMaskBand()
8719
 *
8720
 * @since GDAL 3.5.0
8721
 *
8722
 */
8723
8724
bool GDALIsMaskBand(GDALRasterBandH hBand)
8725
8726
0
{
8727
0
    VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8728
8729
0
    const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8730
0
    return poBand->IsMaskBand();
8731
0
}
8732
8733
/************************************************************************/
8734
/*                         GetMaskValueRange()                          */
8735
/************************************************************************/
8736
8737
/**
8738
 * \brief Returns the range of values that a mask band can take.
8739
 *
8740
 * @return the range of values that a mask band can take.
8741
 *
8742
 * @since GDAL 3.5.0
8743
 *
8744
 */
8745
8746
GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8747
0
{
8748
0
    return GMVR_UNKNOWN;
8749
0
}
8750
8751
/************************************************************************/
8752
/*                    GetIndexColorTranslationTo()                      */
8753
/************************************************************************/
8754
8755
/**
8756
 * \brief Compute translation table for color tables.
8757
 *
8758
 * When the raster band has a palette index, it may be useful to compute
8759
 * the "translation" of this palette to the palette of another band.
8760
 * The translation tries to do exact matching first, and then approximate
8761
 * matching if no exact matching is possible.
8762
 * This method returns a table such that table[i] = j where i is an index
8763
 * of the 'this' rasterband and j the corresponding index for the reference
8764
 * rasterband.
8765
 *
8766
 * This method is thought as internal to GDAL and is used for drivers
8767
 * like RPFTOC.
8768
 *
8769
 * The implementation only supports 1-byte palette rasterbands.
8770
 *
8771
 * @param poReferenceBand the raster band
8772
 * @param pTranslationTable an already allocated translation table (at least 256
8773
 * bytes), or NULL to let the method allocate it
8774
 * @param pApproximateMatching a pointer to a flag that is set if the matching
8775
 *                              is approximate. May be NULL.
8776
 *
8777
 * @return a translation table if the two bands are palette index and that they
8778
 * do not match or NULL in other cases. The table must be freed with CPLFree if
8779
 * NULL was passed for pTranslationTable.
8780
 */
8781
8782
unsigned char *
8783
GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8784
                                           unsigned char *pTranslationTable,
8785
                                           int *pApproximateMatching)
8786
0
{
8787
0
    if (poReferenceBand == nullptr)
8788
0
        return nullptr;
8789
8790
    // cppcheck-suppress knownConditionTrueFalse
8791
0
    if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8792
        // cppcheck-suppress knownConditionTrueFalse
8793
0
        GetColorInterpretation() == GCI_PaletteIndex &&
8794
0
        poReferenceBand->GetRasterDataType() == GDT_Byte &&
8795
0
        GetRasterDataType() == GDT_Byte)
8796
0
    {
8797
0
        const GDALColorTable *srcColorTable = GetColorTable();
8798
0
        GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8799
0
        if (srcColorTable != nullptr && destColorTable != nullptr)
8800
0
        {
8801
0
            const int nEntries = srcColorTable->GetColorEntryCount();
8802
0
            const int nRefEntries = destColorTable->GetColorEntryCount();
8803
8804
0
            int bHasNoDataValueSrc = FALSE;
8805
0
            double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8806
0
            if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8807
0
                  dfNoDataValueSrc <= 255 &&
8808
0
                  dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8809
0
                bHasNoDataValueSrc = FALSE;
8810
0
            const int noDataValueSrc =
8811
0
                bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8812
8813
0
            int bHasNoDataValueRef = FALSE;
8814
0
            const double dfNoDataValueRef =
8815
0
                poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8816
0
            if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8817
0
                  dfNoDataValueRef <= 255 &&
8818
0
                  dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8819
0
                bHasNoDataValueRef = FALSE;
8820
0
            const int noDataValueRef =
8821
0
                bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8822
8823
0
            bool samePalette = false;
8824
8825
0
            if (pApproximateMatching)
8826
0
                *pApproximateMatching = FALSE;
8827
8828
0
            if (nEntries == nRefEntries &&
8829
0
                bHasNoDataValueSrc == bHasNoDataValueRef &&
8830
0
                (bHasNoDataValueSrc == FALSE ||
8831
0
                 noDataValueSrc == noDataValueRef))
8832
0
            {
8833
0
                samePalette = true;
8834
0
                for (int i = 0; i < nEntries; ++i)
8835
0
                {
8836
0
                    if (noDataValueSrc == i)
8837
0
                        continue;
8838
0
                    const GDALColorEntry *entry =
8839
0
                        srcColorTable->GetColorEntry(i);
8840
0
                    const GDALColorEntry *entryRef =
8841
0
                        destColorTable->GetColorEntry(i);
8842
0
                    if (entry->c1 != entryRef->c1 ||
8843
0
                        entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8844
0
                    {
8845
0
                        samePalette = false;
8846
0
                    }
8847
0
                }
8848
0
            }
8849
8850
0
            if (!samePalette)
8851
0
            {
8852
0
                if (pTranslationTable == nullptr)
8853
0
                {
8854
0
                    pTranslationTable = static_cast<unsigned char *>(
8855
0
                        VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8856
0
                    if (pTranslationTable == nullptr)
8857
0
                        return nullptr;
8858
0
                }
8859
8860
                // Trying to remap the product palette on the subdataset
8861
                // palette.
8862
0
                for (int i = 0; i < nEntries; ++i)
8863
0
                {
8864
0
                    if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8865
0
                        noDataValueSrc == i)
8866
0
                        continue;
8867
0
                    const GDALColorEntry *entry =
8868
0
                        srcColorTable->GetColorEntry(i);
8869
0
                    bool bMatchFound = false;
8870
0
                    for (int j = 0; j < nRefEntries; ++j)
8871
0
                    {
8872
0
                        if (bHasNoDataValueRef && noDataValueRef == j)
8873
0
                            continue;
8874
0
                        const GDALColorEntry *entryRef =
8875
0
                            destColorTable->GetColorEntry(j);
8876
0
                        if (entry->c1 == entryRef->c1 &&
8877
0
                            entry->c2 == entryRef->c2 &&
8878
0
                            entry->c3 == entryRef->c3)
8879
0
                        {
8880
0
                            pTranslationTable[i] =
8881
0
                                static_cast<unsigned char>(j);
8882
0
                            bMatchFound = true;
8883
0
                            break;
8884
0
                        }
8885
0
                    }
8886
0
                    if (!bMatchFound)
8887
0
                    {
8888
                        // No exact match. Looking for closest color now.
8889
0
                        int best_j = 0;
8890
0
                        int best_distance = 0;
8891
0
                        if (pApproximateMatching)
8892
0
                            *pApproximateMatching = TRUE;
8893
0
                        for (int j = 0; j < nRefEntries; ++j)
8894
0
                        {
8895
0
                            const GDALColorEntry *entryRef =
8896
0
                                destColorTable->GetColorEntry(j);
8897
0
                            int distance = (entry->c1 - entryRef->c1) *
8898
0
                                               (entry->c1 - entryRef->c1) +
8899
0
                                           (entry->c2 - entryRef->c2) *
8900
0
                                               (entry->c2 - entryRef->c2) +
8901
0
                                           (entry->c3 - entryRef->c3) *
8902
0
                                               (entry->c3 - entryRef->c3);
8903
0
                            if (j == 0 || distance < best_distance)
8904
0
                            {
8905
0
                                best_j = j;
8906
0
                                best_distance = distance;
8907
0
                            }
8908
0
                        }
8909
0
                        pTranslationTable[i] =
8910
0
                            static_cast<unsigned char>(best_j);
8911
0
                    }
8912
0
                }
8913
0
                if (bHasNoDataValueRef && bHasNoDataValueSrc)
8914
0
                    pTranslationTable[noDataValueSrc] =
8915
0
                        static_cast<unsigned char>(noDataValueRef);
8916
8917
0
                return pTranslationTable;
8918
0
            }
8919
0
        }
8920
0
    }
8921
0
    return nullptr;
8922
0
}
8923
8924
/************************************************************************/
8925
/*                         SetFlushBlockErr()                           */
8926
/************************************************************************/
8927
8928
/**
8929
 * \brief Store that an error occurred while writing a dirty block.
8930
 *
8931
 * This function stores the fact that an error occurred while writing a dirty
8932
 * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8933
 * flushed when the block cache get full, it is not convenient/possible to
8934
 * report that a dirty block could not be written correctly. This function
8935
 * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8936
 * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8937
 * places where the user can easily match the error with the relevant dataset.
8938
 */
8939
8940
void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8941
0
{
8942
0
    eFlushBlockErr = eErr;
8943
0
}
8944
8945
/************************************************************************/
8946
/*                         IncDirtyBlocks()                             */
8947
/************************************************************************/
8948
8949
/**
8950
 * \brief Increment/decrement the number of dirty blocks
8951
 */
8952
8953
void GDALRasterBand::IncDirtyBlocks(int nInc)
8954
0
{
8955
0
    if (poBandBlockCache)
8956
0
        poBandBlockCache->IncDirtyBlocks(nInc);
8957
0
}
8958
8959
/************************************************************************/
8960
/*                            ReportError()                             */
8961
/************************************************************************/
8962
8963
#ifndef DOXYGEN_XML
8964
/**
8965
 * \brief Emits an error related to a raster band.
8966
 *
8967
 * This function is a wrapper for regular CPLError(). The only difference
8968
 * with CPLError() is that it prepends the error message with the dataset
8969
 * name and the band number.
8970
 *
8971
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
8972
 * @param err_no the error number (CPLE_*) from cpl_error.h.
8973
 * @param fmt a printf() style format string.  Any additional arguments
8974
 * will be treated as arguments to fill in this format in a manner
8975
 * similar to printf().
8976
 *
8977
 * @since GDAL 1.9.0
8978
 */
8979
8980
void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
8981
                                 const char *fmt, ...) const
8982
0
{
8983
0
    va_list args;
8984
8985
0
    va_start(args, fmt);
8986
8987
0
    const char *pszDSName = poDS ? poDS->GetDescription() : "";
8988
0
    pszDSName = CPLGetFilename(pszDSName);
8989
0
    if (pszDSName[0] != '\0')
8990
0
    {
8991
0
        CPLError(eErrClass, err_no, "%s",
8992
0
                 CPLString()
8993
0
                     .Printf("%s, band %d: ", pszDSName, GetBand())
8994
0
                     .append(CPLString().vPrintf(fmt, args))
8995
0
                     .c_str());
8996
0
    }
8997
0
    else
8998
0
    {
8999
0
        CPLErrorV(eErrClass, err_no, fmt, args);
9000
0
    }
9001
9002
0
    va_end(args);
9003
0
}
9004
#endif
9005
9006
/************************************************************************/
9007
/*                           GetVirtualMemAuto()                        */
9008
/************************************************************************/
9009
9010
/** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9011
 *
9012
 * Only supported on Linux and Unix systems with mmap() for now.
9013
 *
9014
 * This method allows creating a virtual memory object for a GDALRasterBand,
9015
 * that exposes the whole image data as a virtual array.
9016
 *
9017
 * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9018
 * specialized implementation, such as for raw files, may also directly use
9019
 * mechanisms of the operating system to create a view of the underlying file
9020
 * into virtual memory ( CPLVirtualMemFileMapNew() )
9021
 *
9022
 * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9023
 * offer a specialized implementation with direct file mapping, provided that
9024
 * some requirements are met :
9025
 *   - for all drivers, the dataset must be backed by a "real" file in the file
9026
 *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9027
 *     must match the native ordering of the CPU.
9028
 *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9029
 * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9030
 * the file in sequential order, and be equally spaced (which is generally the
9031
 * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9032
 * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9033
 *
9034
 * The pointer returned remains valid until CPLVirtualMemFree() is called.
9035
 * CPLVirtualMemFree() must be called before the raster band object is
9036
 * destroyed.
9037
 *
9038
 * If p is such a pointer and base_type the type matching
9039
 * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9040
 * accessed with
9041
 * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9042
 *
9043
 * This method is the same as the C GDALGetVirtualMemAuto() function.
9044
 *
9045
 * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9046
 * read/write the band.
9047
 *
9048
 * @param pnPixelSpace Output parameter giving the byte offset from the start of
9049
 * one pixel value in the buffer to the start of the next pixel value within a
9050
 * scanline.
9051
 *
9052
 * @param pnLineSpace Output parameter giving the byte offset from the start of
9053
 * one scanline in the buffer to the start of the next.
9054
 *
9055
 * @param papszOptions NULL terminated list of options.
9056
 *                     If a specialized implementation exists, defining
9057
 * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9058
 * used. On the contrary, starting with GDAL 2.2, defining
9059
 * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9060
 * being used (thus only allowing efficient implementations to be used). When
9061
 * requiring or falling back to the default implementation, the following
9062
 *                     options are available : CACHE_SIZE (in bytes, defaults to
9063
 * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9064
 * to FALSE)
9065
 *
9066
 * @return a virtual memory object that must be unreferenced by
9067
 * CPLVirtualMemFree(), or NULL in case of failure.
9068
 *
9069
 * @since GDAL 1.11
9070
 */
9071
9072
CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9073
                                                 int *pnPixelSpace,
9074
                                                 GIntBig *pnLineSpace,
9075
                                                 char **papszOptions)
9076
0
{
9077
0
    const char *pszImpl = CSLFetchNameValueDef(
9078
0
        papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9079
0
    if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9080
0
        EQUAL(pszImpl, "FALSE"))
9081
0
    {
9082
0
        return nullptr;
9083
0
    }
9084
9085
0
    const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9086
0
    const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9087
0
    if (pnPixelSpace)
9088
0
        *pnPixelSpace = nPixelSpace;
9089
0
    if (pnLineSpace)
9090
0
        *pnLineSpace = nLineSpace;
9091
0
    const size_t nCacheSize =
9092
0
        atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9093
0
    const size_t nPageSizeHint =
9094
0
        atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9095
0
    const bool bSingleThreadUsage = CPLTestBool(
9096
0
        CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9097
0
    return GDALRasterBandGetVirtualMem(
9098
0
        GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9099
0
        nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9100
0
        nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9101
0
        papszOptions);
9102
0
}
9103
9104
/************************************************************************/
9105
/*                         GDALGetVirtualMemAuto()                      */
9106
/************************************************************************/
9107
9108
/**
9109
 * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9110
 *
9111
 * @see GDALRasterBand::GetVirtualMemAuto()
9112
 */
9113
9114
CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9115
                                     int *pnPixelSpace, GIntBig *pnLineSpace,
9116
                                     CSLConstList papszOptions)
9117
0
{
9118
0
    VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9119
9120
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9121
9122
0
    return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9123
0
                                     const_cast<char **>(papszOptions));
9124
0
}
9125
9126
/************************************************************************/
9127
/*                        GDALGetDataCoverageStatus()                   */
9128
/************************************************************************/
9129
9130
/**
9131
 * \brief Get the coverage status of a sub-window of the raster.
9132
 *
9133
 * Returns whether a sub-window of the raster contains only data, only empty
9134
 * blocks or a mix of both. This function can be used to determine quickly
9135
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9136
 * be sparse.
9137
 *
9138
 * Empty blocks are blocks that are generally not physically present in the
9139
 * file, and when read through GDAL, contain only pixels whose value is the
9140
 * nodata value when it is set, or whose value is 0 when the nodata value is
9141
 * not set.
9142
 *
9143
 * The query is done in an efficient way without reading the actual pixel
9144
 * values. If not possible, or not implemented at all by the driver,
9145
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9146
 * be returned.
9147
 *
9148
 * The values that can be returned by the function are the following,
9149
 * potentially combined with the binary or operator :
9150
 * <ul>
9151
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9152
 * GetDataCoverageStatus(). This flag should be returned together with
9153
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9154
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9155
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9156
 * the queried window. This is typically identified by the concept of missing
9157
 * block in formats that supports it.
9158
 * </li>
9159
 * </ul>
9160
 *
9161
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9162
 * should be interpreted more as hint of potential presence of data. For example
9163
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9164
 * nodata value), instead of using the missing block mechanism,
9165
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9166
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9167
 *
9168
 * The nMaskFlagStop should be generally set to 0. It can be set to a
9169
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9170
 * the function as soon as the computed mask matches the nMaskFlagStop. For
9171
 * example, you can issue a request on the whole raster with nMaskFlagStop =
9172
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9173
 * the function will exit, so that you can potentially refine the requested area
9174
 * to find which particular region(s) have missing blocks.
9175
 *
9176
 * @see GDALRasterBand::GetDataCoverageStatus()
9177
 *
9178
 * @param hBand raster band
9179
 *
9180
 * @param nXOff The pixel offset to the top left corner of the region
9181
 * of the band to be queried. This would be zero to start from the left side.
9182
 *
9183
 * @param nYOff The line offset to the top left corner of the region
9184
 * of the band to be queried. This would be zero to start from the top.
9185
 *
9186
 * @param nXSize The width of the region of the band to be queried in pixels.
9187
 *
9188
 * @param nYSize The height of the region of the band to be queried in lines.
9189
 *
9190
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9191
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9192
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9193
 * as the computation of the coverage matches the mask, the computation will be
9194
 * stopped. *pdfDataPct will not be valid in that case.
9195
 *
9196
 * @param pdfDataPct Optional output parameter whose pointed value will be set
9197
 * to the (approximate) percentage in [0,100] of pixels in the queried
9198
 * sub-window that have valid values. The implementation might not always be
9199
 * able to compute it, in which case it will be set to a negative value.
9200
 *
9201
 * @return a binary-or'ed combination of possible values
9202
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9203
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9204
 *
9205
 * @note Added in GDAL 2.2
9206
 */
9207
9208
int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
9209
                                          int nYOff, int nXSize, int nYSize,
9210
                                          int nMaskFlagStop, double *pdfDataPct)
9211
0
{
9212
0
    VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
9213
0
                      GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
9214
9215
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9216
9217
0
    return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
9218
0
                                         nMaskFlagStop, pdfDataPct);
9219
0
}
9220
9221
/************************************************************************/
9222
/*                          GetDataCoverageStatus()                     */
9223
/************************************************************************/
9224
9225
/**
9226
 * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
9227
 *                                           int nYOff,
9228
 *                                           int nXSize,
9229
 *                                           int nYSize,
9230
 *                                           int nMaskFlagStop,
9231
 *                                           double* pdfDataPct)
9232
 * \brief Get the coverage status of a sub-window of the raster.
9233
 *
9234
 * Returns whether a sub-window of the raster contains only data, only empty
9235
 * blocks or a mix of both. This function can be used to determine quickly
9236
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9237
 * be sparse.
9238
 *
9239
 * Empty blocks are blocks that contain only pixels whose value is the nodata
9240
 * value when it is set, or whose value is 0 when the nodata value is not set.
9241
 *
9242
 * The query is done in an efficient way without reading the actual pixel
9243
 * values. If not possible, or not implemented at all by the driver,
9244
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9245
 * be returned.
9246
 *
9247
 * The values that can be returned by the function are the following,
9248
 * potentially combined with the binary or operator :
9249
 * <ul>
9250
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9251
 * GetDataCoverageStatus(). This flag should be returned together with
9252
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9253
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9254
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9255
 * the queried window. This is typically identified by the concept of missing
9256
 * block in formats that supports it.
9257
 * </li>
9258
 * </ul>
9259
 *
9260
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9261
 * should be interpreted more as hint of potential presence of data. For example
9262
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9263
 * nodata value), instead of using the missing block mechanism,
9264
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9265
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9266
 *
9267
 * The nMaskFlagStop should be generally set to 0. It can be set to a
9268
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9269
 * the function as soon as the computed mask matches the nMaskFlagStop. For
9270
 * example, you can issue a request on the whole raster with nMaskFlagStop =
9271
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9272
 * the function will exit, so that you can potentially refine the requested area
9273
 * to find which particular region(s) have missing blocks.
9274
 *
9275
 * @see GDALGetDataCoverageStatus()
9276
 *
9277
 * @param nXOff The pixel offset to the top left corner of the region
9278
 * of the band to be queried. This would be zero to start from the left side.
9279
 *
9280
 * @param nYOff The line offset to the top left corner of the region
9281
 * of the band to be queried. This would be zero to start from the top.
9282
 *
9283
 * @param nXSize The width of the region of the band to be queried in pixels.
9284
 *
9285
 * @param nYSize The height of the region of the band to be queried in lines.
9286
 *
9287
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9288
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9289
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9290
 * as the computation of the coverage matches the mask, the computation will be
9291
 * stopped. *pdfDataPct will not be valid in that case.
9292
 *
9293
 * @param pdfDataPct Optional output parameter whose pointed value will be set
9294
 * to the (approximate) percentage in [0,100] of pixels in the queried
9295
 * sub-window that have valid values. The implementation might not always be
9296
 * able to compute it, in which case it will be set to a negative value.
9297
 *
9298
 * @return a binary-or'ed combination of possible values
9299
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9300
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9301
 *
9302
 * @note Added in GDAL 2.2
9303
 */
9304
9305
/**
9306
 * \brief Get the coverage status of a sub-window of the raster.
9307
 *
9308
 * Returns whether a sub-window of the raster contains only data, only empty
9309
 * blocks or a mix of both. This function can be used to determine quickly
9310
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9311
 * be sparse.
9312
 *
9313
 * Empty blocks are blocks that contain only pixels whose value is the nodata
9314
 * value when it is set, or whose value is 0 when the nodata value is not set.
9315
 *
9316
 * The query is done in an efficient way without reading the actual pixel
9317
 * values. If not possible, or not implemented at all by the driver,
9318
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9319
 * be returned.
9320
 *
9321
 * The values that can be returned by the function are the following,
9322
 * potentially combined with the binary or operator :
9323
 * <ul>
9324
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9325
 * GetDataCoverageStatus(). This flag should be returned together with
9326
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9327
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9328
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9329
 * the queried window. This is typically identified by the concept of missing
9330
 * block in formats that supports it.
9331
 * </li>
9332
 * </ul>
9333
 *
9334
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9335
 * should be interpreted more as hint of potential presence of data. For example
9336
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9337
 * nodata value), instead of using the missing block mechanism,
9338
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9339
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9340
 *
9341
 * The nMaskFlagStop should be generally set to 0. It can be set to a
9342
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9343
 * the function as soon as the computed mask matches the nMaskFlagStop. For
9344
 * example, you can issue a request on the whole raster with nMaskFlagStop =
9345
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9346
 * the function will exit, so that you can potentially refine the requested area
9347
 * to find which particular region(s) have missing blocks.
9348
 *
9349
 * @see GDALGetDataCoverageStatus()
9350
 *
9351
 * @param nXOff The pixel offset to the top left corner of the region
9352
 * of the band to be queried. This would be zero to start from the left side.
9353
 *
9354
 * @param nYOff The line offset to the top left corner of the region
9355
 * of the band to be queried. This would be zero to start from the top.
9356
 *
9357
 * @param nXSize The width of the region of the band to be queried in pixels.
9358
 *
9359
 * @param nYSize The height of the region of the band to be queried in lines.
9360
 *
9361
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9362
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9363
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9364
 * as the computation of the coverage matches the mask, the computation will be
9365
 * stopped. *pdfDataPct will not be valid in that case.
9366
 *
9367
 * @param pdfDataPct Optional output parameter whose pointed value will be set
9368
 * to the (approximate) percentage in [0,100] of pixels in the queried
9369
 * sub-window that have valid values. The implementation might not always be
9370
 * able to compute it, in which case it will be set to a negative value.
9371
 *
9372
 * @return a binary-or'ed combination of possible values
9373
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9374
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9375
 *
9376
 * @note Added in GDAL 2.2
9377
 */
9378
9379
int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9380
                                          int nYSize, int nMaskFlagStop,
9381
                                          double *pdfDataPct)
9382
0
{
9383
0
    if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9384
0
        nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9385
0
        nYOff + nYSize > nRasterYSize)
9386
0
    {
9387
0
        CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9388
0
        if (pdfDataPct)
9389
0
            *pdfDataPct = 0.0;
9390
0
        return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9391
0
               GDAL_DATA_COVERAGE_STATUS_EMPTY;
9392
0
    }
9393
0
    return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9394
0
                                  pdfDataPct);
9395
0
}
9396
9397
/************************************************************************/
9398
/*                         IGetDataCoverageStatus()                     */
9399
/************************************************************************/
9400
9401
int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9402
                                           int /*nXSize*/, int /*nYSize*/,
9403
                                           int /*nMaskFlagStop*/,
9404
                                           double *pdfDataPct)
9405
0
{
9406
0
    if (pdfDataPct != nullptr)
9407
0
        *pdfDataPct = 100.0;
9408
0
    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9409
0
           GDAL_DATA_COVERAGE_STATUS_DATA;
9410
0
}
9411
9412
//! @cond Doxygen_Suppress
9413
/************************************************************************/
9414
/*                          EnterReadWrite()                            */
9415
/************************************************************************/
9416
9417
int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9418
0
{
9419
0
    if (poDS != nullptr)
9420
0
        return poDS->EnterReadWrite(eRWFlag);
9421
0
    return FALSE;
9422
0
}
9423
9424
/************************************************************************/
9425
/*                         LeaveReadWrite()                             */
9426
/************************************************************************/
9427
9428
void GDALRasterBand::LeaveReadWrite()
9429
0
{
9430
0
    if (poDS != nullptr)
9431
0
        poDS->LeaveReadWrite();
9432
0
}
9433
9434
/************************************************************************/
9435
/*                           InitRWLock()                               */
9436
/************************************************************************/
9437
9438
void GDALRasterBand::InitRWLock()
9439
0
{
9440
0
    if (poDS != nullptr)
9441
0
        poDS->InitRWLock();
9442
0
}
9443
9444
//! @endcond
9445
9446
// clang-format off
9447
9448
/**
9449
 * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9450
 * \brief Set metadata.
9451
 *
9452
 * CAUTION: depending on the format, older values of the updated information
9453
 * might still be found in the file in a "ghost" state, even if no longer
9454
 * accessible through the GDAL API. This is for example the case of the GTiff
9455
 * format (this is not a exhaustive list)
9456
 *
9457
 * The C function GDALSetMetadata() does the same thing as this method.
9458
 *
9459
 * @param papszMetadata the metadata in name=value string list format to
9460
 * apply.
9461
 * @param pszDomain the domain of interest.  Use "" or NULL for the default
9462
 * domain.
9463
 * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9464
 * metadata has been accepted, but is likely not maintained persistently
9465
 * by the underlying object between sessions.
9466
 */
9467
9468
/**
9469
 * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9470
 * \brief Set single metadata item.
9471
 *
9472
 * CAUTION: depending on the format, older values of the updated information
9473
 * might still be found in the file in a "ghost" state, even if no longer
9474
 * accessible through the GDAL API. This is for example the case of the GTiff
9475
 * format (this is not a exhaustive list)
9476
 *
9477
 * The C function GDALSetMetadataItem() does the same thing as this method.
9478
 *
9479
 * @param pszName the key for the metadata item to fetch.
9480
 * @param pszValue the value to assign to the key.
9481
 * @param pszDomain the domain to set within, use NULL for the default domain.
9482
 *
9483
 * @return CE_None on success, or an error code on failure.
9484
 */
9485
9486
// clang-format on
9487
9488
//! @cond Doxygen_Suppress
9489
/************************************************************************/
9490
/*                    EnablePixelTypeSignedByteWarning()                */
9491
/************************************************************************/
9492
9493
void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9494
0
{
9495
0
    m_bEnablePixelTypeSignedByteWarning = b;
9496
0
}
9497
9498
void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9499
0
{
9500
0
    GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9501
0
}
9502
9503
//! @endcond
9504
9505
/************************************************************************/
9506
/*                           GetMetadataItem()                          */
9507
/************************************************************************/
9508
9509
const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9510
                                            const char *pszDomain)
9511
0
{
9512
    // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9513
0
    if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9514
0
        pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9515
0
        EQUAL(pszName, "PIXELTYPE"))
9516
0
    {
9517
0
        CPLError(CE_Warning, CPLE_AppDefined,
9518
0
                 "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9519
0
                 "used to signal signed 8-bit raster. Change your code to "
9520
0
                 "test for the new GDT_Int8 data type instead.");
9521
0
    }
9522
0
    return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9523
0
}
9524
9525
/************************************************************************/
9526
/*                     GDALMDArrayFromRasterBand                        */
9527
/************************************************************************/
9528
9529
class GDALMDArrayFromRasterBand final : public GDALMDArray
9530
{
9531
    CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9532
9533
    GDALDataset *m_poDS;
9534
    GDALRasterBand *m_poBand;
9535
    GDALExtendedDataType m_dt;
9536
    std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9537
    std::string m_osUnit;
9538
    std::vector<GByte> m_pabyNoData{};
9539
    std::shared_ptr<GDALMDArray> m_varX{};
9540
    std::shared_ptr<GDALMDArray> m_varY{};
9541
    std::string m_osFilename{};
9542
9543
    bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9544
                   const size_t *count, const GInt64 *arrayStep,
9545
                   const GPtrDiff_t *bufferStride,
9546
                   const GDALExtendedDataType &bufferDataType,
9547
                   void *pBuffer) const;
9548
9549
  protected:
9550
    GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9551
0
        : GDALAbstractMDArray(std::string(),
9552
0
                              std::string(poDS->GetDescription()) +
9553
0
                                  CPLSPrintf(" band %d", poBand->GetBand())),
9554
0
          GDALMDArray(std::string(),
9555
0
                      std::string(poDS->GetDescription()) +
9556
0
                          CPLSPrintf(" band %d", poBand->GetBand())),
9557
0
          m_poDS(poDS), m_poBand(poBand),
9558
0
          m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9559
0
          m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9560
0
    {
9561
0
        m_poDS->Reference();
9562
9563
0
        int bHasNoData = false;
9564
0
        if (m_poBand->GetRasterDataType() == GDT_Int64)
9565
0
        {
9566
0
            const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9567
0
            if (bHasNoData)
9568
0
            {
9569
0
                m_pabyNoData.resize(m_dt.GetSize());
9570
0
                GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9571
0
                                m_dt.GetNumericDataType(), 0, 1);
9572
0
            }
9573
0
        }
9574
0
        else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9575
0
        {
9576
0
            const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9577
0
            if (bHasNoData)
9578
0
            {
9579
0
                m_pabyNoData.resize(m_dt.GetSize());
9580
0
                GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9581
0
                                m_dt.GetNumericDataType(), 0, 1);
9582
0
            }
9583
0
        }
9584
0
        else
9585
0
        {
9586
0
            const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9587
0
            if (bHasNoData)
9588
0
            {
9589
0
                m_pabyNoData.resize(m_dt.GetSize());
9590
0
                GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9591
0
                                m_dt.GetNumericDataType(), 0, 1);
9592
0
            }
9593
0
        }
9594
9595
0
        const int nXSize = poBand->GetXSize();
9596
0
        const int nYSize = poBand->GetYSize();
9597
9598
0
        auto poSRS = m_poDS->GetSpatialRef();
9599
0
        std::string osTypeY;
9600
0
        std::string osTypeX;
9601
0
        std::string osDirectionY;
9602
0
        std::string osDirectionX;
9603
0
        if (poSRS && poSRS->GetAxesCount() == 2)
9604
0
        {
9605
0
            const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9606
0
            OGRAxisOrientation eOrientation1 = OAO_Other;
9607
0
            poSRS->GetAxis(nullptr, 0, &eOrientation1);
9608
0
            OGRAxisOrientation eOrientation2 = OAO_Other;
9609
0
            poSRS->GetAxis(nullptr, 1, &eOrientation2);
9610
0
            if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9611
0
            {
9612
0
                if (mapping == std::vector<int>{1, 2})
9613
0
                {
9614
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9615
0
                    osDirectionY = "NORTH";
9616
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9617
0
                    osDirectionX = "EAST";
9618
0
                }
9619
0
            }
9620
0
            else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9621
0
            {
9622
0
                if (mapping == std::vector<int>{2, 1})
9623
0
                {
9624
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9625
0
                    osDirectionY = "NORTH";
9626
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9627
0
                    osDirectionX = "EAST";
9628
0
                }
9629
0
            }
9630
0
        }
9631
9632
0
        m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9633
0
                      "/", "Y", osTypeY, osDirectionY, nYSize),
9634
0
                  std::make_shared<GDALDimensionWeakIndexingVar>(
9635
0
                      "/", "X", osTypeX, osDirectionX, nXSize)};
9636
9637
0
        double adfGeoTransform[6];
9638
0
        if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
9639
0
            adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
9640
0
        {
9641
0
            m_varX = GDALMDArrayRegularlySpaced::Create(
9642
0
                "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
9643
0
                0.5);
9644
0
            m_dims[1]->SetIndexingVariable(m_varX);
9645
9646
0
            m_varY = GDALMDArrayRegularlySpaced::Create(
9647
0
                "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
9648
0
                0.5);
9649
0
            m_dims[0]->SetIndexingVariable(m_varY);
9650
0
        }
9651
0
    }
9652
9653
    bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9654
               const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9655
               const GDALExtendedDataType &bufferDataType,
9656
               void *pDstBuffer) const override;
9657
9658
    bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9659
                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9660
                const GDALExtendedDataType &bufferDataType,
9661
                const void *pSrcBuffer) override
9662
0
    {
9663
0
        return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9664
0
                         bufferStride, bufferDataType,
9665
0
                         const_cast<void *>(pSrcBuffer));
9666
0
    }
9667
9668
  public:
9669
    ~GDALMDArrayFromRasterBand()
9670
0
    {
9671
0
        m_poDS->ReleaseRef();
9672
0
    }
9673
9674
    static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9675
                                               GDALRasterBand *poBand)
9676
0
    {
9677
0
        auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9678
0
            new GDALMDArrayFromRasterBand(poDS, poBand)));
9679
0
        array->SetSelf(array);
9680
0
        return array;
9681
0
    }
9682
9683
    bool IsWritable() const override
9684
0
    {
9685
0
        return m_poDS->GetAccess() == GA_Update;
9686
0
    }
9687
9688
    const std::string &GetFilename() const override
9689
0
    {
9690
0
        return m_osFilename;
9691
0
    }
9692
9693
    const std::vector<std::shared_ptr<GDALDimension>> &
9694
    GetDimensions() const override
9695
0
    {
9696
0
        return m_dims;
9697
0
    }
9698
9699
    const GDALExtendedDataType &GetDataType() const override
9700
0
    {
9701
0
        return m_dt;
9702
0
    }
9703
9704
    const std::string &GetUnit() const override
9705
0
    {
9706
0
        return m_osUnit;
9707
0
    }
9708
9709
    const void *GetRawNoDataValue() const override
9710
0
    {
9711
0
        return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9712
0
    }
9713
9714
    double GetOffset(bool *pbHasOffset,
9715
                     GDALDataType *peStorageType) const override
9716
0
    {
9717
0
        int bHasOffset = false;
9718
0
        double dfRes = m_poBand->GetOffset(&bHasOffset);
9719
0
        if (pbHasOffset)
9720
0
            *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9721
0
        if (peStorageType)
9722
0
            *peStorageType = GDT_Unknown;
9723
0
        return dfRes;
9724
0
    }
9725
9726
    double GetScale(bool *pbHasScale,
9727
                    GDALDataType *peStorageType) const override
9728
0
    {
9729
0
        int bHasScale = false;
9730
0
        double dfRes = m_poBand->GetScale(&bHasScale);
9731
0
        if (pbHasScale)
9732
0
            *pbHasScale = CPL_TO_BOOL(bHasScale);
9733
0
        if (peStorageType)
9734
0
            *peStorageType = GDT_Unknown;
9735
0
        return dfRes;
9736
0
    }
9737
9738
    std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9739
0
    {
9740
0
        auto poSrcSRS = m_poDS->GetSpatialRef();
9741
0
        if (!poSrcSRS)
9742
0
            return nullptr;
9743
0
        auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9744
9745
0
        auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9746
0
        constexpr int iYDim = 0;
9747
0
        constexpr int iXDim = 1;
9748
0
        for (auto &m : axisMapping)
9749
0
        {
9750
0
            if (m == 1)
9751
0
                m = iXDim + 1;
9752
0
            else if (m == 2)
9753
0
                m = iYDim + 1;
9754
0
            else
9755
0
                m = 0;
9756
0
        }
9757
0
        poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9758
0
        return poSRS;
9759
0
    }
9760
9761
    std::vector<GUInt64> GetBlockSize() const override
9762
0
    {
9763
0
        int nBlockXSize = 0;
9764
0
        int nBlockYSize = 0;
9765
0
        m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9766
0
        return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9767
0
                                    static_cast<GUInt64>(nBlockXSize)};
9768
0
    }
9769
9770
    class MDIAsAttribute : public GDALAttribute
9771
    {
9772
        std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9773
        const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
9774
        std::string m_osValue;
9775
9776
      public:
9777
        MDIAsAttribute(const std::string &name, const std::string &value)
9778
0
            : GDALAbstractMDArray(std::string(), name),
9779
0
              GDALAttribute(std::string(), name), m_osValue(value)
9780
0
        {
9781
0
        }
9782
9783
        const std::vector<std::shared_ptr<GDALDimension>> &
9784
        GetDimensions() const override;
9785
9786
        const GDALExtendedDataType &GetDataType() const override
9787
0
        {
9788
0
            return m_dt;
9789
0
        }
9790
9791
        bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
9792
                   const GPtrDiff_t *,
9793
                   const GDALExtendedDataType &bufferDataType,
9794
                   void *pDstBuffer) const override
9795
0
        {
9796
0
            const char *pszStr = m_osValue.c_str();
9797
0
            GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
9798
0
                                            bufferDataType);
9799
0
            return true;
9800
0
        }
9801
    };
9802
9803
    std::vector<std::shared_ptr<GDALAttribute>>
9804
    GetAttributes(CSLConstList) const override
9805
0
    {
9806
0
        std::vector<std::shared_ptr<GDALAttribute>> res;
9807
0
        auto papszMD = m_poBand->GetMetadata();
9808
0
        for (auto iter = papszMD; iter && iter[0]; ++iter)
9809
0
        {
9810
0
            char *pszKey = nullptr;
9811
0
            const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9812
0
            if (pszKey && pszValue)
9813
0
            {
9814
0
                res.emplace_back(
9815
0
                    std::make_shared<MDIAsAttribute>(pszKey, pszValue));
9816
0
            }
9817
0
            CPLFree(pszKey);
9818
0
        }
9819
0
        return res;
9820
0
    }
9821
};
9822
9823
bool GDALMDArrayFromRasterBand::IRead(
9824
    const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
9825
    const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
9826
    void *pDstBuffer) const
9827
0
{
9828
0
    return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9829
0
                     bufferDataType, pDstBuffer);
9830
0
}
9831
9832
const std::vector<std::shared_ptr<GDALDimension>> &
9833
GDALMDArrayFromRasterBand::MDIAsAttribute::GetDimensions() const
9834
0
{
9835
0
    return m_dims;
9836
0
}
9837
9838
/************************************************************************/
9839
/*                            ReadWrite()                               */
9840
/************************************************************************/
9841
9842
bool GDALMDArrayFromRasterBand::ReadWrite(
9843
    GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
9844
    const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9845
    const GDALExtendedDataType &bufferDataType, void *pBuffer) const
9846
0
{
9847
0
    constexpr size_t iDimX = 1;
9848
0
    constexpr size_t iDimY = 0;
9849
0
    return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
9850
0
                                  arrayStartIdx, count, arrayStep, bufferStride,
9851
0
                                  bufferDataType, pBuffer);
9852
0
}
9853
9854
/************************************************************************/
9855
/*                       GDALMDRasterIOFromBand()                       */
9856
/************************************************************************/
9857
9858
bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
9859
                            size_t iDimX, size_t iDimY,
9860
                            const GUInt64 *arrayStartIdx, const size_t *count,
9861
                            const GInt64 *arrayStep,
9862
                            const GPtrDiff_t *bufferStride,
9863
                            const GDALExtendedDataType &bufferDataType,
9864
                            void *pBuffer)
9865
0
{
9866
0
    const auto eDT(bufferDataType.GetNumericDataType());
9867
0
    const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
9868
0
    const int nX =
9869
0
        arrayStep[iDimX] > 0
9870
0
            ? static_cast<int>(arrayStartIdx[iDimX])
9871
0
            : static_cast<int>(arrayStartIdx[iDimX] -
9872
0
                               (count[iDimX] - 1) * -arrayStep[iDimX]);
9873
0
    const int nY =
9874
0
        arrayStep[iDimY] > 0
9875
0
            ? static_cast<int>(arrayStartIdx[iDimY])
9876
0
            : static_cast<int>(arrayStartIdx[iDimY] -
9877
0
                               (count[iDimY] - 1) * -arrayStep[iDimY]);
9878
0
    const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
9879
0
    const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
9880
0
    GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
9881
0
    int nStrideXSign = 1;
9882
0
    if (arrayStep[iDimX] < 0)
9883
0
    {
9884
0
        pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
9885
0
        nStrideXSign = -1;
9886
0
    }
9887
0
    int nStrideYSign = 1;
9888
0
    if (arrayStep[iDimY] < 0)
9889
0
    {
9890
0
        pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
9891
0
        nStrideYSign = -1;
9892
0
    }
9893
9894
0
    return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
9895
0
                            static_cast<int>(count[iDimX]),
9896
0
                            static_cast<int>(count[iDimY]), eDT,
9897
0
                            static_cast<GSpacing>(
9898
0
                                nStrideXSign * bufferStride[iDimX] * nDTSize),
9899
0
                            static_cast<GSpacing>(
9900
0
                                nStrideYSign * bufferStride[iDimY] * nDTSize),
9901
0
                            nullptr) == CE_None;
9902
0
}
9903
9904
/************************************************************************/
9905
/*                            AsMDArray()                               */
9906
/************************************************************************/
9907
9908
/** Return a view of this raster band as a 2D multidimensional GDALMDArray.
9909
 *
9910
 * The band must be linked to a GDALDataset. If this dataset is not already
9911
 * marked as shared, it will be, so that the returned array holds a reference
9912
 * to it.
9913
 *
9914
 * If the dataset has a geotransform attached, the X and Y dimensions of the
9915
 * returned array will have an associated indexing variable.
9916
 *
9917
 * This is the same as the C function GDALRasterBandAsMDArray().
9918
 *
9919
 * The "reverse" method is GDALMDArray::AsClassicDataset().
9920
 *
9921
 * @return a new array, or nullptr.
9922
 *
9923
 * @since GDAL 3.1
9924
 */
9925
std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
9926
0
{
9927
0
    if (!poDS)
9928
0
    {
9929
0
        CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
9930
0
        return nullptr;
9931
0
    }
9932
0
    if (!poDS->GetShared())
9933
0
    {
9934
0
        poDS->MarkAsShared();
9935
0
    }
9936
0
    return GDALMDArrayFromRasterBand::Create(
9937
0
        poDS, const_cast<GDALRasterBand *>(this));
9938
0
}
9939
9940
/************************************************************************/
9941
/*                             InterpolateAtPoint()                     */
9942
/************************************************************************/
9943
9944
/**
9945
 * \brief Interpolates the value between pixels using a resampling algorithm,
9946
 * taking pixel/line coordinates as input.
9947
 *
9948
 * @param dfPixel pixel coordinate as a double, where interpolation should be done.
9949
 * @param dfLine line coordinate as a double, where interpolation should be done.
9950
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
9951
 * @param pdfRealValue pointer to real part of interpolated value
9952
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
9953
 *
9954
 * @return CE_None on success, or an error code on failure.
9955
 * @since GDAL 3.10
9956
 */
9957
9958
CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
9959
                                          GDALRIOResampleAlg eInterpolation,
9960
                                          double *pdfRealValue,
9961
                                          double *pdfImagValue) const
9962
0
{
9963
0
    if (eInterpolation != GRIORA_NearestNeighbour &&
9964
0
        eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
9965
0
        eInterpolation != GRIORA_CubicSpline)
9966
0
    {
9967
0
        CPLError(CE_Failure, CPLE_AppDefined,
9968
0
                 "Only nearest, bilinear, cubic and cubicspline interpolation "
9969
0
                 "methods "
9970
0
                 "allowed");
9971
9972
0
        return CE_Failure;
9973
0
    }
9974
9975
0
    GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
9976
0
    if (!m_poPointsCache)
9977
0
        m_poPointsCache = new GDALDoublePointsCache();
9978
9979
0
    const bool res =
9980
0
        GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
9981
0
                               dfPixel, dfLine, pdfRealValue, pdfImagValue);
9982
9983
0
    return res ? CE_None : CE_Failure;
9984
0
}
9985
9986
/************************************************************************/
9987
/*                        GDALRasterInterpolateAtPoint()                */
9988
/************************************************************************/
9989
9990
/**
9991
 * \brief Interpolates the value between pixels using
9992
 * a resampling algorithm
9993
 *
9994
 * @see GDALRasterBand::InterpolateAtPoint()
9995
 * @since GDAL 3.10
9996
 */
9997
9998
CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
9999
                                    double dfLine,
10000
                                    GDALRIOResampleAlg eInterpolation,
10001
                                    double *pdfRealValue, double *pdfImagValue)
10002
0
{
10003
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10004
10005
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10006
0
    return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10007
0
                                      pdfRealValue, pdfImagValue);
10008
0
}
10009
10010
/************************************************************************/
10011
/*                    InterpolateAtGeolocation()                        */
10012
/************************************************************************/
10013
10014
/**
10015
 * \brief Interpolates the value between pixels using a resampling algorithm,
10016
 * taking georeferenced coordinates as input.
10017
 *
10018
 * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
10019
 * must be in the "natural" SRS of the dataset, that is the one returned by
10020
 * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
10021
 * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
10022
 * array (generally WGS 84) if there is a geolocation array.
10023
 * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10024
 * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10025
 * be a easting, and dfGeolocY a northing.
10026
 *
10027
 * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10028
 * expressed in that CRS, and that tuple must be conformant with the
10029
 * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10030
 * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10031
 * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10032
 * before calling this method, and in that case, dfGeolocX must be a longitude
10033
 * or an easting value, and dfGeolocX a latitude or a northing value.
10034
 *
10035
 * The GDALDataset::GeolocationToPixelLine() will be used to transform from
10036
 * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
10037
 * it for details on how that transformation is done.
10038
 *
10039
 * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
10040
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10041
 * where interpolation should be done.
10042
 * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
10043
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10044
 * where interpolation should be done.
10045
 * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
10046
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10047
 * @param pdfRealValue pointer to real part of interpolated value
10048
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10049
 * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
10050
 *
10051
 * @return CE_None on success, or an error code on failure.
10052
 * @since GDAL 3.11
10053
 */
10054
10055
CPLErr GDALRasterBand::InterpolateAtGeolocation(
10056
    double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
10057
    GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
10058
    double *pdfImagValue, CSLConstList papszTransformerOptions) const
10059
0
{
10060
0
    double dfPixel;
10061
0
    double dfLine;
10062
0
    if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
10063
0
                                     &dfLine,
10064
0
                                     papszTransformerOptions) != CE_None)
10065
0
    {
10066
0
        return CE_Failure;
10067
0
    }
10068
0
    return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
10069
0
                              pdfImagValue);
10070
0
}
10071
10072
/************************************************************************/
10073
/*                  GDALRasterInterpolateAtGeolocation()                */
10074
/************************************************************************/
10075
10076
/**
10077
 * \brief Interpolates the value between pixels using a resampling algorithm,
10078
 * taking georeferenced coordinates as input.
10079
 *
10080
 * @see GDALRasterBand::InterpolateAtGeolocation()
10081
 * @since GDAL 3.11
10082
 */
10083
10084
CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
10085
                                          double dfGeolocX, double dfGeolocY,
10086
                                          OGRSpatialReferenceH hSRS,
10087
                                          GDALRIOResampleAlg eInterpolation,
10088
                                          double *pdfRealValue,
10089
                                          double *pdfImagValue,
10090
                                          CSLConstList papszTransformerOptions)
10091
0
{
10092
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
10093
10094
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10095
0
    return poBand->InterpolateAtGeolocation(
10096
0
        dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
10097
0
        eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
10098
0
}
10099
10100
/************************************************************************/
10101
/*                    GDALRasterBand::SplitRasterIO()                   */
10102
/************************************************************************/
10103
10104
//! @cond Doxygen_Suppress
10105
10106
/** Implements IRasterIO() by dividing the request in 2.
10107
 *
10108
 * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
10109
 *
10110
 * Return CE_Warning if the split could not be done, CE_None in case of
10111
 * success and CE_Failure in case of error.
10112
 *
10113
 * @since 3.12
10114
 */
10115
CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
10116
                                     [[maybe_unused]] int nXSize,
10117
                                     [[maybe_unused]] int nYSize, void *pData,
10118
                                     int nBufXSize, int nBufYSize,
10119
                                     GDALDataType eBufType,
10120
                                     GSpacing nPixelSpace, GSpacing nLineSpace,
10121
                                     GDALRasterIOExtraArg *psExtraArg)
10122
0
{
10123
0
    CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
10124
10125
0
    GByte *pabyData = static_cast<GByte *>(pData);
10126
0
    if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
10127
0
    {
10128
0
        GDALRasterIOExtraArg sArg;
10129
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
10130
0
        const int nHalfHeight = nBufYSize / 2;
10131
10132
0
        sArg.pfnProgress = GDALScaledProgress;
10133
0
        sArg.pProgressData = GDALCreateScaledProgress(
10134
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10135
0
        if (sArg.pProgressData == nullptr)
10136
0
            sArg.pfnProgress = nullptr;
10137
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
10138
0
                                pabyData, nBufXSize, nHalfHeight, eBufType,
10139
0
                                nPixelSpace, nLineSpace, &sArg);
10140
0
        GDALDestroyScaledProgress(sArg.pProgressData);
10141
10142
0
        if (eErr == CE_None)
10143
0
        {
10144
0
            sArg.pfnProgress = GDALScaledProgress;
10145
0
            sArg.pProgressData = GDALCreateScaledProgress(
10146
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10147
0
            if (sArg.pProgressData == nullptr)
10148
0
                sArg.pfnProgress = nullptr;
10149
0
            eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
10150
0
                             nBufYSize - nHalfHeight,
10151
0
                             pabyData + nHalfHeight * nLineSpace, nBufXSize,
10152
0
                             nBufYSize - nHalfHeight, eBufType, nPixelSpace,
10153
0
                             nLineSpace, &sArg);
10154
0
            GDALDestroyScaledProgress(sArg.pProgressData);
10155
0
        }
10156
0
        return eErr;
10157
0
    }
10158
0
    else if (nBufXSize >= 2)
10159
0
    {
10160
0
        GDALRasterIOExtraArg sArg;
10161
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
10162
0
        const int nHalfWidth = nBufXSize / 2;
10163
10164
0
        sArg.pfnProgress = GDALScaledProgress;
10165
0
        sArg.pProgressData = GDALCreateScaledProgress(
10166
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10167
0
        if (sArg.pProgressData == nullptr)
10168
0
            sArg.pfnProgress = nullptr;
10169
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
10170
0
                                pabyData, nHalfWidth, nBufYSize, eBufType,
10171
0
                                nPixelSpace, nLineSpace, &sArg);
10172
0
        GDALDestroyScaledProgress(sArg.pProgressData);
10173
10174
0
        if (eErr == CE_None)
10175
0
        {
10176
0
            sArg.pfnProgress = GDALScaledProgress;
10177
0
            sArg.pProgressData = GDALCreateScaledProgress(
10178
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10179
0
            if (sArg.pProgressData == nullptr)
10180
0
                sArg.pfnProgress = nullptr;
10181
0
            eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
10182
0
                             nBufXSize - nHalfWidth, nBufYSize,
10183
0
                             pabyData + nHalfWidth * nPixelSpace,
10184
0
                             nBufXSize - nHalfWidth, nBufYSize, eBufType,
10185
0
                             nPixelSpace, nLineSpace, &sArg);
10186
0
            GDALDestroyScaledProgress(sArg.pProgressData);
10187
0
        }
10188
0
        return eErr;
10189
0
    }
10190
10191
0
    return CE_Warning;
10192
0
}
10193
10194
//! @endcond