Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Base class for format specific band class implementation. This
5 : * base class provides default implementation for many methods.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1998, Frank Warmerdam
10 : * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "cpl_port.h"
32 : #include "gdal_priv.h"
33 :
34 : #include <climits>
35 : #include <cmath>
36 : #include <cstdarg>
37 : #include <cstddef>
38 : #include <cstdio>
39 : #include <cstdlib>
40 : #include <cstring>
41 : #include <algorithm>
42 : #include <limits>
43 : #include <memory>
44 : #include <new>
45 : #include <type_traits>
46 :
47 : #include "cpl_conv.h"
48 : #include "cpl_error.h"
49 : #include "cpl_progress.h"
50 : #include "cpl_string.h"
51 : #include "cpl_virtualmem.h"
52 : #include "cpl_vsi.h"
53 : #include "gdal.h"
54 : #include "gdal_rat.h"
55 : #include "gdal_priv_templates.hpp"
56 :
57 : /************************************************************************/
58 : /* GDALRasterBand() */
59 : /************************************************************************/
60 :
61 : /*! Constructor. Applications should never create GDALRasterBands directly. */
62 :
63 978459 : GDALRasterBand::GDALRasterBand()
64 : : GDALRasterBand(
65 978459 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
66 : {
67 978433 : }
68 :
69 : /** Constructor. Applications should never create GDALRasterBands directly.
70 : * @param bForceCachedIOIn Whether cached IO should be forced.
71 : */
72 1040890 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
73 1040890 : : bForceCachedIO(bForceCachedIOIn)
74 :
75 : {
76 1040850 : }
77 :
78 : /************************************************************************/
79 : /* ~GDALRasterBand() */
80 : /************************************************************************/
81 :
82 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
83 : instead destroy the GDALDataset. */
84 :
85 1040900 : GDALRasterBand::~GDALRasterBand()
86 :
87 : {
88 1040900 : if (poDS && poDS->IsMarkedSuppressOnClose())
89 : {
90 429 : if (poBandBlockCache)
91 380 : poBandBlockCache->DisableDirtyBlockWriting();
92 : }
93 1040900 : GDALRasterBand::FlushCache(true);
94 :
95 1040900 : delete poBandBlockCache;
96 :
97 1040900 : if (static_cast<GIntBig>(nBlockReads) >
98 1040900 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
99 190 : nBand == 1 && poDS != nullptr)
100 : {
101 278 : CPLDebug("GDAL", "%d block reads on %d block band 1 of %s.",
102 139 : nBlockReads, nBlocksPerRow * nBlocksPerColumn,
103 139 : poDS->GetDescription());
104 : }
105 :
106 1040900 : InvalidateMaskBand();
107 1040900 : nBand = -nBand;
108 1040900 : }
109 :
110 : /************************************************************************/
111 : /* RasterIO() */
112 : /************************************************************************/
113 :
114 : /**
115 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
116 : * int nXOff, int nYOff, int nXSize, int nYSize,
117 : * void * pData, int nBufXSize, int nBufYSize,
118 : * GDALDataType eBufType,
119 : * GSpacing nPixelSpace,
120 : * GSpacing nLineSpace,
121 : * GDALRasterIOExtraArg* psExtraArg )
122 : * \brief Read/write a region of image data for this band.
123 : *
124 : * This method allows reading a region of a GDALRasterBand into a buffer,
125 : * or writing data from a buffer into a region of a GDALRasterBand. It
126 : * automatically takes care of data type translation if the data type
127 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
128 : * The method also takes care of image decimation / replication if the
129 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
130 : * region being accessed (nXSize x nYSize).
131 : *
132 : * The nPixelSpace and nLineSpace parameters allow reading into or
133 : * writing from unusually organized buffers. This is primarily used
134 : * for buffers containing more than one bands raster data in interleaved
135 : * format.
136 : *
137 : * Some formats may efficiently implement decimation into a buffer by
138 : * reading from lower resolution overview images. The logic of the default
139 : * implementation in the base class GDALRasterBand is the following one. It
140 : * computes a target_downscaling_factor from the window of interest and buffer
141 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
142 : * It then walks through overviews and will select the first one whose
143 : * downscaling factor is greater than target_downscaling_factor / 1.2.
144 : *
145 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
146 : * The relationship between target_downscaling_factor and the select overview
147 : * level is the following one:
148 : *
149 : * target_downscaling_factor | selected_overview
150 : * ------------------------- | -----------------
151 : * ]0, 2 / 1.2] | full resolution band
152 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
153 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
154 : * ]8 / 1.2, infinity[ | 8x downsampled band
155 : *
156 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
157 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
158 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
159 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
160 : * this oversampling threshold defaults to 1. Consequently if there are overviews
161 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
162 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
163 : *
164 : * For highest performance full resolution data access, read and write
165 : * on "block boundaries" as returned by GetBlockSize(), or use the
166 : * ReadBlock() and WriteBlock() methods.
167 : *
168 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
169 : * functions.
170 : *
171 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
172 : * write a region of data.
173 : *
174 : * @param nXOff The pixel offset to the top left corner of the region
175 : * of the band to be accessed. This would be zero to start from the left side.
176 : *
177 : * @param nYOff The line offset to the top left corner of the region
178 : * of the band to be accessed. This would be zero to start from the top.
179 : *
180 : * @param nXSize The width of the region of the band to be accessed in pixels.
181 : *
182 : * @param nYSize The height of the region of the band to be accessed in lines.
183 : *
184 : * @param pData The buffer into which the data should be read, or from which
185 : * it should be written. This buffer must contain at least nBufXSize *
186 : * nBufYSize words of type eBufType. It is organized in left to right,
187 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
188 : * and nLineSpace parameters.
189 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
190 : * temporarily modified during the execution of this method (and eventually
191 : * restored back to its original content), so it is not safe to use a buffer
192 : * stored in a read-only section of the calling program.
193 : *
194 : * @param nBufXSize the width 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 nBufYSize the height of the buffer image into which the desired region
198 : * is to be read, or from which it is to be written.
199 : *
200 : * @param eBufType the type of the pixel values in the pData data buffer. The
201 : * pixel values will automatically be translated to/from the GDALRasterBand
202 : * data type as needed.
203 : *
204 : * @param nPixelSpace The byte offset from the start of one pixel value in
205 : * pData to the start of the next pixel value within a scanline. If defaulted
206 : * (0) the size of the datatype eBufType is used.
207 : *
208 : * @param nLineSpace The byte offset from the start of one scanline in
209 : * pData to the start of the next. If defaulted (0) the size of the datatype
210 : * eBufType * nBufXSize is used.
211 : *
212 : * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
213 : * structure with additional arguments to specify resampling and progress
214 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
215 : * configuration option can also be defined to override the default resampling
216 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
217 : *
218 : * @return CE_Failure if the access fails, otherwise CE_None.
219 : */
220 :
221 : /**
222 : * \brief Read/write a region of image data for this band.
223 : *
224 : * This method allows reading a region of a GDALRasterBand into a buffer,
225 : * or writing data from a buffer into a region of a GDALRasterBand. It
226 : * automatically takes care of data type translation if the data type
227 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
228 : * The method also takes care of image decimation / replication if the
229 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
230 : * region being accessed (nXSize x nYSize).
231 : *
232 : * The nPixelSpace and nLineSpace parameters allow reading into or
233 : * writing from unusually organized buffers. This is primarily used
234 : * for buffers containing more than one bands raster data in interleaved
235 : * format.
236 : *
237 : * Some formats may efficiently implement decimation into a buffer by
238 : * reading from lower resolution overview images. The logic of the default
239 : * implementation in the base class GDALRasterBand is the following one. It
240 : * computes a target_downscaling_factor from the window of interest and buffer
241 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
242 : * It then walks through overviews and will select the first one whose
243 : * downscaling factor is greater than target_downscaling_factor / 1.2.
244 : *
245 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
246 : * The relationship between target_downscaling_factor and the select overview
247 : * level is the following one:
248 : *
249 : * target_downscaling_factor | selected_overview
250 : * ------------------------- | -----------------
251 : * ]0, 2 / 1.2] | full resolution band
252 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
253 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
254 : * ]8 / 1.2, infinity[ | 8x downsampled band
255 : *
256 : * For highest performance full resolution data access, read and write
257 : * on "block boundaries" as returned by GetBlockSize(), or use the
258 : * ReadBlock() and WriteBlock() methods.
259 : *
260 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
261 : * functions.
262 : *
263 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
264 : * write a region of data.
265 : *
266 : * @param nXOff The pixel offset to the top left corner of the region
267 : * of the band to be accessed. This would be zero to start from the left side.
268 : *
269 : * @param nYOff The line offset to the top left corner of the region
270 : * of the band to be accessed. This would be zero to start from the top.
271 : *
272 : * @param nXSize The width of the region of the band to be accessed in pixels.
273 : *
274 : * @param nYSize The height of the region of the band to be accessed in lines.
275 : *
276 : * @param[in,out] pData The buffer into which the data should be read, or from
277 : * which it should be written. This buffer must contain at least nBufXSize *
278 : * nBufYSize words of type eBufType. It is organized in left to right,
279 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
280 : * and nLineSpace parameters.
281 : *
282 : * @param nBufXSize the width of the buffer image into which the desired region
283 : * is to be read, or from which it is to be written.
284 : *
285 : * @param nBufYSize the height of the buffer image into which the desired region
286 : * is to be read, or from which it is to be written.
287 : *
288 : * @param eBufType the type of the pixel values in the pData data buffer. The
289 : * pixel values will automatically be translated to/from the GDALRasterBand
290 : * data type as needed.
291 : *
292 : * @param nPixelSpace The byte offset from the start of one pixel value in
293 : * pData to the start of the next pixel value within a scanline. If defaulted
294 : * (0) the size of the datatype eBufType is used.
295 : *
296 : * @param nLineSpace The byte offset from the start of one scanline in
297 : * pData to the start of the next. If defaulted (0) the size of the datatype
298 : * eBufType * nBufXSize is used.
299 : *
300 : * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
301 : * structure with additional arguments to specify resampling and progress
302 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
303 : * configuration option can also be defined to override the default resampling
304 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
305 : *
306 : * @return CE_Failure if the access fails, otherwise CE_None.
307 : */
308 :
309 2751420 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
310 : int nXSize, int nYSize, void *pData,
311 : int nBufXSize, int nBufYSize,
312 : GDALDataType eBufType, GSpacing nPixelSpace,
313 : GSpacing nLineSpace,
314 : GDALRasterIOExtraArg *psExtraArg)
315 :
316 : {
317 : GDALRasterIOExtraArg sExtraArg;
318 2751420 : if (psExtraArg == nullptr)
319 : {
320 2674980 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
321 2674980 : psExtraArg = &sExtraArg;
322 : }
323 76441 : else if (psExtraArg->nVersion != RASTERIO_EXTRA_ARG_CURRENT_VERSION)
324 : {
325 0 : ReportError(CE_Failure, CPLE_AppDefined,
326 : "Unhandled version of GDALRasterIOExtraArg");
327 0 : return CE_Failure;
328 : }
329 :
330 2751420 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
331 : nBufYSize);
332 :
333 2751270 : if (nullptr == pData)
334 : {
335 0 : ReportError(CE_Failure, CPLE_AppDefined,
336 : "The buffer into which the data should be read is null");
337 0 : return CE_Failure;
338 : }
339 :
340 : /* -------------------------------------------------------------------- */
341 : /* Some size values are "noop". Lets just return to avoid */
342 : /* stressing lower level functions. */
343 : /* -------------------------------------------------------------------- */
344 2751270 : if (nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1)
345 : {
346 441 : CPLDebug("GDAL",
347 : "RasterIO() skipped for odd window or buffer size.\n"
348 : " Window = (%d,%d)x%dx%d\n"
349 : " Buffer = %dx%d\n",
350 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
351 :
352 2 : return CE_None;
353 : }
354 :
355 2750830 : if (eRWFlag == GF_Write)
356 : {
357 113122 : if (eFlushBlockErr != CE_None)
358 : {
359 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
360 : "An error occurred while writing a dirty block "
361 : "from GDALRasterBand::RasterIO");
362 0 : CPLErr eErr = eFlushBlockErr;
363 0 : eFlushBlockErr = CE_None;
364 0 : return eErr;
365 : }
366 113122 : if (eAccess != GA_Update)
367 : {
368 3 : ReportError(CE_Failure, CPLE_AppDefined,
369 : "Write operation not permitted on dataset opened "
370 : "in read-only mode");
371 3 : return CE_Failure;
372 : }
373 : }
374 :
375 : /* -------------------------------------------------------------------- */
376 : /* If pixel and line spacing are defaulted assign reasonable */
377 : /* value assuming a packed buffer. */
378 : /* -------------------------------------------------------------------- */
379 2750830 : if (nPixelSpace == 0)
380 : {
381 2670490 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
382 : }
383 :
384 2750880 : if (nLineSpace == 0)
385 : {
386 2667100 : nLineSpace = nPixelSpace * nBufXSize;
387 : }
388 :
389 : /* -------------------------------------------------------------------- */
390 : /* Do some validation of parameters. */
391 : /* -------------------------------------------------------------------- */
392 2750880 : if (nXOff < 0 || nXOff > INT_MAX - nXSize ||
393 2751630 : nXOff + nXSize > nRasterXSize || nYOff < 0 ||
394 2751510 : nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize)
395 : {
396 0 : ReportError(CE_Failure, CPLE_IllegalArg,
397 : "Access window out of range in RasterIO(). Requested\n"
398 : "(%d,%d) of size %dx%d on raster of %dx%d.",
399 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
400 15 : return CE_Failure;
401 : }
402 :
403 2751550 : if (eRWFlag != GF_Read && eRWFlag != GF_Write)
404 : {
405 0 : ReportError(
406 : CE_Failure, CPLE_IllegalArg,
407 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
408 : eRWFlag);
409 0 : return CE_Failure;
410 : }
411 :
412 : /* -------------------------------------------------------------------- */
413 : /* Call the format specific function. */
414 : /* -------------------------------------------------------------------- */
415 :
416 2751550 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
417 :
418 : CPLErr eErr;
419 2751610 : if (bForceCachedIO)
420 22 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
421 : pData, nBufXSize, nBufYSize, eBufType,
422 : nPixelSpace, nLineSpace, psExtraArg);
423 : else
424 : eErr =
425 2751780 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
426 2751590 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
427 :
428 2751800 : if (bCallLeaveReadWrite)
429 186646 : LeaveReadWrite();
430 :
431 2751720 : return eErr;
432 : }
433 :
434 : /************************************************************************/
435 : /* GDALRasterIO() */
436 : /************************************************************************/
437 :
438 : /**
439 : * \brief Read/write a region of image data for this band.
440 : *
441 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
442 : * resolution, progress callback, etc. are needed)
443 : *
444 : * @see GDALRasterBand::RasterIO()
445 : */
446 :
447 2513650 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
448 : int nXOff, int nYOff, int nXSize, int nYSize,
449 : void *pData, int nBufXSize, int nBufYSize,
450 : GDALDataType eBufType, int nPixelSpace,
451 : int nLineSpace)
452 :
453 : {
454 2513650 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
455 :
456 2513650 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
457 :
458 2513520 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
459 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
460 2513920 : nLineSpace, nullptr));
461 : }
462 :
463 : /************************************************************************/
464 : /* GDALRasterIOEx() */
465 : /************************************************************************/
466 :
467 : /**
468 : * \brief Read/write a region of image data for this band.
469 : *
470 : * @see GDALRasterBand::RasterIO()
471 : * @since GDAL 2.0
472 : */
473 :
474 31241 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
475 : int nXOff, int nYOff, int nXSize, int nYSize,
476 : void *pData, int nBufXSize, int nBufYSize,
477 : GDALDataType eBufType, GSpacing nPixelSpace,
478 : GSpacing nLineSpace,
479 : GDALRasterIOExtraArg *psExtraArg)
480 :
481 : {
482 31241 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
483 :
484 31241 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
485 :
486 31241 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
487 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
488 31240 : nLineSpace, psExtraArg));
489 : }
490 :
491 : /************************************************************************/
492 : /* ReadBlock() */
493 : /************************************************************************/
494 :
495 : /**
496 : * \brief Read a block of image data efficiently.
497 : *
498 : * This method accesses a "natural" block from the raster band without
499 : * resampling, or data type conversion. For a more generalized, but
500 : * potentially less efficient access use RasterIO().
501 : *
502 : * This method is the same as the C GDALReadBlock() function.
503 : *
504 : * See the GetLockedBlockRef() method for a way of accessing internally cached
505 : * block oriented data without an extra copy into an application buffer.
506 : *
507 : * The following code would efficiently compute a histogram of eight bit
508 : * raster data. Note that the final block may be partial ... data beyond
509 : * the edge of the underlying raster band in these edge blocks is of an
510 : * undetermined value.
511 : *
512 : \code{.cpp}
513 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
514 :
515 : {
516 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
517 :
518 : CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
519 :
520 : int nXBlockSize, nYBlockSize;
521 :
522 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
523 : int nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
524 : int nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
525 :
526 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
527 :
528 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
529 : {
530 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
531 : {
532 : int nXValid, nYValid;
533 :
534 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
535 :
536 : // Compute the portion of the block that is valid
537 : // for partial edge blocks.
538 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
539 :
540 : // Collect the histogram counts.
541 : for( int iY = 0; iY < nYValid; iY++ )
542 : {
543 : for( int iX = 0; iX < nXValid; iX++ )
544 : {
545 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
546 : }
547 : }
548 : }
549 : }
550 : }
551 : \endcode
552 : *
553 : * @param nXBlockOff the horizontal block offset, with zero indicating
554 : * the left most block, 1 the next block and so forth.
555 : *
556 : * @param nYBlockOff the vertical block offset, with zero indicating
557 : * the top most block, 1 the next block and so forth.
558 : *
559 : * @param pImage the buffer into which the data will be read. The buffer
560 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
561 : * of type GetRasterDataType().
562 : *
563 : * @return CE_None on success or CE_Failure on an error.
564 : */
565 :
566 607 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
567 :
568 : {
569 : /* -------------------------------------------------------------------- */
570 : /* Validate arguments. */
571 : /* -------------------------------------------------------------------- */
572 607 : CPLAssert(pImage != nullptr);
573 :
574 607 : if (!InitBlockInfo())
575 0 : return CE_Failure;
576 :
577 607 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
578 : {
579 0 : ReportError(CE_Failure, CPLE_IllegalArg,
580 : "Illegal nXBlockOff value (%d) in "
581 : "GDALRasterBand::ReadBlock()\n",
582 : nXBlockOff);
583 :
584 0 : return (CE_Failure);
585 : }
586 :
587 607 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
588 : {
589 0 : ReportError(CE_Failure, CPLE_IllegalArg,
590 : "Illegal nYBlockOff value (%d) in "
591 : "GDALRasterBand::ReadBlock()\n",
592 : nYBlockOff);
593 :
594 0 : return (CE_Failure);
595 : }
596 :
597 : /* -------------------------------------------------------------------- */
598 : /* Invoke underlying implementation method. */
599 : /* -------------------------------------------------------------------- */
600 :
601 607 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
602 607 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
603 607 : if (bCallLeaveReadWrite)
604 4 : LeaveReadWrite();
605 607 : return eErr;
606 : }
607 :
608 : /************************************************************************/
609 : /* GDALReadBlock() */
610 : /************************************************************************/
611 :
612 : /**
613 : * \brief Read a block of image data efficiently.
614 : *
615 : * @see GDALRasterBand::ReadBlock()
616 : */
617 :
618 67 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
619 : void *pData)
620 :
621 : {
622 67 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
623 :
624 67 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
625 67 : return (poBand->ReadBlock(nXOff, nYOff, pData));
626 : }
627 :
628 : /************************************************************************/
629 : /* IReadBlock() */
630 : /************************************************************************/
631 :
632 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
633 : * ) \brief Read a block of data.
634 : *
635 : * Default internal implementation ... to be overridden by
636 : * subclasses that support reading.
637 : * @param nBlockXOff Block X Offset
638 : * @param nBlockYOff Block Y Offset
639 : * @param pData Pixel buffer into which to place read data.
640 : * @return CE_None on success or CE_Failure on an error.
641 : */
642 :
643 : /************************************************************************/
644 : /* IWriteBlock() */
645 : /************************************************************************/
646 :
647 : /**
648 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
649 : * Write a block of data.
650 : *
651 : * Default internal implementation ... to be overridden by
652 : * subclasses that support writing.
653 : * @param nBlockXOff Block X Offset
654 : * @param nBlockYOff Block Y Offset
655 : * @param pData Pixel buffer to write
656 : * @return CE_None on success or CE_Failure on an error.
657 : */
658 :
659 : /**/
660 : /**/
661 :
662 2 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
663 : void * /*pData*/)
664 :
665 : {
666 2 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
667 2 : ReportError(CE_Failure, CPLE_NotSupported,
668 : "WriteBlock() not supported for this dataset.");
669 :
670 2 : return (CE_Failure);
671 : }
672 :
673 : /************************************************************************/
674 : /* WriteBlock() */
675 : /************************************************************************/
676 :
677 : /**
678 : * \brief Write a block of image data efficiently.
679 : *
680 : * This method accesses a "natural" block from the raster band without
681 : * resampling, or data type conversion. For a more generalized, but
682 : * potentially less efficient access use RasterIO().
683 : *
684 : * This method is the same as the C GDALWriteBlock() function.
685 : *
686 : * See ReadBlock() for an example of block oriented data access.
687 : *
688 : * @param nXBlockOff the horizontal block offset, with zero indicating
689 : * the left most block, 1 the next block and so forth.
690 : *
691 : * @param nYBlockOff the vertical block offset, with zero indicating
692 : * the left most block, 1 the next block and so forth.
693 : *
694 : * @param pImage the buffer from which the data will be written. The buffer
695 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
696 : * of type GetRasterDataType(). Note that the content of the buffer might be
697 : * temporarily modified during the execution of this method (and eventually
698 : * restored back to its original content), so it is not safe to use a buffer
699 : * stored in a read-only section of the calling program.
700 : *
701 : * @return CE_None on success or CE_Failure on an error.
702 : */
703 :
704 4799 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
705 :
706 : {
707 : /* -------------------------------------------------------------------- */
708 : /* Validate arguments. */
709 : /* -------------------------------------------------------------------- */
710 4799 : CPLAssert(pImage != nullptr);
711 :
712 4799 : if (!InitBlockInfo())
713 0 : return CE_Failure;
714 :
715 4799 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
716 : {
717 0 : ReportError(CE_Failure, CPLE_IllegalArg,
718 : "Illegal nXBlockOff value (%d) in "
719 : "GDALRasterBand::WriteBlock()\n",
720 : nXBlockOff);
721 :
722 0 : return (CE_Failure);
723 : }
724 :
725 4799 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
726 : {
727 0 : ReportError(CE_Failure, CPLE_IllegalArg,
728 : "Illegal nYBlockOff value (%d) in "
729 : "GDALRasterBand::WriteBlock()\n",
730 : nYBlockOff);
731 :
732 0 : return (CE_Failure);
733 : }
734 :
735 4799 : if (eAccess == GA_ReadOnly)
736 : {
737 0 : ReportError(CE_Failure, CPLE_NoWriteAccess,
738 : "Attempt to write to read only dataset in"
739 : "GDALRasterBand::WriteBlock().\n");
740 :
741 0 : return (CE_Failure);
742 : }
743 :
744 4799 : if (eFlushBlockErr != CE_None)
745 : {
746 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
747 : "An error occurred while writing a dirty block "
748 : "from GDALRasterBand::WriteBlock");
749 0 : CPLErr eErr = eFlushBlockErr;
750 0 : eFlushBlockErr = CE_None;
751 0 : return eErr;
752 : }
753 :
754 : /* -------------------------------------------------------------------- */
755 : /* Invoke underlying implementation method. */
756 : /* -------------------------------------------------------------------- */
757 :
758 4799 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
759 4799 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
760 4799 : if (bCallLeaveReadWrite)
761 4799 : LeaveReadWrite();
762 :
763 4799 : return eErr;
764 : }
765 :
766 : /************************************************************************/
767 : /* GDALWriteBlock() */
768 : /************************************************************************/
769 :
770 : /**
771 : * \brief Write a block of image data efficiently.
772 : *
773 : * @see GDALRasterBand::WriteBlock()
774 : */
775 :
776 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
777 : void *pData)
778 :
779 : {
780 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
781 :
782 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
783 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
784 : }
785 :
786 : /************************************************************************/
787 : /* GetActualBlockSize() */
788 : /************************************************************************/
789 : /**
790 : * \brief Fetch the actual block size for a given block offset.
791 : *
792 : * Handles partial blocks at the edges of the raster and returns the true
793 : * number of pixels
794 : *
795 : * @param nXBlockOff the horizontal block offset for which to calculate the
796 : * number of valid pixels, with zero indicating the left most block, 1 the next
797 : * block and so forth.
798 : *
799 : * @param nYBlockOff the vertical block offset, with zero indicating
800 : * the top most block, 1 the next block and so forth.
801 : *
802 : * @param pnXValid pointer to an integer in which the number of valid pixels in
803 : * the x direction will be stored
804 : *
805 : * @param pnYValid pointer to an integer in which the number of valid pixels in
806 : * the y direction will be stored
807 : *
808 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
809 : *
810 : * @since GDAL 2.2
811 : */
812 45308 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
813 : int *pnXValid, int *pnYValid)
814 : {
815 90615 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
816 90613 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
817 90610 : nYBlockOff < 0 || nBlockYSize == 0 ||
818 45305 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
819 : {
820 4 : return CE_Failure;
821 : }
822 :
823 45304 : const int nXPixelOff = nXBlockOff * nBlockXSize;
824 45304 : const int nYPixelOff = nYBlockOff * nBlockYSize;
825 :
826 45304 : *pnXValid = nBlockXSize;
827 45304 : *pnYValid = nBlockYSize;
828 :
829 45304 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
830 : {
831 43815 : *pnXValid = nRasterXSize - nXPixelOff;
832 : }
833 :
834 45304 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
835 : {
836 3203 : *pnYValid = nRasterYSize - nYPixelOff;
837 : }
838 :
839 45304 : return CE_None;
840 : }
841 :
842 : /************************************************************************/
843 : /* GDALGetActualBlockSize() */
844 : /************************************************************************/
845 :
846 : /**
847 : * \brief Retrieve the actual block size for a given block offset.
848 : *
849 : * @see GDALRasterBand::GetActualBlockSize()
850 : */
851 :
852 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
853 : int nYBlockOff, int *pnXValid,
854 : int *pnYValid)
855 :
856 : {
857 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
858 :
859 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
860 : return (
861 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
862 : }
863 :
864 : /************************************************************************/
865 : /* GetSuggestedBlockAccessPattern() */
866 : /************************************************************************/
867 :
868 : /**
869 : * \brief Return the suggested/most efficient access pattern to blocks
870 : * (for read operations).
871 : *
872 : * While all GDAL drivers have to expose a block size, not all can guarantee
873 : * efficient random access (GSBAP_RANDOM) to any block.
874 : * Some drivers for example decompress sequentially a compressed stream from
875 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
876 : * case best performance will be achieved while reading blocks in that order.
877 : * (accessing blocks in random access in such rasters typically causes the
878 : * decoding to be re-initialized from the start if accessing blocks in
879 : * a non-sequential order)
880 : *
881 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
882 : * returned by drivers that expose a somewhat artificial block size, because
883 : * they can extract any part of a raster, but in a rather inefficient way.
884 : *
885 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
886 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
887 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
888 : * most efficient strategy is to read as many pixels as possible in the less
889 : * RasterIO() operations.
890 : *
891 : * The return of this method is for example used to determine the swath size
892 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
893 : *
894 : * @since GDAL 3.6
895 : */
896 :
897 : GDALSuggestedBlockAccessPattern
898 1277 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
899 : {
900 1277 : return GSBAP_UNKNOWN;
901 : }
902 :
903 : /************************************************************************/
904 : /* GetRasterDataType() */
905 : /************************************************************************/
906 :
907 : /**
908 : * \brief Fetch the pixel data type for this band.
909 : *
910 : * This method is the same as the C function GDALGetRasterDataType().
911 : *
912 : * @return the data type of pixels for this band.
913 : */
914 :
915 5253330 : GDALDataType GDALRasterBand::GetRasterDataType()
916 :
917 : {
918 5253330 : return eDataType;
919 : }
920 :
921 : /************************************************************************/
922 : /* GDALGetRasterDataType() */
923 : /************************************************************************/
924 :
925 : /**
926 : * \brief Fetch the pixel data type for this band.
927 : *
928 : * @see GDALRasterBand::GetRasterDataType()
929 : */
930 :
931 866966 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
932 :
933 : {
934 866966 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
935 :
936 866966 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
937 866966 : return poBand->GetRasterDataType();
938 : }
939 :
940 : /************************************************************************/
941 : /* GetBlockSize() */
942 : /************************************************************************/
943 :
944 : /**
945 : * \brief Fetch the "natural" block size of this band.
946 : *
947 : * GDAL contains a concept of the natural block size of rasters so that
948 : * applications can organized data access efficiently for some file formats.
949 : * The natural block size is the block size that is most efficient for
950 : * accessing the format. For many formats this is simple a whole scanline
951 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
952 : *
953 : * However, for tiled images this will typically be the tile size.
954 : *
955 : * Note that the X and Y block sizes don't have to divide the image size
956 : * evenly, meaning that right and bottom edge blocks may be incomplete.
957 : * See ReadBlock() for an example of code dealing with these issues.
958 : *
959 : * This method is the same as the C function GDALGetBlockSize().
960 : *
961 : * @param pnXSize integer to put the X block size into or NULL.
962 : *
963 : * @param pnYSize integer to put the Y block size into or NULL.
964 : */
965 :
966 3276770 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize)
967 :
968 : {
969 3276770 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
970 : {
971 19 : ReportError(CE_Failure, CPLE_AppDefined,
972 : "Invalid block dimension : %d * %d", nBlockXSize,
973 : nBlockYSize);
974 0 : if (pnXSize != nullptr)
975 0 : *pnXSize = 0;
976 0 : if (pnYSize != nullptr)
977 0 : *pnYSize = 0;
978 : }
979 : else
980 : {
981 3276750 : if (pnXSize != nullptr)
982 3276760 : *pnXSize = nBlockXSize;
983 3276750 : if (pnYSize != nullptr)
984 3276760 : *pnYSize = nBlockYSize;
985 : }
986 3276750 : }
987 :
988 : /************************************************************************/
989 : /* GDALGetBlockSize() */
990 : /************************************************************************/
991 :
992 : /**
993 : * \brief Fetch the "natural" block size of this band.
994 : *
995 : * @see GDALRasterBand::GetBlockSize()
996 : */
997 :
998 10849 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
999 : int *pnYSize)
1000 :
1001 : {
1002 10849 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1003 :
1004 10849 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1005 10849 : poBand->GetBlockSize(pnXSize, pnYSize);
1006 : }
1007 :
1008 : /************************************************************************/
1009 : /* InitBlockInfo() */
1010 : /************************************************************************/
1011 :
1012 : //! @cond Doxygen_Suppress
1013 3144080 : int GDALRasterBand::InitBlockInfo()
1014 :
1015 : {
1016 3144080 : if (poBandBlockCache != nullptr)
1017 3115020 : return poBandBlockCache->IsInitOK();
1018 :
1019 : /* Do some validation of raster and block dimensions in case the driver */
1020 : /* would have neglected to do it itself */
1021 29059 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1022 : {
1023 0 : ReportError(CE_Failure, CPLE_AppDefined,
1024 : "Invalid block dimension : %d * %d", nBlockXSize,
1025 : nBlockYSize);
1026 0 : return FALSE;
1027 : }
1028 :
1029 29059 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1030 : {
1031 0 : ReportError(CE_Failure, CPLE_AppDefined,
1032 : "Invalid raster dimension : %d * %d", nRasterXSize,
1033 : nRasterYSize);
1034 0 : return FALSE;
1035 : }
1036 :
1037 29059 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1038 29059 : if (nDataTypeSize == 0)
1039 : {
1040 0 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1041 0 : return FALSE;
1042 : }
1043 :
1044 : #if SIZEOF_VOIDP == 4
1045 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1046 : {
1047 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1048 : * multiplication in other cases */
1049 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1050 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1051 : {
1052 : ReportError(CE_Failure, CPLE_NotSupported,
1053 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1054 : nBlockYSize);
1055 : return FALSE;
1056 : }
1057 : }
1058 : #endif
1059 :
1060 29059 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1061 29059 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1062 :
1063 : const char *pszBlockStrategy =
1064 29059 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1065 29059 : bool bUseArray = true;
1066 29059 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1067 : {
1068 29019 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1069 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1070 : {
1071 29000 : GUIntBig nBlockCount =
1072 29000 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1073 29000 : if (poDS != nullptr)
1074 28757 : nBlockCount *= poDS->GetRasterCount();
1075 29000 : bUseArray = (nBlockCount < 1024 * 1024);
1076 : }
1077 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1078 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1079 : {
1080 0 : bUseArray = false;
1081 29019 : }
1082 : }
1083 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1084 40 : bUseArray = false;
1085 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1086 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1087 : pszBlockStrategy);
1088 :
1089 29059 : if (bUseArray)
1090 28989 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1091 : else
1092 : {
1093 70 : if (nBand == 1)
1094 25 : CPLDebug("GDAL", "Use hashset band block cache");
1095 70 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1096 : }
1097 29059 : if (poBandBlockCache == nullptr)
1098 0 : return FALSE;
1099 29059 : return poBandBlockCache->Init();
1100 : }
1101 :
1102 : //! @endcond
1103 :
1104 : /************************************************************************/
1105 : /* FlushCache() */
1106 : /************************************************************************/
1107 :
1108 : /**
1109 : * \brief Flush raster data cache.
1110 : *
1111 : * This call will recover memory used to cache data blocks for this raster
1112 : * band, and ensure that new requests are referred to the underlying driver.
1113 : *
1114 : * This method is the same as the C function GDALFlushRasterCache().
1115 : *
1116 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1117 : * @return CE_None on success.
1118 : */
1119 :
1120 2913710 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1121 :
1122 : {
1123 2957080 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1124 43367 : poBandBlockCache)
1125 2041 : poBandBlockCache->DisableDirtyBlockWriting();
1126 :
1127 2913680 : CPLErr eGlobalErr = eFlushBlockErr;
1128 :
1129 2913680 : if (eFlushBlockErr != CE_None)
1130 : {
1131 1 : ReportError(
1132 : eFlushBlockErr, CPLE_AppDefined,
1133 : "An error occurred while writing a dirty block from FlushCache");
1134 1 : eFlushBlockErr = CE_None;
1135 : }
1136 :
1137 2913680 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1138 2775040 : return eGlobalErr;
1139 :
1140 138636 : return poBandBlockCache->FlushCache();
1141 : }
1142 :
1143 : /************************************************************************/
1144 : /* GDALFlushRasterCache() */
1145 : /************************************************************************/
1146 :
1147 : /**
1148 : * \brief Flush raster data cache.
1149 : *
1150 : * @see GDALRasterBand::FlushCache()
1151 : */
1152 :
1153 129 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1154 :
1155 : {
1156 129 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1157 :
1158 129 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1159 : }
1160 :
1161 : /************************************************************************/
1162 : /* DropCache() */
1163 : /************************************************************************/
1164 :
1165 : /**
1166 : * \brief Drop raster data cache : data in cache will be lost.
1167 : *
1168 : * This call will recover memory used to cache data blocks for this raster
1169 : * band, and ensure that new requests are referred to the underlying driver.
1170 : *
1171 : * This method is the same as the C function GDALDropRasterCache().
1172 : *
1173 : * @return CE_None on success.
1174 : * @since 3.9
1175 : */
1176 :
1177 1 : CPLErr GDALRasterBand::DropCache()
1178 :
1179 : {
1180 1 : CPLErr result = CE_None;
1181 :
1182 1 : if (poBandBlockCache)
1183 1 : poBandBlockCache->DisableDirtyBlockWriting();
1184 :
1185 1 : CPLErr eGlobalErr = eFlushBlockErr;
1186 :
1187 1 : if (eFlushBlockErr != CE_None)
1188 : {
1189 0 : ReportError(
1190 : eFlushBlockErr, CPLE_AppDefined,
1191 : "An error occurred while writing a dirty block from DropCache");
1192 0 : eFlushBlockErr = CE_None;
1193 : }
1194 :
1195 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1196 0 : result = eGlobalErr;
1197 : else
1198 1 : result = poBandBlockCache->FlushCache();
1199 :
1200 1 : if (poBandBlockCache)
1201 1 : poBandBlockCache->EnableDirtyBlockWriting();
1202 :
1203 1 : return result;
1204 : }
1205 :
1206 : /************************************************************************/
1207 : /* GDALDropRasterCache() */
1208 : /************************************************************************/
1209 :
1210 : /**
1211 : * \brief Drop raster data cache.
1212 : *
1213 : * @see GDALRasterBand::DropCache()
1214 : * @since 3.9
1215 : */
1216 :
1217 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1218 :
1219 : {
1220 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1221 :
1222 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1223 : }
1224 :
1225 : /************************************************************************/
1226 : /* UnreferenceBlock() */
1227 : /* */
1228 : /* Unreference the block from our array of blocks */
1229 : /* This method should only be called by */
1230 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1231 : /* the block cache mutex) */
1232 : /************************************************************************/
1233 :
1234 29608 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1235 : {
1236 : #ifdef notdef
1237 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1238 : {
1239 : if (poBandBlockCache == nullptr)
1240 : printf("poBandBlockCache == NULL\n"); /*ok*/
1241 : else
1242 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1243 : printf("caller = %s\n", pszCaller); /*ok*/
1244 : printf("GDALRasterBand: %p\n", this); /*ok*/
1245 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1246 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1247 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1248 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1249 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1250 : poBlock->DumpBlock();
1251 : if (GetDataset() != nullptr)
1252 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1253 : GDALRasterBlock::Verify();
1254 : abort();
1255 : }
1256 : #endif
1257 29608 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1258 29608 : return poBandBlockCache->UnreferenceBlock(poBlock);
1259 : }
1260 :
1261 : /************************************************************************/
1262 : /* AddBlockToFreeList() */
1263 : /* */
1264 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1265 : /* finished with a block about to be free'd, they pass it to that */
1266 : /* method. */
1267 : /************************************************************************/
1268 :
1269 : //! @cond Doxygen_Suppress
1270 29608 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1271 : {
1272 29608 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1273 29608 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1274 : }
1275 :
1276 : //! @endcond
1277 :
1278 : /************************************************************************/
1279 : /* FlushBlock() */
1280 : /************************************************************************/
1281 :
1282 : /** Flush a block out of the block cache.
1283 : * @param nXBlockOff block x offset
1284 : * @param nYBlockOff blocky offset
1285 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1286 : * @return CE_None in case of success, an error code otherwise.
1287 : */
1288 2285 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1289 : int bWriteDirtyBlock)
1290 :
1291 : {
1292 2285 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1293 0 : return (CE_Failure);
1294 :
1295 : /* -------------------------------------------------------------------- */
1296 : /* Validate the request */
1297 : /* -------------------------------------------------------------------- */
1298 2285 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1299 : {
1300 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1301 : "Illegal nBlockXOff value (%d) in "
1302 : "GDALRasterBand::FlushBlock()\n",
1303 : nXBlockOff);
1304 :
1305 0 : return (CE_Failure);
1306 : }
1307 :
1308 2285 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1309 : {
1310 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1311 : "Illegal nBlockYOff value (%d) in "
1312 : "GDALRasterBand::FlushBlock()\n",
1313 : nYBlockOff);
1314 :
1315 0 : return (CE_Failure);
1316 : }
1317 :
1318 2285 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1319 2285 : bWriteDirtyBlock);
1320 : }
1321 :
1322 : /************************************************************************/
1323 : /* TryGetLockedBlockRef() */
1324 : /************************************************************************/
1325 :
1326 : /**
1327 : * \brief Try fetching block ref.
1328 : *
1329 : * This method will returned the requested block (locked) if it is already
1330 : * in the block cache for the layer. If not, nullptr is returned.
1331 : *
1332 : * If a non-NULL value is returned, then a lock for the block will have been
1333 : * acquired on behalf of the caller. It is absolutely imperative that the
1334 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1335 : * severe problems may result.
1336 : *
1337 : * @param nXBlockOff the horizontal block offset, with zero indicating
1338 : * the left most block, 1 the next block and so forth.
1339 : *
1340 : * @param nYBlockOff the vertical block offset, with zero indicating
1341 : * the top most block, 1 the next block and so forth.
1342 : *
1343 : * @return NULL if block not available, or locked block pointer.
1344 : */
1345 :
1346 9498360 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1347 : int nYBlockOff)
1348 :
1349 : {
1350 9498360 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1351 54277 : return nullptr;
1352 :
1353 : /* -------------------------------------------------------------------- */
1354 : /* Validate the request */
1355 : /* -------------------------------------------------------------------- */
1356 9444070 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1357 : {
1358 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1359 : "Illegal nBlockXOff value (%d) in "
1360 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1361 : nXBlockOff);
1362 :
1363 0 : return (nullptr);
1364 : }
1365 :
1366 9444070 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1367 : {
1368 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1369 : "Illegal nBlockYOff value (%d) in "
1370 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1371 : nYBlockOff);
1372 :
1373 0 : return (nullptr);
1374 : }
1375 :
1376 9444070 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1377 : }
1378 :
1379 : /************************************************************************/
1380 : /* GetLockedBlockRef() */
1381 : /************************************************************************/
1382 :
1383 : /**
1384 : * \brief Fetch a pointer to an internally cached raster block.
1385 : *
1386 : * This method will returned the requested block (locked) if it is already
1387 : * in the block cache for the layer. If not, the block will be read from
1388 : * the driver, and placed in the layer block cached, then returned. If an
1389 : * error occurs reading the block from the driver, a NULL value will be
1390 : * returned.
1391 : *
1392 : * If a non-NULL value is returned, then a lock for the block will have been
1393 : * acquired on behalf of the caller. It is absolutely imperative that the
1394 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1395 : * severe problems may result.
1396 : *
1397 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1398 : * enable caching.
1399 : *
1400 : * @param nXBlockOff the horizontal block offset, with zero indicating
1401 : * the left most block, 1 the next block and so forth.
1402 : *
1403 : * @param nYBlockOff the vertical block offset, with zero indicating
1404 : * the top most block, 1 the next block and so forth.
1405 : *
1406 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1407 : * but not actually read from the source. This is useful when it will just
1408 : * be completely set and written back.
1409 : *
1410 : * @return pointer to the block object, or NULL on failure.
1411 : */
1412 :
1413 9304580 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1414 : int nYBlockOff,
1415 : int bJustInitialize)
1416 :
1417 : {
1418 : /* -------------------------------------------------------------------- */
1419 : /* Try and fetch from cache. */
1420 : /* -------------------------------------------------------------------- */
1421 9304580 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1422 :
1423 : /* -------------------------------------------------------------------- */
1424 : /* If we didn't find it in our memory cache, instantiate a */
1425 : /* block (potentially load from disk) and "adopt" it into the */
1426 : /* cache. */
1427 : /* -------------------------------------------------------------------- */
1428 9304580 : if (poBlock == nullptr)
1429 : {
1430 2967590 : if (!InitBlockInfo())
1431 0 : return (nullptr);
1432 :
1433 : /* --------------------------------------------------------------------
1434 : */
1435 : /* Validate the request */
1436 : /* --------------------------------------------------------------------
1437 : */
1438 2967590 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1439 : {
1440 2 : ReportError(CE_Failure, CPLE_IllegalArg,
1441 : "Illegal nBlockXOff value (%d) in "
1442 : "GDALRasterBand::GetLockedBlockRef()\n",
1443 : nXBlockOff);
1444 :
1445 0 : return (nullptr);
1446 : }
1447 :
1448 2967590 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1449 : {
1450 11 : ReportError(CE_Failure, CPLE_IllegalArg,
1451 : "Illegal nBlockYOff value (%d) in "
1452 : "GDALRasterBand::GetLockedBlockRef()\n",
1453 : nYBlockOff);
1454 :
1455 0 : return (nullptr);
1456 : }
1457 :
1458 2967580 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1459 2967590 : if (poBlock == nullptr)
1460 0 : return nullptr;
1461 :
1462 2967590 : poBlock->AddLock();
1463 :
1464 : /* We need to temporarily drop the read-write lock in the following */
1465 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
1466 : */
1467 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
1468 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
1469 : */
1470 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
1471 : */
1472 : /* called and attempt at taking the lock on T2 (already taken).
1473 : * Similarly */
1474 : /* for T2 with D1, hence a deadlock situation (#6163) */
1475 : /* But this may open the door to other problems... */
1476 2967600 : if (poDS)
1477 2966560 : poDS->TemporarilyDropReadWriteLock();
1478 : /* allocate data space */
1479 2967590 : CPLErr eErr = poBlock->Internalize();
1480 2967600 : if (poDS)
1481 2966560 : poDS->ReacquireReadWriteLock();
1482 2967600 : if (eErr != CE_None)
1483 : {
1484 0 : poBlock->DropLock();
1485 0 : delete poBlock;
1486 0 : return nullptr;
1487 : }
1488 :
1489 2967600 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
1490 : {
1491 0 : poBlock->DropLock();
1492 0 : delete poBlock;
1493 0 : return nullptr;
1494 : }
1495 :
1496 2967590 : if (!bJustInitialize)
1497 : {
1498 2649120 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
1499 2649130 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1500 2649130 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
1501 2649130 : if (bCallLeaveReadWrite)
1502 127771 : LeaveReadWrite();
1503 2649120 : if (eErr != CE_None)
1504 : {
1505 1144 : poBlock->DropLock();
1506 1144 : FlushBlock(nXBlockOff, nYBlockOff);
1507 1144 : ReportError(CE_Failure, CPLE_AppDefined,
1508 : "IReadBlock failed at X offset %d, Y offset %d%s",
1509 : nXBlockOff, nYBlockOff,
1510 1144 : (nErrorCounter != CPLGetErrorCounter())
1511 1142 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
1512 : : "");
1513 1144 : return nullptr;
1514 : }
1515 :
1516 2647980 : nBlockReads++;
1517 2647980 : if (static_cast<GIntBig>(nBlockReads) ==
1518 2647980 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
1519 190 : 1 &&
1520 190 : nBand == 1 && poDS != nullptr)
1521 : {
1522 139 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
1523 139 : poDS->GetDescription());
1524 : }
1525 : }
1526 : }
1527 :
1528 9303460 : return poBlock;
1529 : }
1530 :
1531 : /************************************************************************/
1532 : /* Fill() */
1533 : /************************************************************************/
1534 :
1535 : /**
1536 : * \brief Fill this band with a constant value.
1537 : *
1538 : * GDAL makes no guarantees
1539 : * about what values pixels in newly created files are set to, so this
1540 : * method can be used to clear a band to a specified "default" value.
1541 : * The fill value is passed in as a double but this will be converted
1542 : * to the underlying type before writing to the file. An optional
1543 : * second argument allows the imaginary component of a complex
1544 : * constant value to be specified.
1545 : *
1546 : * This method is the same as the C function GDALFillRaster().
1547 : *
1548 : * @param dfRealValue Real component of fill value
1549 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
1550 : *
1551 : * @return CE_Failure if the write fails, otherwise CE_None
1552 : */
1553 169125 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
1554 : {
1555 :
1556 : // General approach is to construct a source block of the file's
1557 : // native type containing the appropriate value and then copy this
1558 : // to each block in the image via the RasterBlock cache. Using
1559 : // the cache means we avoid file I/O if it is not necessary, at the
1560 : // expense of some extra memcpy's (since we write to the
1561 : // RasterBlock cache, which is then at some point written to the
1562 : // underlying file, rather than simply directly to the underlying
1563 : // file.)
1564 :
1565 : // Check we can write to the file.
1566 169125 : if (eAccess == GA_ReadOnly)
1567 : {
1568 1 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1569 : "Attempt to write to read only dataset in "
1570 : "GDALRasterBand::Fill().");
1571 1 : return CE_Failure;
1572 : }
1573 :
1574 : // Make sure block parameters are set.
1575 169124 : if (!InitBlockInfo())
1576 0 : return CE_Failure;
1577 :
1578 : // Allocate the source block.
1579 169124 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
1580 169124 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
1581 169124 : auto blockByteSize = blockSize * elementSize;
1582 : unsigned char *srcBlock =
1583 169124 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
1584 169124 : if (srcBlock == nullptr)
1585 : {
1586 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
1587 : "GDALRasterBand::Fill(): Out of memory "
1588 : "allocating " CPL_FRMT_GUIB " bytes.\n",
1589 : static_cast<GUIntBig>(blockByteSize));
1590 0 : return CE_Failure;
1591 : }
1592 :
1593 : // Initialize the source block.
1594 169124 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
1595 169124 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
1596 : elementSize, blockSize);
1597 :
1598 169124 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1599 :
1600 : // Write block to block cache
1601 627190 : for (int j = 0; j < nBlocksPerColumn; ++j)
1602 : {
1603 1210460 : for (int i = 0; i < nBlocksPerRow; ++i)
1604 : {
1605 752397 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
1606 752397 : if (destBlock == nullptr)
1607 : {
1608 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
1609 : "GDALRasterBand::Fill(): Error "
1610 : "while retrieving cache block.");
1611 0 : VSIFree(srcBlock);
1612 0 : return CE_Failure;
1613 : }
1614 752397 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
1615 752397 : destBlock->MarkDirty();
1616 752397 : destBlock->DropLock();
1617 : }
1618 : }
1619 :
1620 169124 : if (bCallLeaveReadWrite)
1621 168655 : LeaveReadWrite();
1622 :
1623 : // Free up the source block
1624 169124 : VSIFree(srcBlock);
1625 :
1626 169124 : return CE_None;
1627 : }
1628 :
1629 : /************************************************************************/
1630 : /* GDALFillRaster() */
1631 : /************************************************************************/
1632 :
1633 : /**
1634 : * \brief Fill this band with a constant value.
1635 : *
1636 : * @see GDALRasterBand::Fill()
1637 : */
1638 169091 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
1639 : double dfImaginaryValue)
1640 : {
1641 169091 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
1642 :
1643 169091 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1644 169091 : return poBand->Fill(dfRealValue, dfImaginaryValue);
1645 : }
1646 :
1647 : /************************************************************************/
1648 : /* GetAccess() */
1649 : /************************************************************************/
1650 :
1651 : /**
1652 : * \brief Find out if we have update permission for this band.
1653 : *
1654 : * This method is the same as the C function GDALGetRasterAccess().
1655 : *
1656 : * @return Either GA_Update or GA_ReadOnly.
1657 : */
1658 :
1659 2407 : GDALAccess GDALRasterBand::GetAccess()
1660 :
1661 : {
1662 2407 : return eAccess;
1663 : }
1664 :
1665 : /************************************************************************/
1666 : /* GDALGetRasterAccess() */
1667 : /************************************************************************/
1668 :
1669 : /**
1670 : * \brief Find out if we have update permission for this band.
1671 : *
1672 : * @see GDALRasterBand::GetAccess()
1673 : */
1674 :
1675 1770 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
1676 :
1677 : {
1678 1770 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
1679 :
1680 1770 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1681 1770 : return poBand->GetAccess();
1682 : }
1683 :
1684 : /************************************************************************/
1685 : /* GetCategoryNames() */
1686 : /************************************************************************/
1687 :
1688 : /**
1689 : * \brief Fetch the list of category names for this raster.
1690 : *
1691 : * The return list is a "StringList" in the sense of the CPL functions.
1692 : * That is a NULL terminated array of strings. Raster values without
1693 : * associated names will have an empty string in the returned list. The
1694 : * first entry in the list is for raster values of zero, and so on.
1695 : *
1696 : * The returned stringlist should not be altered or freed by the application.
1697 : * It may change on the next GDAL call, so please copy it if it is needed
1698 : * for any period of time.
1699 : *
1700 : * This method is the same as the C function GDALGetRasterCategoryNames().
1701 : *
1702 : * @return list of names, or NULL if none.
1703 : */
1704 :
1705 207 : char **GDALRasterBand::GetCategoryNames()
1706 :
1707 : {
1708 207 : return nullptr;
1709 : }
1710 :
1711 : /************************************************************************/
1712 : /* GDALGetRasterCategoryNames() */
1713 : /************************************************************************/
1714 :
1715 : /**
1716 : * \brief Fetch the list of category names for this raster.
1717 : *
1718 : * @see GDALRasterBand::GetCategoryNames()
1719 : */
1720 :
1721 155 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
1722 :
1723 : {
1724 155 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
1725 :
1726 155 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1727 155 : return poBand->GetCategoryNames();
1728 : }
1729 :
1730 : /************************************************************************/
1731 : /* SetCategoryNames() */
1732 : /************************************************************************/
1733 :
1734 : /**
1735 : * \fn GDALRasterBand::SetCategoryNames(char**)
1736 : * \brief Set the category names for this band.
1737 : *
1738 : * See the GetCategoryNames() method for more on the interpretation of
1739 : * category names.
1740 : *
1741 : * This method is the same as the C function GDALSetRasterCategoryNames().
1742 : *
1743 : * @param papszNames the NULL terminated StringList of category names. May
1744 : * be NULL to just clear the existing list.
1745 : *
1746 : * @return CE_None on success of CE_Failure on failure. If unsupported
1747 : * by the driver CE_Failure is returned, but no error message is reported.
1748 : */
1749 :
1750 : /**/
1751 : /**/
1752 :
1753 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
1754 : {
1755 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1756 0 : ReportError(CE_Failure, CPLE_NotSupported,
1757 : "SetCategoryNames() not supported for this dataset.");
1758 :
1759 0 : return CE_Failure;
1760 : }
1761 :
1762 : /************************************************************************/
1763 : /* GDALSetCategoryNames() */
1764 : /************************************************************************/
1765 :
1766 : /**
1767 : * \brief Set the category names for this band.
1768 : *
1769 : * @see GDALRasterBand::SetCategoryNames()
1770 : */
1771 :
1772 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
1773 : CSLConstList papszNames)
1774 :
1775 : {
1776 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
1777 :
1778 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1779 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
1780 : }
1781 :
1782 : /************************************************************************/
1783 : /* GetNoDataValue() */
1784 : /************************************************************************/
1785 :
1786 : /**
1787 : * \brief Fetch the no data value for this band.
1788 : *
1789 : * If there is no out of data value, an out of range value will generally
1790 : * be returned. The no data value for a band is generally a special marker
1791 : * value used to mark pixels that are not valid data. Such pixels should
1792 : * generally not be displayed, nor contribute to analysis operations.
1793 : *
1794 : * The no data value returned is 'raw', meaning that it has no offset and
1795 : * scale applied.
1796 : *
1797 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
1798 : * lossy if the nodata value cannot exactly been represented by a double.
1799 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
1800 : *
1801 : * This method is the same as the C function GDALGetRasterNoDataValue().
1802 : *
1803 : * @param pbSuccess pointer to a boolean to use to indicate if a value
1804 : * is actually associated with this layer. May be NULL (default).
1805 : *
1806 : * @return the nodata value for this band.
1807 : */
1808 :
1809 31196 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
1810 :
1811 : {
1812 31196 : if (pbSuccess != nullptr)
1813 31196 : *pbSuccess = FALSE;
1814 :
1815 31196 : return -1e10;
1816 : }
1817 :
1818 : /************************************************************************/
1819 : /* GDALGetRasterNoDataValue() */
1820 : /************************************************************************/
1821 :
1822 : /**
1823 : * \brief Fetch the no data value for this band.
1824 : *
1825 : * @see GDALRasterBand::GetNoDataValue()
1826 : */
1827 :
1828 413392 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
1829 : int *pbSuccess)
1830 :
1831 : {
1832 413392 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
1833 :
1834 413392 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1835 413392 : return poBand->GetNoDataValue(pbSuccess);
1836 : }
1837 :
1838 : /************************************************************************/
1839 : /* GetNoDataValueAsInt64() */
1840 : /************************************************************************/
1841 :
1842 : /**
1843 : * \brief Fetch the no data value for this band.
1844 : *
1845 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
1846 : *
1847 : * If there is no out of data value, an out of range value will generally
1848 : * be returned. The no data value for a band is generally a special marker
1849 : * value used to mark pixels that are not valid data. Such pixels should
1850 : * generally not be displayed, nor contribute to analysis operations.
1851 : *
1852 : * The no data value returned is 'raw', meaning that it has no offset and
1853 : * scale applied.
1854 : *
1855 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
1856 : *
1857 : * @param pbSuccess pointer to a boolean to use to indicate if a value
1858 : * is actually associated with this layer. May be NULL (default).
1859 : *
1860 : * @return the nodata value for this band.
1861 : *
1862 : * @since GDAL 3.5
1863 : */
1864 :
1865 2 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
1866 :
1867 : {
1868 2 : if (pbSuccess != nullptr)
1869 2 : *pbSuccess = FALSE;
1870 :
1871 2 : return std::numeric_limits<int64_t>::min();
1872 : }
1873 :
1874 : /************************************************************************/
1875 : /* GDALGetRasterNoDataValueAsInt64() */
1876 : /************************************************************************/
1877 :
1878 : /**
1879 : * \brief Fetch the no data value for this band.
1880 : *
1881 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
1882 : *
1883 : * @see GDALRasterBand::GetNoDataValueAsInt64()
1884 : *
1885 : * @since GDAL 3.5
1886 : */
1887 :
1888 21 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
1889 : int *pbSuccess)
1890 :
1891 : {
1892 21 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
1893 : std::numeric_limits<int64_t>::min());
1894 :
1895 21 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1896 21 : return poBand->GetNoDataValueAsInt64(pbSuccess);
1897 : }
1898 :
1899 : /************************************************************************/
1900 : /* GetNoDataValueAsUInt64() */
1901 : /************************************************************************/
1902 :
1903 : /**
1904 : * \brief Fetch the no data value for this band.
1905 : *
1906 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
1907 : *
1908 : * If there is no out of data value, an out of range value will generally
1909 : * be returned. The no data value for a band is generally a special marker
1910 : * value used to mark pixels that are not valid data. Such pixels should
1911 : * generally not be displayed, nor contribute to analysis operations.
1912 : *
1913 : * The no data value returned is 'raw', meaning that it has no offset and
1914 : * scale applied.
1915 : *
1916 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
1917 : *
1918 : * @param pbSuccess pointer to a boolean to use to indicate if a value
1919 : * is actually associated with this layer. May be NULL (default).
1920 : *
1921 : * @return the nodata value for this band.
1922 : *
1923 : * @since GDAL 3.5
1924 : */
1925 :
1926 2 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
1927 :
1928 : {
1929 2 : if (pbSuccess != nullptr)
1930 2 : *pbSuccess = FALSE;
1931 :
1932 2 : return std::numeric_limits<uint64_t>::max();
1933 : }
1934 :
1935 : /************************************************************************/
1936 : /* GDALGetRasterNoDataValueAsUInt64() */
1937 : /************************************************************************/
1938 :
1939 : /**
1940 : * \brief Fetch the no data value for this band.
1941 : *
1942 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
1943 : *
1944 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
1945 : *
1946 : * @since GDAL 3.5
1947 : */
1948 :
1949 17 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
1950 : int *pbSuccess)
1951 :
1952 : {
1953 17 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
1954 : std::numeric_limits<uint64_t>::max());
1955 :
1956 17 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1957 17 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
1958 : }
1959 :
1960 : /************************************************************************/
1961 : /* SetNoDataValue() */
1962 : /************************************************************************/
1963 :
1964 : /**
1965 : * \fn GDALRasterBand::SetNoDataValue(double)
1966 : * \brief Set the no data value for this band.
1967 : *
1968 : * Depending on drivers, changing the no data value may or may not have an
1969 : * effect on the pixel values of a raster that has just been created. It is
1970 : * thus advised to explicitly called Fill() if the intent is to initialize
1971 : * the raster to the nodata value.
1972 : * In any case, changing an existing no data value, when one already exists and
1973 : * the dataset exists or has been initialized, has no effect on the pixel whose
1974 : * value matched the previous nodata value.
1975 : *
1976 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
1977 : * be represented by a double, use SetNoDataValueAsInt64() or
1978 : * SetNoDataValueAsUInt64() instead.
1979 : *
1980 : * To clear the nodata value, use DeleteNoDataValue().
1981 : *
1982 : * This method is the same as the C function GDALSetRasterNoDataValue().
1983 : *
1984 : * @param dfNoData the value to set.
1985 : *
1986 : * @return CE_None on success, or CE_Failure on failure. If unsupported
1987 : * by the driver, CE_Failure is returned by no error message will have
1988 : * been emitted.
1989 : */
1990 :
1991 : /**/
1992 : /**/
1993 :
1994 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
1995 :
1996 : {
1997 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1998 0 : ReportError(CE_Failure, CPLE_NotSupported,
1999 : "SetNoDataValue() not supported for this dataset.");
2000 :
2001 0 : return CE_Failure;
2002 : }
2003 :
2004 : /************************************************************************/
2005 : /* GDALSetRasterNoDataValue() */
2006 : /************************************************************************/
2007 :
2008 : /**
2009 : * \brief Set the no data value for this band.
2010 : *
2011 : * Depending on drivers, changing the no data value may or may not have an
2012 : * effect on the pixel values of a raster that has just been created. It is
2013 : * thus advised to explicitly called Fill() if the intent is to initialize
2014 : * the raster to the nodata value.
2015 : * In any case, changing an existing no data value, when one already exists and
2016 : * the dataset exists or has been initialized, has no effect on the pixel whose
2017 : * value matched the previous nodata value.
2018 : *
2019 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2020 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2021 : * GDALSetRasterNoDataValueAsUInt64() instead.
2022 : *
2023 : * @see GDALRasterBand::SetNoDataValue()
2024 : */
2025 :
2026 556 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2027 : double dfValue)
2028 :
2029 : {
2030 556 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2031 :
2032 556 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2033 556 : return poBand->SetNoDataValue(dfValue);
2034 : }
2035 :
2036 : /************************************************************************/
2037 : /* SetNoDataValueAsInt64() */
2038 : /************************************************************************/
2039 :
2040 : /**
2041 : * \brief Set the no data value for this band.
2042 : *
2043 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2044 : *
2045 : * Depending on drivers, changing the no data value may or may not have an
2046 : * effect on the pixel values of a raster that has just been created. It is
2047 : * thus advised to explicitly called Fill() if the intent is to initialize
2048 : * the raster to the nodata value.
2049 : * In ay case, changing an existing no data value, when one already exists and
2050 : * the dataset exists or has been initialized, has no effect on the pixel whose
2051 : * value matched the previous nodata value.
2052 : *
2053 : * To clear the nodata value, use DeleteNoDataValue().
2054 : *
2055 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2056 : *
2057 : * @param nNoDataValue the value to set.
2058 : *
2059 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2060 : * by the driver, CE_Failure is returned by no error message will have
2061 : * been emitted.
2062 : *
2063 : * @since GDAL 3.5
2064 : */
2065 :
2066 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2067 :
2068 : {
2069 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2070 0 : ReportError(CE_Failure, CPLE_NotSupported,
2071 : "SetNoDataValueAsInt64() not supported for this dataset.");
2072 :
2073 0 : return CE_Failure;
2074 : }
2075 :
2076 : /************************************************************************/
2077 : /* GDALSetRasterNoDataValueAsInt64() */
2078 : /************************************************************************/
2079 :
2080 : /**
2081 : * \brief Set the no data value for this band.
2082 : *
2083 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2084 : *
2085 : * Depending on drivers, changing the no data value may or may not have an
2086 : * effect on the pixel values of a raster that has just been created. It is
2087 : * thus advised to explicitly called Fill() if the intent is to initialize
2088 : * the raster to the nodata value.
2089 : * In ay case, changing an existing no data value, when one already exists and
2090 : * the dataset exists or has been initialized, has no effect on the pixel whose
2091 : * value matched the previous nodata value.
2092 : *
2093 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2094 : *
2095 : * @since GDAL 3.5
2096 : */
2097 :
2098 11 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2099 : int64_t nValue)
2100 :
2101 : {
2102 11 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2103 :
2104 11 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2105 11 : return poBand->SetNoDataValueAsInt64(nValue);
2106 : }
2107 :
2108 : /************************************************************************/
2109 : /* SetNoDataValueAsUInt64() */
2110 : /************************************************************************/
2111 :
2112 : /**
2113 : * \brief Set the no data value for this band.
2114 : *
2115 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2116 : *
2117 : * Depending on drivers, changing the no data value may or may not have an
2118 : * effect on the pixel values of a raster that has just been created. It is
2119 : * thus advised to explicitly called Fill() if the intent is to initialize
2120 : * the raster to the nodata value.
2121 : * In ay case, changing an existing no data value, when one already exists and
2122 : * the dataset exists or has been initialized, has no effect on the pixel whose
2123 : * value matched the previous nodata value.
2124 : *
2125 : * To clear the nodata value, use DeleteNoDataValue().
2126 : *
2127 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2128 : *
2129 : * @param nNoDataValue the value to set.
2130 : *
2131 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2132 : * by the driver, CE_Failure is returned by no error message will have
2133 : * been emitted.
2134 : *
2135 : * @since GDAL 3.5
2136 : */
2137 :
2138 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2139 :
2140 : {
2141 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2142 0 : ReportError(CE_Failure, CPLE_NotSupported,
2143 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2144 :
2145 0 : return CE_Failure;
2146 : }
2147 :
2148 : /************************************************************************/
2149 : /* GDALSetRasterNoDataValueAsUInt64() */
2150 : /************************************************************************/
2151 :
2152 : /**
2153 : * \brief Set the no data value for this band.
2154 : *
2155 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2156 : *
2157 : * Depending on drivers, changing the no data value may or may not have an
2158 : * effect on the pixel values of a raster that has just been created. It is
2159 : * thus advised to explicitly called Fill() if the intent is to initialize
2160 : * the raster to the nodata value.
2161 : * In ay case, changing an existing no data value, when one already exists and
2162 : * the dataset exists or has been initialized, has no effect on the pixel whose
2163 : * value matched the previous nodata value.
2164 : *
2165 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2166 : *
2167 : * @since GDAL 3.5
2168 : */
2169 :
2170 10 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2171 : uint64_t nValue)
2172 :
2173 : {
2174 10 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2175 :
2176 10 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2177 10 : return poBand->SetNoDataValueAsUInt64(nValue);
2178 : }
2179 :
2180 : /************************************************************************/
2181 : /* DeleteNoDataValue() */
2182 : /************************************************************************/
2183 :
2184 : /**
2185 : * \brief Remove the no data value for this band.
2186 : *
2187 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2188 : *
2189 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2190 : * by the driver, CE_Failure is returned by no error message will have
2191 : * been emitted.
2192 : *
2193 : * @since GDAL 2.1
2194 : */
2195 :
2196 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2197 :
2198 : {
2199 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2200 0 : ReportError(CE_Failure, CPLE_NotSupported,
2201 : "DeleteNoDataValue() not supported for this dataset.");
2202 :
2203 0 : return CE_Failure;
2204 : }
2205 :
2206 : /************************************************************************/
2207 : /* GDALDeleteRasterNoDataValue() */
2208 : /************************************************************************/
2209 :
2210 : /**
2211 : * \brief Remove the no data value for this band.
2212 : *
2213 : * @see GDALRasterBand::DeleteNoDataValue()
2214 : *
2215 : * @since GDAL 2.1
2216 : */
2217 :
2218 35 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2219 :
2220 : {
2221 35 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2222 :
2223 35 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2224 35 : return poBand->DeleteNoDataValue();
2225 : }
2226 :
2227 : /************************************************************************/
2228 : /* GetMaximum() */
2229 : /************************************************************************/
2230 :
2231 : /**
2232 : * \brief Fetch the maximum value for this band.
2233 : *
2234 : * For file formats that don't know this intrinsically, the maximum supported
2235 : * value for the data type will generally be returned.
2236 : *
2237 : * This method is the same as the C function GDALGetRasterMaximum().
2238 : *
2239 : * @param pbSuccess pointer to a boolean to use to indicate if the
2240 : * returned value is a tight maximum or not. May be NULL (default).
2241 : *
2242 : * @return the maximum raster value (excluding no data pixels)
2243 : */
2244 :
2245 422 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2246 :
2247 : {
2248 422 : const char *pszValue = nullptr;
2249 :
2250 422 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2251 : {
2252 47 : if (pbSuccess != nullptr)
2253 42 : *pbSuccess = TRUE;
2254 :
2255 47 : return CPLAtofM(pszValue);
2256 : }
2257 :
2258 375 : if (pbSuccess != nullptr)
2259 343 : *pbSuccess = FALSE;
2260 :
2261 375 : switch (eDataType)
2262 : {
2263 269 : case GDT_Byte:
2264 : {
2265 269 : EnablePixelTypeSignedByteWarning(false);
2266 : const char *pszPixelType =
2267 269 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2268 269 : EnablePixelTypeSignedByteWarning(true);
2269 269 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2270 0 : return 127;
2271 :
2272 269 : return 255;
2273 : }
2274 :
2275 0 : case GDT_Int8:
2276 0 : return 127;
2277 :
2278 19 : case GDT_UInt16:
2279 19 : return 65535;
2280 :
2281 14 : case GDT_Int16:
2282 : case GDT_CInt16:
2283 14 : return 32767;
2284 :
2285 14 : case GDT_Int32:
2286 : case GDT_CInt32:
2287 14 : return 2147483647.0;
2288 :
2289 13 : case GDT_UInt32:
2290 13 : return 4294967295.0;
2291 :
2292 0 : case GDT_Int64:
2293 0 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2294 :
2295 0 : case GDT_UInt64:
2296 0 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2297 :
2298 26 : case GDT_Float32:
2299 : case GDT_CFloat32:
2300 26 : return 4294967295.0; // Not actually accurate.
2301 :
2302 20 : case GDT_Float64:
2303 : case GDT_CFloat64:
2304 20 : return 4294967295.0; // Not actually accurate.
2305 :
2306 0 : case GDT_Unknown:
2307 : case GDT_TypeCount:
2308 0 : break;
2309 : }
2310 0 : return 4294967295.0; // Not actually accurate.
2311 : }
2312 :
2313 : /************************************************************************/
2314 : /* GDALGetRasterMaximum() */
2315 : /************************************************************************/
2316 :
2317 : /**
2318 : * \brief Fetch the maximum value for this band.
2319 : *
2320 : * @see GDALRasterBand::GetMaximum()
2321 : */
2322 :
2323 183 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2324 :
2325 : {
2326 183 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2327 :
2328 183 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2329 183 : return poBand->GetMaximum(pbSuccess);
2330 : }
2331 :
2332 : /************************************************************************/
2333 : /* GetMinimum() */
2334 : /************************************************************************/
2335 :
2336 : /**
2337 : * \brief Fetch the minimum value for this band.
2338 : *
2339 : * For file formats that don't know this intrinsically, the minimum supported
2340 : * value for the data type will generally be returned.
2341 : *
2342 : * This method is the same as the C function GDALGetRasterMinimum().
2343 : *
2344 : * @param pbSuccess pointer to a boolean to use to indicate if the
2345 : * returned value is a tight minimum or not. May be NULL (default).
2346 : *
2347 : * @return the minimum raster value (excluding no data pixels)
2348 : */
2349 :
2350 429 : double GDALRasterBand::GetMinimum(int *pbSuccess)
2351 :
2352 : {
2353 429 : const char *pszValue = nullptr;
2354 :
2355 429 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
2356 : {
2357 52 : if (pbSuccess != nullptr)
2358 47 : *pbSuccess = TRUE;
2359 :
2360 52 : return CPLAtofM(pszValue);
2361 : }
2362 :
2363 377 : if (pbSuccess != nullptr)
2364 345 : *pbSuccess = FALSE;
2365 :
2366 377 : switch (eDataType)
2367 : {
2368 271 : case GDT_Byte:
2369 : {
2370 271 : EnablePixelTypeSignedByteWarning(false);
2371 : const char *pszPixelType =
2372 271 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2373 271 : EnablePixelTypeSignedByteWarning(true);
2374 271 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2375 0 : return -128;
2376 :
2377 271 : return 0;
2378 : }
2379 :
2380 0 : case GDT_Int8:
2381 0 : return -128;
2382 : break;
2383 :
2384 19 : case GDT_UInt16:
2385 19 : return 0;
2386 :
2387 14 : case GDT_Int16:
2388 : case GDT_CInt16:
2389 14 : return -32768;
2390 :
2391 14 : case GDT_Int32:
2392 : case GDT_CInt32:
2393 14 : return -2147483648.0;
2394 :
2395 13 : case GDT_UInt32:
2396 13 : return 0;
2397 :
2398 0 : case GDT_Int64:
2399 0 : return static_cast<double>(std::numeric_limits<GInt64>::min());
2400 :
2401 0 : case GDT_UInt64:
2402 0 : return 0;
2403 :
2404 26 : case GDT_Float32:
2405 : case GDT_CFloat32:
2406 26 : return -4294967295.0; // Not actually accurate.
2407 :
2408 20 : case GDT_Float64:
2409 : case GDT_CFloat64:
2410 20 : return -4294967295.0; // Not actually accurate.
2411 :
2412 0 : case GDT_Unknown:
2413 : case GDT_TypeCount:
2414 0 : break;
2415 : }
2416 0 : return -4294967295.0; // Not actually accurate.
2417 : }
2418 :
2419 : /************************************************************************/
2420 : /* GDALGetRasterMinimum() */
2421 : /************************************************************************/
2422 :
2423 : /**
2424 : * \brief Fetch the minimum value for this band.
2425 : *
2426 : * @see GDALRasterBand::GetMinimum()
2427 : */
2428 :
2429 191 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
2430 :
2431 : {
2432 191 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
2433 :
2434 191 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2435 191 : return poBand->GetMinimum(pbSuccess);
2436 : }
2437 :
2438 : /************************************************************************/
2439 : /* GetColorInterpretation() */
2440 : /************************************************************************/
2441 :
2442 : /**
2443 : * \brief How should this band be interpreted as color?
2444 : *
2445 : * GCI_Undefined is returned when the format doesn't know anything
2446 : * about the color interpretation.
2447 : *
2448 : * This method is the same as the C function
2449 : * GDALGetRasterColorInterpretation().
2450 : *
2451 : * @return color interpretation value for band.
2452 : */
2453 :
2454 107 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
2455 :
2456 : {
2457 107 : return GCI_Undefined;
2458 : }
2459 :
2460 : /************************************************************************/
2461 : /* GDALGetRasterColorInterpretation() */
2462 : /************************************************************************/
2463 :
2464 : /**
2465 : * \brief How should this band be interpreted as color?
2466 : *
2467 : * @see GDALRasterBand::GetColorInterpretation()
2468 : */
2469 :
2470 : GDALColorInterp CPL_STDCALL
2471 4637 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
2472 :
2473 : {
2474 4637 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
2475 :
2476 4637 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2477 4637 : return poBand->GetColorInterpretation();
2478 : }
2479 :
2480 : /************************************************************************/
2481 : /* SetColorInterpretation() */
2482 : /************************************************************************/
2483 :
2484 : /**
2485 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
2486 : * \brief Set color interpretation of a band.
2487 : *
2488 : * This method is the same as the C function GDALSetRasterColorInterpretation().
2489 : *
2490 : * @param eColorInterp the new color interpretation to apply to this band.
2491 : *
2492 : * @return CE_None on success or CE_Failure if method is unsupported by format.
2493 : */
2494 :
2495 : /**/
2496 : /**/
2497 :
2498 3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
2499 :
2500 : {
2501 3 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2502 3 : ReportError(CE_Failure, CPLE_NotSupported,
2503 : "SetColorInterpretation() not supported for this dataset.");
2504 3 : return CE_Failure;
2505 : }
2506 :
2507 : /************************************************************************/
2508 : /* GDALSetRasterColorInterpretation() */
2509 : /************************************************************************/
2510 :
2511 : /**
2512 : * \brief Set color interpretation of a band.
2513 : *
2514 : * @see GDALRasterBand::SetColorInterpretation()
2515 : */
2516 :
2517 1697 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
2518 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
2519 :
2520 : {
2521 1697 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
2522 :
2523 1697 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2524 1697 : return poBand->SetColorInterpretation(eColorInterp);
2525 : }
2526 :
2527 : /************************************************************************/
2528 : /* GetColorTable() */
2529 : /************************************************************************/
2530 :
2531 : /**
2532 : * \brief Fetch the color table associated with band.
2533 : *
2534 : * If there is no associated color table, the return result is NULL. The
2535 : * returned color table remains owned by the GDALRasterBand, and can't
2536 : * be depended on for long, nor should it ever be modified by the caller.
2537 : *
2538 : * This method is the same as the C function GDALGetRasterColorTable().
2539 : *
2540 : * @return internal color table, or NULL.
2541 : */
2542 :
2543 180 : GDALColorTable *GDALRasterBand::GetColorTable()
2544 :
2545 : {
2546 180 : return nullptr;
2547 : }
2548 :
2549 : /************************************************************************/
2550 : /* GDALGetRasterColorTable() */
2551 : /************************************************************************/
2552 :
2553 : /**
2554 : * \brief Fetch the color table associated with band.
2555 : *
2556 : * @see GDALRasterBand::GetColorTable()
2557 : */
2558 :
2559 1555 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
2560 :
2561 : {
2562 1555 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
2563 :
2564 1555 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2565 1555 : return GDALColorTable::ToHandle(poBand->GetColorTable());
2566 : }
2567 :
2568 : /************************************************************************/
2569 : /* SetColorTable() */
2570 : /************************************************************************/
2571 :
2572 : /**
2573 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
2574 : * \brief Set the raster color table.
2575 : *
2576 : * The driver will make a copy of all desired data in the colortable. It
2577 : * remains owned by the caller after the call.
2578 : *
2579 : * This method is the same as the C function GDALSetRasterColorTable().
2580 : *
2581 : * @param poCT the color table to apply. This may be NULL to clear the color
2582 : * table (where supported).
2583 : *
2584 : * @return CE_None on success, or CE_Failure on failure. If the action is
2585 : * unsupported by the driver, a value of CE_Failure is returned, but no
2586 : * error is issued.
2587 : */
2588 :
2589 : /**/
2590 : /**/
2591 :
2592 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
2593 :
2594 : {
2595 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2596 0 : ReportError(CE_Failure, CPLE_NotSupported,
2597 : "SetColorTable() not supported for this dataset.");
2598 0 : return CE_Failure;
2599 : }
2600 :
2601 : /************************************************************************/
2602 : /* GDALSetRasterColorTable() */
2603 : /************************************************************************/
2604 :
2605 : /**
2606 : * \brief Set the raster color table.
2607 : *
2608 : * @see GDALRasterBand::SetColorTable()
2609 : */
2610 :
2611 73 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
2612 : GDALColorTableH hCT)
2613 :
2614 : {
2615 73 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
2616 :
2617 73 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2618 73 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
2619 : }
2620 :
2621 : /************************************************************************/
2622 : /* HasArbitraryOverviews() */
2623 : /************************************************************************/
2624 :
2625 : /**
2626 : * \brief Check for arbitrary overviews.
2627 : *
2628 : * This returns TRUE if the underlying datastore can compute arbitrary
2629 : * overviews efficiently, such as is the case with OGDI over a network.
2630 : * Datastores with arbitrary overviews don't generally have any fixed
2631 : * overviews, but the RasterIO() method can be used in downsampling mode
2632 : * to get overview data efficiently.
2633 : *
2634 : * This method is the same as the C function GDALHasArbitraryOverviews(),
2635 : *
2636 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
2637 : * FALSE.
2638 : */
2639 :
2640 210 : int GDALRasterBand::HasArbitraryOverviews()
2641 :
2642 : {
2643 210 : return FALSE;
2644 : }
2645 :
2646 : /************************************************************************/
2647 : /* GDALHasArbitraryOverviews() */
2648 : /************************************************************************/
2649 :
2650 : /**
2651 : * \brief Check for arbitrary overviews.
2652 : *
2653 : * @see GDALRasterBand::HasArbitraryOverviews()
2654 : */
2655 :
2656 145 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
2657 :
2658 : {
2659 145 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
2660 :
2661 145 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2662 145 : return poBand->HasArbitraryOverviews();
2663 : }
2664 :
2665 : /************************************************************************/
2666 : /* GetOverviewCount() */
2667 : /************************************************************************/
2668 :
2669 : /**
2670 : * \brief Return the number of overview layers available.
2671 : *
2672 : * This method is the same as the C function GDALGetOverviewCount().
2673 : *
2674 : * @return overview count, zero if none.
2675 : */
2676 :
2677 659467 : int GDALRasterBand::GetOverviewCount()
2678 :
2679 : {
2680 1314070 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
2681 654604 : poDS->AreOverviewsEnabled())
2682 654604 : return poDS->oOvManager.GetOverviewCount(nBand);
2683 :
2684 4863 : return 0;
2685 : }
2686 :
2687 : /************************************************************************/
2688 : /* GDALGetOverviewCount() */
2689 : /************************************************************************/
2690 :
2691 : /**
2692 : * \brief Return the number of overview layers available.
2693 : *
2694 : * @see GDALRasterBand::GetOverviewCount()
2695 : */
2696 :
2697 3133 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
2698 :
2699 : {
2700 3133 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
2701 :
2702 3133 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2703 3133 : return poBand->GetOverviewCount();
2704 : }
2705 :
2706 : /************************************************************************/
2707 : /* GetOverview() */
2708 : /************************************************************************/
2709 :
2710 : /**
2711 : * \brief Fetch overview raster band object.
2712 : *
2713 : * This method is the same as the C function GDALGetOverview().
2714 : *
2715 : * @param i overview index between 0 and GetOverviewCount()-1.
2716 : *
2717 : * @return overview GDALRasterBand.
2718 : */
2719 :
2720 795 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
2721 :
2722 : {
2723 1536 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
2724 741 : poDS->AreOverviewsEnabled())
2725 741 : return poDS->oOvManager.GetOverview(nBand, i);
2726 :
2727 54 : return nullptr;
2728 : }
2729 :
2730 : /************************************************************************/
2731 : /* GDALGetOverview() */
2732 : /************************************************************************/
2733 :
2734 : /**
2735 : * \brief Fetch overview raster band object.
2736 : *
2737 : * @see GDALRasterBand::GetOverview()
2738 : */
2739 :
2740 1361 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
2741 :
2742 : {
2743 1361 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
2744 :
2745 1361 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2746 1361 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
2747 : }
2748 :
2749 : /************************************************************************/
2750 : /* GetRasterSampleOverview() */
2751 : /************************************************************************/
2752 :
2753 : /**
2754 : * \brief Fetch best sampling overview.
2755 : *
2756 : * Returns the most reduced overview of the given band that still satisfies
2757 : * the desired number of samples. This function can be used with zero
2758 : * as the number of desired samples to fetch the most reduced overview.
2759 : * The same band as was passed in will be returned if it has not overviews,
2760 : * or if none of the overviews have enough samples.
2761 : *
2762 : * This method is the same as the C functions GDALGetRasterSampleOverview()
2763 : * and GDALGetRasterSampleOverviewEx().
2764 : *
2765 : * @param nDesiredSamples the returned band will have at least this many
2766 : * pixels.
2767 : *
2768 : * @return optimal overview or the band itself.
2769 : */
2770 :
2771 : GDALRasterBand *
2772 6 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
2773 :
2774 : {
2775 6 : GDALRasterBand *poBestBand = this;
2776 :
2777 6 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
2778 :
2779 23 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
2780 : {
2781 17 : GDALRasterBand *poOBand = GetOverview(iOverview);
2782 :
2783 17 : if (poOBand == nullptr)
2784 0 : continue;
2785 :
2786 : const double dfOSamples =
2787 17 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
2788 :
2789 17 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
2790 : {
2791 14 : dfBestSamples = dfOSamples;
2792 14 : poBestBand = poOBand;
2793 : }
2794 : }
2795 :
2796 6 : return poBestBand;
2797 : }
2798 :
2799 : /************************************************************************/
2800 : /* GDALGetRasterSampleOverview() */
2801 : /************************************************************************/
2802 :
2803 : /**
2804 : * \brief Fetch best sampling overview.
2805 : *
2806 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
2807 : * billion samples.
2808 : *
2809 : * @see GDALRasterBand::GetRasterSampleOverview()
2810 : * @see GDALGetRasterSampleOverviewEx()
2811 : */
2812 :
2813 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
2814 : int nDesiredSamples)
2815 :
2816 : {
2817 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
2818 :
2819 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2820 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
2821 0 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
2822 : }
2823 :
2824 : /************************************************************************/
2825 : /* GDALGetRasterSampleOverviewEx() */
2826 : /************************************************************************/
2827 :
2828 : /**
2829 : * \brief Fetch best sampling overview.
2830 : *
2831 : * @see GDALRasterBand::GetRasterSampleOverview()
2832 : * @since GDAL 2.0
2833 : */
2834 :
2835 : GDALRasterBandH CPL_STDCALL
2836 0 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
2837 :
2838 : {
2839 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
2840 :
2841 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2842 0 : return GDALRasterBand::ToHandle(
2843 0 : poBand->GetRasterSampleOverview(nDesiredSamples));
2844 : }
2845 :
2846 : /************************************************************************/
2847 : /* BuildOverviews() */
2848 : /************************************************************************/
2849 :
2850 : /**
2851 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
2852 : * GDALProgressFunc, void*) \brief Build raster overview(s)
2853 : *
2854 : * If the operation is unsupported for the indicated dataset, then
2855 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
2856 : * CPLE_NotSupported.
2857 : *
2858 : * WARNING: It is not possible to build overviews for a single band in
2859 : * TIFF format, and thus this method does not work for TIFF format, or any
2860 : * formats that use the default overview building in TIFF format. Instead
2861 : * it is necessary to build overviews on the dataset as a whole using
2862 : * GDALDataset::BuildOverviews(). That makes this method pretty useless
2863 : * from a practical point of view.
2864 : *
2865 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
2866 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
2867 : * applied.
2868 : * @param nOverviews number of overviews to build.
2869 : * @param panOverviewList the list of overview decimation factors to build.
2870 : * @param pfnProgress a function to call to report progress, or NULL.
2871 : * @param pProgressData application data to pass to the progress function.
2872 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
2873 : * key=value pairs, or NULL
2874 : *
2875 : * @return CE_None on success or CE_Failure if the operation doesn't work.
2876 : */
2877 :
2878 : /**/
2879 : /**/
2880 :
2881 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
2882 : int /*nOverviews*/,
2883 : const int * /*panOverviewList*/,
2884 : GDALProgressFunc /*pfnProgress*/,
2885 : void * /*pProgressData*/,
2886 : CSLConstList /* papszOptions */)
2887 :
2888 : {
2889 0 : ReportError(CE_Failure, CPLE_NotSupported,
2890 : "BuildOverviews() not supported for this dataset.");
2891 :
2892 0 : return (CE_Failure);
2893 : }
2894 :
2895 : /************************************************************************/
2896 : /* GetOffset() */
2897 : /************************************************************************/
2898 :
2899 : /**
2900 : * \brief Fetch the raster value offset.
2901 : *
2902 : * This value (in combination with the GetScale() value) can be used to
2903 : * transform raw pixel values into the units returned by GetUnitType().
2904 : * For example this might be used to store elevations in GUInt16 bands
2905 : * with a precision of 0.1, and starting from -100.
2906 : *
2907 : * Units value = (raw value * scale) + offset
2908 : *
2909 : * Note that applying scale and offset is of the responsibility of the user,
2910 : * and is not done by methods such as RasterIO() or ReadBlock().
2911 : *
2912 : * For file formats that don't know this intrinsically a value of zero
2913 : * is returned.
2914 : *
2915 : * This method is the same as the C function GDALGetRasterOffset().
2916 : *
2917 : * @param pbSuccess pointer to a boolean to use to indicate if the
2918 : * returned value is meaningful or not. May be NULL (default).
2919 : *
2920 : * @return the raster offset.
2921 : */
2922 :
2923 363 : double GDALRasterBand::GetOffset(int *pbSuccess)
2924 :
2925 : {
2926 363 : if (pbSuccess != nullptr)
2927 315 : *pbSuccess = FALSE;
2928 :
2929 363 : return 0.0;
2930 : }
2931 :
2932 : /************************************************************************/
2933 : /* GDALGetRasterOffset() */
2934 : /************************************************************************/
2935 :
2936 : /**
2937 : * \brief Fetch the raster value offset.
2938 : *
2939 : * @see GDALRasterBand::GetOffset()
2940 : */
2941 :
2942 266 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
2943 :
2944 : {
2945 266 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
2946 :
2947 266 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2948 266 : return poBand->GetOffset(pbSuccess);
2949 : }
2950 :
2951 : /************************************************************************/
2952 : /* SetOffset() */
2953 : /************************************************************************/
2954 :
2955 : /**
2956 : * \fn GDALRasterBand::SetOffset(double)
2957 : * \brief Set scaling offset.
2958 : *
2959 : * Very few formats implement this method. When not implemented it will
2960 : * issue a CPLE_NotSupported error and return CE_Failure.
2961 : *
2962 : * This method is the same as the C function GDALSetRasterOffset().
2963 : *
2964 : * @param dfNewOffset the new offset.
2965 : *
2966 : * @return CE_None or success or CE_Failure on failure.
2967 : */
2968 :
2969 : /**/
2970 : /**/
2971 :
2972 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
2973 : {
2974 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2975 0 : ReportError(CE_Failure, CPLE_NotSupported,
2976 : "SetOffset() not supported on this raster band.");
2977 :
2978 0 : return CE_Failure;
2979 : }
2980 :
2981 : /************************************************************************/
2982 : /* GDALSetRasterOffset() */
2983 : /************************************************************************/
2984 :
2985 : /**
2986 : * \brief Set scaling offset.
2987 : *
2988 : * @see GDALRasterBand::SetOffset()
2989 : */
2990 :
2991 41 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
2992 : double dfNewOffset)
2993 :
2994 : {
2995 41 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
2996 :
2997 41 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2998 41 : return poBand->SetOffset(dfNewOffset);
2999 : }
3000 :
3001 : /************************************************************************/
3002 : /* GetScale() */
3003 : /************************************************************************/
3004 :
3005 : /**
3006 : * \brief Fetch the raster value scale.
3007 : *
3008 : * This value (in combination with the GetOffset() value) can be used to
3009 : * transform raw pixel values into the units returned by GetUnitType().
3010 : * For example this might be used to store elevations in GUInt16 bands
3011 : * with a precision of 0.1, and starting from -100.
3012 : *
3013 : * Units value = (raw value * scale) + offset
3014 : *
3015 : * Note that applying scale and offset is of the responsibility of the user,
3016 : * and is not done by methods such as RasterIO() or ReadBlock().
3017 : *
3018 : * For file formats that don't know this intrinsically a value of one
3019 : * is returned.
3020 : *
3021 : * This method is the same as the C function GDALGetRasterScale().
3022 : *
3023 : * @param pbSuccess pointer to a boolean to use to indicate if the
3024 : * returned value is meaningful or not. May be NULL (default).
3025 : *
3026 : * @return the raster scale.
3027 : */
3028 :
3029 363 : double GDALRasterBand::GetScale(int *pbSuccess)
3030 :
3031 : {
3032 363 : if (pbSuccess != nullptr)
3033 315 : *pbSuccess = FALSE;
3034 :
3035 363 : return 1.0;
3036 : }
3037 :
3038 : /************************************************************************/
3039 : /* GDALGetRasterScale() */
3040 : /************************************************************************/
3041 :
3042 : /**
3043 : * \brief Fetch the raster value scale.
3044 : *
3045 : * @see GDALRasterBand::GetScale()
3046 : */
3047 :
3048 265 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3049 :
3050 : {
3051 265 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3052 :
3053 265 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3054 265 : return poBand->GetScale(pbSuccess);
3055 : }
3056 :
3057 : /************************************************************************/
3058 : /* SetScale() */
3059 : /************************************************************************/
3060 :
3061 : /**
3062 : * \fn GDALRasterBand::SetScale(double)
3063 : * \brief Set scaling ratio.
3064 : *
3065 : * Very few formats implement this method. When not implemented it will
3066 : * issue a CPLE_NotSupported error and return CE_Failure.
3067 : *
3068 : * This method is the same as the C function GDALSetRasterScale().
3069 : *
3070 : * @param dfNewScale the new scale.
3071 : *
3072 : * @return CE_None or success or CE_Failure on failure.
3073 : */
3074 :
3075 : /**/
3076 : /**/
3077 :
3078 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3079 :
3080 : {
3081 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3082 0 : ReportError(CE_Failure, CPLE_NotSupported,
3083 : "SetScale() not supported on this raster band.");
3084 :
3085 0 : return CE_Failure;
3086 : }
3087 :
3088 : /************************************************************************/
3089 : /* GDALSetRasterScale() */
3090 : /************************************************************************/
3091 :
3092 : /**
3093 : * \brief Set scaling ratio.
3094 : *
3095 : * @see GDALRasterBand::SetScale()
3096 : */
3097 :
3098 42 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3099 :
3100 : {
3101 42 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3102 :
3103 42 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3104 42 : return poBand->SetScale(dfNewOffset);
3105 : }
3106 :
3107 : /************************************************************************/
3108 : /* GetUnitType() */
3109 : /************************************************************************/
3110 :
3111 : /**
3112 : * \brief Return raster unit type.
3113 : *
3114 : * Return a name for the units of this raster's values. For instance, it
3115 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3116 : * units are available, a value of "" will be returned. The returned string
3117 : * should not be modified, nor freed by the calling application.
3118 : *
3119 : * This method is the same as the C function GDALGetRasterUnitType().
3120 : *
3121 : * @return unit name string.
3122 : */
3123 :
3124 155 : const char *GDALRasterBand::GetUnitType()
3125 :
3126 : {
3127 155 : return "";
3128 : }
3129 :
3130 : /************************************************************************/
3131 : /* GDALGetRasterUnitType() */
3132 : /************************************************************************/
3133 :
3134 : /**
3135 : * \brief Return raster unit type.
3136 : *
3137 : * @see GDALRasterBand::GetUnitType()
3138 : */
3139 :
3140 1220 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3141 :
3142 : {
3143 1220 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3144 :
3145 1220 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3146 1220 : return poBand->GetUnitType();
3147 : }
3148 :
3149 : /************************************************************************/
3150 : /* SetUnitType() */
3151 : /************************************************************************/
3152 :
3153 : /**
3154 : * \fn GDALRasterBand::SetUnitType(const char*)
3155 : * \brief Set unit type.
3156 : *
3157 : * Set the unit type for a raster band. Values should be one of
3158 : * "" (the default indicating it is unknown), "m" indicating meters,
3159 : * or "ft" indicating feet, though other nonstandard values are allowed.
3160 : *
3161 : * This method is the same as the C function GDALSetRasterUnitType().
3162 : *
3163 : * @param pszNewValue the new unit type value.
3164 : *
3165 : * @return CE_None on success or CE_Failure if not successful, or
3166 : * unsupported.
3167 : */
3168 :
3169 : /**/
3170 : /**/
3171 :
3172 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3173 :
3174 : {
3175 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3176 0 : ReportError(CE_Failure, CPLE_NotSupported,
3177 : "SetUnitType() not supported on this raster band.");
3178 0 : return CE_Failure;
3179 : }
3180 :
3181 : /************************************************************************/
3182 : /* GDALSetRasterUnitType() */
3183 : /************************************************************************/
3184 :
3185 : /**
3186 : * \brief Set unit type.
3187 : *
3188 : * @see GDALRasterBand::SetUnitType()
3189 : *
3190 : * @since GDAL 1.8.0
3191 : */
3192 :
3193 53 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3194 : const char *pszNewValue)
3195 :
3196 : {
3197 53 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3198 :
3199 53 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3200 53 : return poBand->SetUnitType(pszNewValue);
3201 : }
3202 :
3203 : /************************************************************************/
3204 : /* GetXSize() */
3205 : /************************************************************************/
3206 :
3207 : /**
3208 : * \brief Fetch XSize of raster.
3209 : *
3210 : * This method is the same as the C function GDALGetRasterBandXSize().
3211 : *
3212 : * @return the width in pixels of this band.
3213 : */
3214 :
3215 3483580 : int GDALRasterBand::GetXSize()
3216 :
3217 : {
3218 3483580 : return nRasterXSize;
3219 : }
3220 :
3221 : /************************************************************************/
3222 : /* GDALGetRasterBandXSize() */
3223 : /************************************************************************/
3224 :
3225 : /**
3226 : * \brief Fetch XSize of raster.
3227 : *
3228 : * @see GDALRasterBand::GetXSize()
3229 : */
3230 :
3231 23506 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3232 :
3233 : {
3234 23506 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3235 :
3236 23506 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3237 23506 : return poBand->GetXSize();
3238 : }
3239 :
3240 : /************************************************************************/
3241 : /* GetYSize() */
3242 : /************************************************************************/
3243 :
3244 : /**
3245 : * \brief Fetch YSize of raster.
3246 : *
3247 : * This method is the same as the C function GDALGetRasterBandYSize().
3248 : *
3249 : * @return the height in pixels of this band.
3250 : */
3251 :
3252 416359 : int GDALRasterBand::GetYSize()
3253 :
3254 : {
3255 416359 : return nRasterYSize;
3256 : }
3257 :
3258 : /************************************************************************/
3259 : /* GDALGetRasterBandYSize() */
3260 : /************************************************************************/
3261 :
3262 : /**
3263 : * \brief Fetch YSize of raster.
3264 : *
3265 : * @see GDALRasterBand::GetYSize()
3266 : */
3267 :
3268 22883 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3269 :
3270 : {
3271 22883 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3272 :
3273 22883 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3274 22883 : return poBand->GetYSize();
3275 : }
3276 :
3277 : /************************************************************************/
3278 : /* GetBand() */
3279 : /************************************************************************/
3280 :
3281 : /**
3282 : * \brief Fetch the band number.
3283 : *
3284 : * This method returns the band that this GDALRasterBand objects represents
3285 : * within its dataset. This method may return a value of 0 to indicate
3286 : * GDALRasterBand objects without an apparently relationship to a dataset,
3287 : * such as GDALRasterBands serving as overviews.
3288 : *
3289 : * This method is the same as the C function GDALGetBandNumber().
3290 : *
3291 : * @return band number (1+) or 0 if the band number isn't known.
3292 : */
3293 :
3294 14743 : int GDALRasterBand::GetBand()
3295 :
3296 : {
3297 14743 : return nBand;
3298 : }
3299 :
3300 : /************************************************************************/
3301 : /* GDALGetBandNumber() */
3302 : /************************************************************************/
3303 :
3304 : /**
3305 : * \brief Fetch the band number.
3306 : *
3307 : * @see GDALRasterBand::GetBand()
3308 : */
3309 :
3310 129 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3311 :
3312 : {
3313 129 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3314 :
3315 129 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3316 129 : return poBand->GetBand();
3317 : }
3318 :
3319 : /************************************************************************/
3320 : /* GetDataset() */
3321 : /************************************************************************/
3322 :
3323 : /**
3324 : * \brief Fetch the owning dataset handle.
3325 : *
3326 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3327 : * such as overviews or other "freestanding" bands.
3328 : *
3329 : * This method is the same as the C function GDALGetBandDataset().
3330 : *
3331 : * @return the pointer to the GDALDataset to which this band belongs, or
3332 : * NULL if this cannot be determined.
3333 : */
3334 :
3335 3606310 : GDALDataset *GDALRasterBand::GetDataset()
3336 :
3337 : {
3338 3606310 : return poDS;
3339 : }
3340 :
3341 : /************************************************************************/
3342 : /* GDALGetBandDataset() */
3343 : /************************************************************************/
3344 :
3345 : /**
3346 : * \brief Fetch the owning dataset handle.
3347 : *
3348 : * @see GDALRasterBand::GetDataset()
3349 : */
3350 :
3351 301 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
3352 :
3353 : {
3354 301 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
3355 :
3356 301 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3357 301 : return GDALDataset::ToHandle(poBand->GetDataset());
3358 : }
3359 :
3360 : /************************************************************************/
3361 : /* ComputeFloatNoDataValue() */
3362 : /************************************************************************/
3363 :
3364 1948 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
3365 : double dfNoDataValue,
3366 : int &bGotNoDataValue,
3367 : float &fNoDataValue,
3368 : bool &bGotFloatNoDataValue)
3369 : {
3370 1948 : if (eDataType == GDT_Float32 && bGotNoDataValue)
3371 : {
3372 77 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
3373 77 : if (GDALIsValueInRange<float>(dfNoDataValue))
3374 : {
3375 77 : fNoDataValue = static_cast<float>(dfNoDataValue);
3376 77 : bGotFloatNoDataValue = true;
3377 77 : bGotNoDataValue = false;
3378 : }
3379 : }
3380 1948 : }
3381 :
3382 : /************************************************************************/
3383 : /* GetHistogram() */
3384 : /************************************************************************/
3385 :
3386 : /**
3387 : * \brief Compute raster histogram.
3388 : *
3389 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
3390 : *
3391 : * For example to compute a simple 256 entry histogram of eight bit data,
3392 : * the following would be suitable. The unusual bounds are to ensure that
3393 : * bucket boundaries don't fall right on integer values causing possible errors
3394 : * due to rounding after scaling.
3395 : \code{.cpp}
3396 : GUIntBig anHistogram[256];
3397 :
3398 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
3399 : GDALDummyProgress, nullptr );
3400 : \endcode
3401 : *
3402 : * Note that setting bApproxOK will generally result in a subsampling of the
3403 : * file, and will utilize overviews if available. It should generally
3404 : * produce a representative histogram for the data that is suitable for use
3405 : * in generating histogram based luts for instance. Generally bApproxOK is
3406 : * much faster than an exactly computed histogram.
3407 : *
3408 : * This method is the same as the C functions GDALGetRasterHistogram() and
3409 : * GDALGetRasterHistogramEx().
3410 : *
3411 : * @param dfMin the lower bound of the histogram.
3412 : * @param dfMax the upper bound of the histogram.
3413 : * @param nBuckets the number of buckets in panHistogram.
3414 : * @param panHistogram array into which the histogram totals are placed.
3415 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
3416 : * mapped into panHistogram[0], and values above will be mapped into
3417 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
3418 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
3419 : * @param pfnProgress function to report progress to completion.
3420 : * @param pProgressData application data to pass to pfnProgress.
3421 : *
3422 : * @return CE_None on success, or CE_Failure if something goes wrong.
3423 : */
3424 :
3425 35 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
3426 : GUIntBig *panHistogram,
3427 : int bIncludeOutOfRange, int bApproxOK,
3428 : GDALProgressFunc pfnProgress,
3429 : void *pProgressData)
3430 :
3431 : {
3432 35 : CPLAssert(nullptr != panHistogram);
3433 :
3434 35 : if (pfnProgress == nullptr)
3435 26 : pfnProgress = GDALDummyProgress;
3436 :
3437 : /* -------------------------------------------------------------------- */
3438 : /* If we have overviews, use them for the histogram. */
3439 : /* -------------------------------------------------------------------- */
3440 35 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
3441 : {
3442 : // FIXME: should we use the most reduced overview here or use some
3443 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
3444 : // does?
3445 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
3446 :
3447 0 : if (poBestOverview != this)
3448 : {
3449 0 : return poBestOverview->GetHistogram(
3450 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
3451 0 : bApproxOK, pfnProgress, pProgressData);
3452 : }
3453 : }
3454 :
3455 : /* -------------------------------------------------------------------- */
3456 : /* Read actual data and build histogram. */
3457 : /* -------------------------------------------------------------------- */
3458 35 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
3459 : {
3460 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3461 0 : return CE_Failure;
3462 : }
3463 :
3464 : // Written this way to deal with NaN
3465 35 : if (!(dfMax > dfMin))
3466 : {
3467 5 : ReportError(CE_Failure, CPLE_IllegalArg,
3468 : "dfMax should be strictly greater than dfMin");
3469 5 : return CE_Failure;
3470 : }
3471 :
3472 : GDALRasterIOExtraArg sExtraArg;
3473 30 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3474 :
3475 30 : const double dfScale = nBuckets / (dfMax - dfMin);
3476 30 : if (dfScale == 0 || !std::isfinite(dfScale))
3477 : {
3478 5 : ReportError(CE_Failure, CPLE_IllegalArg,
3479 : "dfMin and dfMax should be finite values such that "
3480 : "nBuckets / (dfMax - dfMin) is non-zero");
3481 5 : return CE_Failure;
3482 : }
3483 25 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
3484 :
3485 25 : int bGotNoDataValue = FALSE;
3486 25 : const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
3487 25 : bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
3488 25 : bool bGotFloatNoDataValue = false;
3489 25 : float fNoDataValue = 0.0f;
3490 25 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
3491 : fNoDataValue, bGotFloatNoDataValue);
3492 25 : GDALRasterBand *poMaskBand = nullptr;
3493 25 : if (!bGotNoDataValue)
3494 : {
3495 24 : const int l_nMaskFlags = GetMaskFlags();
3496 25 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
3497 1 : GetColorInterpretation() != GCI_AlphaBand)
3498 : {
3499 1 : poMaskBand = GetMaskBand();
3500 : }
3501 : }
3502 :
3503 25 : bool bSignedByte = false;
3504 25 : if (eDataType == GDT_Byte)
3505 : {
3506 18 : EnablePixelTypeSignedByteWarning(false);
3507 : const char *pszPixelType =
3508 18 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3509 18 : EnablePixelTypeSignedByteWarning(true);
3510 18 : bSignedByte =
3511 18 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
3512 : }
3513 :
3514 25 : if (bApproxOK && HasArbitraryOverviews())
3515 : {
3516 : /* --------------------------------------------------------------------
3517 : */
3518 : /* Figure out how much the image should be reduced to get an */
3519 : /* approximate value. */
3520 : /* --------------------------------------------------------------------
3521 : */
3522 : const double dfReduction =
3523 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
3524 : GDALSTAT_APPROX_NUMSAMPLES);
3525 :
3526 0 : int nXReduced = nRasterXSize;
3527 0 : int nYReduced = nRasterYSize;
3528 0 : if (dfReduction > 1.0)
3529 : {
3530 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
3531 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
3532 :
3533 : // Catch the case of huge resizing ratios here
3534 0 : if (nXReduced == 0)
3535 0 : nXReduced = 1;
3536 0 : if (nYReduced == 0)
3537 0 : nYReduced = 1;
3538 : }
3539 :
3540 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
3541 : nXReduced, nYReduced);
3542 0 : if (!pData)
3543 0 : return CE_Failure;
3544 :
3545 : const CPLErr eErr =
3546 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
3547 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
3548 0 : if (eErr != CE_None)
3549 : {
3550 0 : CPLFree(pData);
3551 0 : return eErr;
3552 : }
3553 :
3554 0 : GByte *pabyMaskData = nullptr;
3555 0 : if (poMaskBand)
3556 : {
3557 : pabyMaskData =
3558 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
3559 0 : if (!pabyMaskData)
3560 : {
3561 0 : CPLFree(pData);
3562 0 : return CE_Failure;
3563 : }
3564 :
3565 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
3566 : pabyMaskData, nXReduced, nYReduced,
3567 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
3568 : {
3569 0 : CPLFree(pData);
3570 0 : CPLFree(pabyMaskData);
3571 0 : return CE_Failure;
3572 : }
3573 : }
3574 :
3575 : // This isn't the fastest way to do this, but is easier for now.
3576 0 : for (int iY = 0; iY < nYReduced; iY++)
3577 : {
3578 0 : for (int iX = 0; iX < nXReduced; iX++)
3579 : {
3580 0 : const int iOffset = iX + iY * nXReduced;
3581 0 : double dfValue = 0.0;
3582 :
3583 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
3584 0 : continue;
3585 :
3586 0 : switch (eDataType)
3587 : {
3588 0 : case GDT_Byte:
3589 : {
3590 0 : if (bSignedByte)
3591 0 : dfValue =
3592 0 : static_cast<signed char *>(pData)[iOffset];
3593 : else
3594 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
3595 0 : break;
3596 : }
3597 0 : case GDT_Int8:
3598 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
3599 0 : break;
3600 0 : case GDT_UInt16:
3601 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
3602 0 : break;
3603 0 : case GDT_Int16:
3604 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
3605 0 : break;
3606 0 : case GDT_UInt32:
3607 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
3608 0 : break;
3609 0 : case GDT_Int32:
3610 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
3611 0 : break;
3612 0 : case GDT_UInt64:
3613 0 : dfValue = static_cast<double>(
3614 0 : static_cast<GUInt64 *>(pData)[iOffset]);
3615 0 : break;
3616 0 : case GDT_Int64:
3617 0 : dfValue = static_cast<double>(
3618 0 : static_cast<GInt64 *>(pData)[iOffset]);
3619 0 : break;
3620 0 : case GDT_Float32:
3621 : {
3622 0 : const float fValue =
3623 0 : static_cast<float *>(pData)[iOffset];
3624 0 : if (CPLIsNan(fValue) ||
3625 0 : (bGotFloatNoDataValue &&
3626 0 : ARE_REAL_EQUAL(fValue, fNoDataValue)))
3627 0 : continue;
3628 0 : dfValue = fValue;
3629 0 : break;
3630 : }
3631 0 : case GDT_Float64:
3632 0 : dfValue = static_cast<double *>(pData)[iOffset];
3633 0 : if (CPLIsNan(dfValue))
3634 0 : continue;
3635 0 : break;
3636 0 : case GDT_CInt16:
3637 : {
3638 0 : const double dfReal =
3639 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
3640 0 : const double dfImag =
3641 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
3642 0 : if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
3643 0 : continue;
3644 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
3645 : }
3646 0 : break;
3647 0 : case GDT_CInt32:
3648 : {
3649 0 : const double dfReal =
3650 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
3651 0 : const double dfImag =
3652 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
3653 0 : if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
3654 0 : continue;
3655 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
3656 : }
3657 0 : break;
3658 0 : case GDT_CFloat32:
3659 : {
3660 0 : const double dfReal =
3661 0 : static_cast<float *>(pData)[iOffset * 2];
3662 0 : const double dfImag =
3663 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
3664 0 : if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
3665 0 : continue;
3666 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
3667 : }
3668 0 : break;
3669 0 : case GDT_CFloat64:
3670 : {
3671 0 : const double dfReal =
3672 0 : static_cast<double *>(pData)[iOffset * 2];
3673 0 : const double dfImag =
3674 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
3675 0 : if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
3676 0 : continue;
3677 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
3678 : }
3679 0 : break;
3680 0 : case GDT_Unknown:
3681 : case GDT_TypeCount:
3682 0 : CPLAssert(false);
3683 : }
3684 :
3685 0 : if (eDataType != GDT_Float32 && bGotNoDataValue &&
3686 0 : ARE_REAL_EQUAL(dfValue, dfNoDataValue))
3687 0 : continue;
3688 :
3689 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
3690 : // finite, the result of the multiplication cannot be NaN
3691 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
3692 :
3693 0 : if (dfIndex < 0)
3694 : {
3695 0 : if (bIncludeOutOfRange)
3696 0 : panHistogram[0]++;
3697 : }
3698 0 : else if (dfIndex >= nBuckets)
3699 : {
3700 0 : if (bIncludeOutOfRange)
3701 0 : ++panHistogram[nBuckets - 1];
3702 : }
3703 : else
3704 : {
3705 0 : ++panHistogram[static_cast<int>(dfIndex)];
3706 : }
3707 : }
3708 : }
3709 :
3710 0 : CPLFree(pData);
3711 0 : CPLFree(pabyMaskData);
3712 : }
3713 : else // No arbitrary overviews.
3714 : {
3715 25 : if (!InitBlockInfo())
3716 0 : return CE_Failure;
3717 :
3718 : /* --------------------------------------------------------------------
3719 : */
3720 : /* Figure out the ratio of blocks we will read to get an */
3721 : /* approximate value. */
3722 : /* --------------------------------------------------------------------
3723 : */
3724 :
3725 25 : int nSampleRate = 1;
3726 25 : if (bApproxOK)
3727 : {
3728 8 : nSampleRate = static_cast<int>(std::max(
3729 16 : 1.0,
3730 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
3731 : // We want to avoid probing only the first column of blocks for
3732 : // a square shaped raster, because it is not unlikely that it may
3733 : // be padding only (#6378).
3734 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
3735 2 : nSampleRate += 1;
3736 : }
3737 :
3738 25 : GByte *pabyMaskData = nullptr;
3739 25 : if (poMaskBand)
3740 : {
3741 : pabyMaskData = static_cast<GByte *>(
3742 1 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
3743 1 : if (!pabyMaskData)
3744 : {
3745 0 : return CE_Failure;
3746 : }
3747 : }
3748 :
3749 : /* --------------------------------------------------------------------
3750 : */
3751 : /* Read the blocks, and add to histogram. */
3752 : /* --------------------------------------------------------------------
3753 : */
3754 25 : for (int iSampleBlock = 0;
3755 109 : iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
3756 84 : iSampleBlock += nSampleRate)
3757 : {
3758 84 : if (!pfnProgress(
3759 : iSampleBlock /
3760 84 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
3761 : "Compute Histogram", pProgressData))
3762 : {
3763 0 : CPLFree(pabyMaskData);
3764 0 : return CE_Failure;
3765 : }
3766 :
3767 84 : const int iYBlock = iSampleBlock / nBlocksPerRow;
3768 84 : const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
3769 :
3770 84 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
3771 84 : if (poBlock == nullptr)
3772 : {
3773 0 : CPLFree(pabyMaskData);
3774 0 : return CE_Failure;
3775 : }
3776 :
3777 84 : void *pData = poBlock->GetDataRef();
3778 :
3779 84 : int nXCheck = 0, nYCheck = 0;
3780 84 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
3781 :
3782 85 : if (poMaskBand &&
3783 1 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
3784 1 : iYBlock * nBlockYSize, nXCheck, nYCheck,
3785 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
3786 1 : 0, nBlockXSize, nullptr) != CE_None)
3787 : {
3788 0 : CPLFree(pabyMaskData);
3789 0 : poBlock->DropLock();
3790 0 : return CE_Failure;
3791 : }
3792 :
3793 : // this is a special case for a common situation.
3794 84 : if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
3795 62 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
3796 59 : nXCheck == nBlockXSize && nBuckets == 256)
3797 : {
3798 59 : const GPtrDiff_t nPixels =
3799 59 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
3800 59 : GByte *pabyData = static_cast<GByte *>(pData);
3801 :
3802 64211 : for (GPtrDiff_t i = 0; i < nPixels; i++)
3803 : {
3804 64152 : if (pabyMaskData && pabyMaskData[i] == 0)
3805 0 : continue;
3806 64664 : if (!(bGotNoDataValue &&
3807 64152 : (pabyData[i] == static_cast<GByte>(dfNoDataValue))))
3808 : {
3809 63896 : panHistogram[pabyData[i]]++;
3810 : }
3811 : }
3812 :
3813 59 : poBlock->DropLock();
3814 59 : continue; // To next sample block.
3815 : }
3816 :
3817 : // This isn't the fastest way to do this, but is easier for now.
3818 721 : for (int iY = 0; iY < nYCheck; iY++)
3819 : {
3820 86017 : for (int iX = 0; iX < nXCheck; iX++)
3821 : {
3822 85321 : const GPtrDiff_t iOffset =
3823 85321 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
3824 :
3825 85321 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
3826 1 : continue;
3827 :
3828 85320 : double dfValue = 0.0;
3829 :
3830 85320 : switch (eDataType)
3831 : {
3832 19716 : case GDT_Byte:
3833 : {
3834 19716 : if (bSignedByte)
3835 0 : dfValue =
3836 0 : static_cast<signed char *>(pData)[iOffset];
3837 : else
3838 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
3839 19716 : break;
3840 : }
3841 0 : case GDT_Int8:
3842 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
3843 0 : break;
3844 65536 : case GDT_UInt16:
3845 65536 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
3846 65536 : break;
3847 2 : case GDT_Int16:
3848 2 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
3849 2 : break;
3850 0 : case GDT_UInt32:
3851 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
3852 0 : break;
3853 60 : case GDT_Int32:
3854 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
3855 60 : break;
3856 0 : case GDT_UInt64:
3857 0 : dfValue = static_cast<double>(
3858 0 : static_cast<GUInt64 *>(pData)[iOffset]);
3859 0 : break;
3860 0 : case GDT_Int64:
3861 0 : dfValue = static_cast<double>(
3862 0 : static_cast<GInt64 *>(pData)[iOffset]);
3863 0 : break;
3864 4 : case GDT_Float32:
3865 : {
3866 4 : const float fValue =
3867 4 : static_cast<float *>(pData)[iOffset];
3868 8 : if (CPLIsNan(fValue) ||
3869 4 : (bGotFloatNoDataValue &&
3870 4 : ARE_REAL_EQUAL(fValue, fNoDataValue)))
3871 1 : continue;
3872 3 : dfValue = fValue;
3873 3 : break;
3874 : }
3875 2 : case GDT_Float64:
3876 2 : dfValue = static_cast<double *>(pData)[iOffset];
3877 2 : if (CPLIsNan(dfValue))
3878 0 : continue;
3879 2 : break;
3880 0 : case GDT_CInt16:
3881 : {
3882 0 : double dfReal =
3883 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
3884 0 : double dfImag =
3885 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
3886 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
3887 : }
3888 0 : break;
3889 0 : case GDT_CInt32:
3890 : {
3891 0 : double dfReal =
3892 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
3893 0 : double dfImag =
3894 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
3895 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
3896 : }
3897 0 : break;
3898 0 : case GDT_CFloat32:
3899 : {
3900 0 : double dfReal =
3901 0 : static_cast<float *>(pData)[iOffset * 2];
3902 0 : double dfImag =
3903 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
3904 0 : if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
3905 0 : continue;
3906 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
3907 : }
3908 0 : break;
3909 0 : case GDT_CFloat64:
3910 : {
3911 0 : double dfReal =
3912 0 : static_cast<double *>(pData)[iOffset * 2];
3913 0 : double dfImag =
3914 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
3915 0 : if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
3916 0 : continue;
3917 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
3918 : }
3919 0 : break;
3920 0 : case GDT_Unknown:
3921 : case GDT_TypeCount:
3922 0 : CPLAssert(false);
3923 : CPLFree(pabyMaskData);
3924 : return CE_Failure;
3925 : }
3926 :
3927 85319 : if (eDataType != GDT_Float32 && bGotNoDataValue &&
3928 0 : ARE_REAL_EQUAL(dfValue, dfNoDataValue))
3929 0 : continue;
3930 :
3931 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
3932 : // and finite, the result of the multiplication cannot be
3933 : // NaN
3934 85319 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
3935 :
3936 85319 : if (dfIndex < 0)
3937 : {
3938 1 : if (bIncludeOutOfRange)
3939 1 : panHistogram[0]++;
3940 : }
3941 85318 : else if (dfIndex >= nBuckets)
3942 : {
3943 7 : if (bIncludeOutOfRange)
3944 4 : ++panHistogram[nBuckets - 1];
3945 : }
3946 : else
3947 : {
3948 85311 : ++panHistogram[static_cast<int>(dfIndex)];
3949 : }
3950 : }
3951 : }
3952 :
3953 25 : poBlock->DropLock();
3954 : }
3955 :
3956 25 : CPLFree(pabyMaskData);
3957 : }
3958 :
3959 25 : pfnProgress(1.0, "Compute Histogram", pProgressData);
3960 :
3961 25 : return CE_None;
3962 : }
3963 :
3964 : /************************************************************************/
3965 : /* GDALGetRasterHistogram() */
3966 : /************************************************************************/
3967 :
3968 : /**
3969 : * \brief Compute raster histogram.
3970 : *
3971 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
3972 : * exceeding 2 billion.
3973 : *
3974 : * @see GDALRasterBand::GetHistogram()
3975 : * @see GDALGetRasterHistogramEx()
3976 : */
3977 :
3978 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
3979 : double dfMax, int nBuckets,
3980 : int *panHistogram,
3981 : int bIncludeOutOfRange, int bApproxOK,
3982 : GDALProgressFunc pfnProgress,
3983 : void *pProgressData)
3984 :
3985 : {
3986 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
3987 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
3988 :
3989 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3990 :
3991 : GUIntBig *panHistogramTemp =
3992 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
3993 0 : if (panHistogramTemp == nullptr)
3994 : {
3995 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
3996 : "Out of memory in GDALGetRasterHistogram().");
3997 0 : return CE_Failure;
3998 : }
3999 :
4000 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4001 : bIncludeOutOfRange, bApproxOK,
4002 0 : pfnProgress, pProgressData);
4003 :
4004 0 : if (eErr == CE_None)
4005 : {
4006 0 : for (int i = 0; i < nBuckets; i++)
4007 : {
4008 0 : if (panHistogramTemp[i] > INT_MAX)
4009 : {
4010 0 : CPLError(CE_Warning, CPLE_AppDefined,
4011 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4012 : " exceeds maximum 32 bit value",
4013 0 : i, panHistogramTemp[i]);
4014 0 : panHistogram[i] = INT_MAX;
4015 : }
4016 : else
4017 : {
4018 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4019 : }
4020 : }
4021 : }
4022 :
4023 0 : CPLFree(panHistogramTemp);
4024 :
4025 0 : return eErr;
4026 : }
4027 :
4028 : /************************************************************************/
4029 : /* GDALGetRasterHistogramEx() */
4030 : /************************************************************************/
4031 :
4032 : /**
4033 : * \brief Compute raster histogram.
4034 : *
4035 : * @see GDALRasterBand::GetHistogram()
4036 : *
4037 : * @since GDAL 2.0
4038 : */
4039 :
4040 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4041 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4042 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4043 : GDALProgressFunc pfnProgress, void *pProgressData)
4044 :
4045 : {
4046 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4047 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4048 :
4049 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4050 :
4051 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4052 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4053 26 : pProgressData);
4054 : }
4055 :
4056 : /************************************************************************/
4057 : /* GetDefaultHistogram() */
4058 : /************************************************************************/
4059 :
4060 : /**
4061 : * \brief Fetch default raster histogram.
4062 : *
4063 : * The default method in GDALRasterBand will compute a default histogram. This
4064 : * method is overridden by derived classes (such as GDALPamRasterBand,
4065 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4066 : * stored histogram.
4067 : *
4068 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4069 : * GDALGetDefaultHistogramEx().
4070 : *
4071 : * @param pdfMin pointer to double value that will contain the lower bound of
4072 : * the histogram.
4073 : * @param pdfMax pointer to double value that will contain the upper bound of
4074 : * the histogram.
4075 : * @param pnBuckets pointer to int value that will contain the number of buckets
4076 : * in *ppanHistogram.
4077 : * @param ppanHistogram pointer to array into which the histogram totals are
4078 : * placed. To be freed with VSIFree
4079 : * @param bForce TRUE to force the computation. If FALSE and no default
4080 : * histogram is available, the method will return CE_Warning
4081 : * @param pfnProgress function to report progress to completion.
4082 : * @param pProgressData application data to pass to pfnProgress.
4083 : *
4084 : * @return CE_None on success, CE_Failure if something goes wrong, or
4085 : * CE_Warning if no default histogram is available.
4086 : */
4087 :
4088 18 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4089 : int *pnBuckets,
4090 : GUIntBig **ppanHistogram, int bForce,
4091 : GDALProgressFunc pfnProgress,
4092 : void *pProgressData)
4093 :
4094 : {
4095 18 : CPLAssert(nullptr != pnBuckets);
4096 18 : CPLAssert(nullptr != ppanHistogram);
4097 18 : CPLAssert(nullptr != pdfMin);
4098 18 : CPLAssert(nullptr != pdfMax);
4099 :
4100 18 : *pnBuckets = 0;
4101 18 : *ppanHistogram = nullptr;
4102 :
4103 18 : if (!bForce)
4104 6 : return CE_Warning;
4105 :
4106 12 : const int nBuckets = 256;
4107 :
4108 12 : bool bSignedByte = false;
4109 12 : if (eDataType == GDT_Byte)
4110 : {
4111 12 : EnablePixelTypeSignedByteWarning(false);
4112 : const char *pszPixelType =
4113 12 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4114 12 : EnablePixelTypeSignedByteWarning(true);
4115 12 : bSignedByte =
4116 12 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4117 : }
4118 :
4119 12 : if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4120 : {
4121 12 : *pdfMin = -0.5;
4122 12 : *pdfMax = 255.5;
4123 : }
4124 : else
4125 : {
4126 :
4127 : const CPLErr eErr =
4128 0 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4129 0 : const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4130 0 : *pdfMin -= dfHalfBucket;
4131 0 : *pdfMax += dfHalfBucket;
4132 :
4133 0 : if (eErr != CE_None)
4134 0 : return eErr;
4135 : }
4136 :
4137 12 : *ppanHistogram =
4138 12 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4139 12 : if (*ppanHistogram == nullptr)
4140 : {
4141 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4142 : "Out of memory in InitBlockInfo().");
4143 0 : return CE_Failure;
4144 : }
4145 :
4146 12 : *pnBuckets = nBuckets;
4147 24 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4148 12 : TRUE, FALSE, pfnProgress, pProgressData);
4149 12 : if (eErr != CE_None)
4150 : {
4151 0 : *pnBuckets = 0;
4152 : }
4153 12 : return eErr;
4154 : }
4155 :
4156 : /************************************************************************/
4157 : /* GDALGetDefaultHistogram() */
4158 : /************************************************************************/
4159 :
4160 : /**
4161 : * \brief Fetch default raster histogram.
4162 : *
4163 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4164 : * exceeding 2 billion.
4165 : *
4166 : * @see GDALRasterBand::GDALGetDefaultHistogram()
4167 : * @see GDALGetRasterHistogramEx()
4168 : */
4169 :
4170 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4171 : double *pdfMin, double *pdfMax,
4172 : int *pnBuckets, int **ppanHistogram,
4173 : int bForce,
4174 : GDALProgressFunc pfnProgress,
4175 : void *pProgressData)
4176 :
4177 : {
4178 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4179 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4180 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4181 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4182 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4183 :
4184 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4185 0 : GUIntBig *panHistogramTemp = nullptr;
4186 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
4187 : &panHistogramTemp, bForce,
4188 0 : pfnProgress, pProgressData);
4189 0 : if (eErr == CE_None)
4190 : {
4191 0 : const int nBuckets = *pnBuckets;
4192 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
4193 0 : if (*ppanHistogram == nullptr)
4194 : {
4195 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4196 : "Out of memory in GDALGetDefaultHistogram().");
4197 0 : VSIFree(panHistogramTemp);
4198 0 : return CE_Failure;
4199 : }
4200 :
4201 0 : for (int i = 0; i < nBuckets; ++i)
4202 : {
4203 0 : if (panHistogramTemp[i] > INT_MAX)
4204 : {
4205 0 : CPLError(CE_Warning, CPLE_AppDefined,
4206 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4207 : " exceeds maximum 32 bit value",
4208 0 : i, panHistogramTemp[i]);
4209 0 : (*ppanHistogram)[i] = INT_MAX;
4210 : }
4211 : else
4212 : {
4213 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
4214 : }
4215 : }
4216 :
4217 0 : CPLFree(panHistogramTemp);
4218 : }
4219 : else
4220 : {
4221 0 : *ppanHistogram = nullptr;
4222 : }
4223 :
4224 0 : return eErr;
4225 : }
4226 :
4227 : /************************************************************************/
4228 : /* GDALGetDefaultHistogramEx() */
4229 : /************************************************************************/
4230 :
4231 : /**
4232 : * \brief Fetch default raster histogram.
4233 : *
4234 : * @see GDALRasterBand::GetDefaultHistogram()
4235 : *
4236 : * @since GDAL 2.0
4237 : */
4238 :
4239 : CPLErr CPL_STDCALL
4240 15 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
4241 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
4242 : GDALProgressFunc pfnProgress, void *pProgressData)
4243 :
4244 : {
4245 15 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4246 15 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4247 15 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4248 15 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4249 15 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4250 :
4251 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4252 15 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
4253 15 : bForce, pfnProgress, pProgressData);
4254 : }
4255 :
4256 : /************************************************************************/
4257 : /* AdviseRead() */
4258 : /************************************************************************/
4259 :
4260 : /**
4261 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
4262 : * \brief Advise driver of upcoming read requests.
4263 : *
4264 : * Some GDAL drivers operate more efficiently if they know in advance what
4265 : * set of upcoming read requests will be made. The AdviseRead() method allows
4266 : * an application to notify the driver of the region of interest,
4267 : * and at what resolution the region will be read.
4268 : *
4269 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
4270 : * accelerate access via some drivers.
4271 : *
4272 : * Depending on call paths, drivers might receive several calls to
4273 : * AdviseRead() with the same parameters.
4274 : *
4275 : * @param nXOff The pixel offset to the top left corner of the region
4276 : * of the band to be accessed. This would be zero to start from the left side.
4277 : *
4278 : * @param nYOff The line offset to the top left corner of the region
4279 : * of the band to be accessed. This would be zero to start from the top.
4280 : *
4281 : * @param nXSize The width of the region of the band to be accessed in pixels.
4282 : *
4283 : * @param nYSize The height of the region of the band to be accessed in lines.
4284 : *
4285 : * @param nBufXSize the width of the buffer image into which the desired region
4286 : * is to be read, or from which it is to be written.
4287 : *
4288 : * @param nBufYSize the height of the buffer image into which the desired
4289 : * region is to be read, or from which it is to be written.
4290 : *
4291 : * @param eBufType the type of the pixel values in the pData data buffer. The
4292 : * pixel values will automatically be translated to/from the GDALRasterBand
4293 : * data type as needed.
4294 : *
4295 : * @param papszOptions a list of name=value strings with special control
4296 : * options. Normally this is NULL.
4297 : *
4298 : * @return CE_Failure if the request is invalid and CE_None if it works or
4299 : * is ignored.
4300 : */
4301 :
4302 : /**/
4303 : /**/
4304 :
4305 41581 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
4306 : int /*nYSize*/, int /*nBufXSize*/,
4307 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
4308 : char ** /*papszOptions*/)
4309 : {
4310 41581 : return CE_None;
4311 : }
4312 :
4313 : /************************************************************************/
4314 : /* GDALRasterAdviseRead() */
4315 : /************************************************************************/
4316 :
4317 : /**
4318 : * \brief Advise driver of upcoming read requests.
4319 : *
4320 : * @see GDALRasterBand::AdviseRead()
4321 : */
4322 :
4323 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
4324 : int nYOff, int nXSize, int nYSize,
4325 : int nBufXSize, int nBufYSize,
4326 : GDALDataType eDT,
4327 : CSLConstList papszOptions)
4328 :
4329 : {
4330 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
4331 :
4332 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4333 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
4334 : nBufYSize, eDT,
4335 2 : const_cast<char **>(papszOptions));
4336 : }
4337 :
4338 : /************************************************************************/
4339 : /* GetStatistics() */
4340 : /************************************************************************/
4341 :
4342 : /**
4343 : * \brief Fetch image statistics.
4344 : *
4345 : * Returns the minimum, maximum, mean and standard deviation of all
4346 : * pixel values in this band. If approximate statistics are sufficient,
4347 : * the bApproxOK flag can be set to true in which case overviews, or a
4348 : * subset of image tiles may be used in computing the statistics.
4349 : *
4350 : * If bForce is FALSE results will only be returned if it can be done
4351 : * quickly (i.e. without scanning the image, typically by using pre-existing
4352 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
4353 : * returned efficiently, the method will return CE_Warning but no warning will
4354 : * be issued. This is a non-standard use of the CE_Warning return value
4355 : * to indicate "nothing done".
4356 : *
4357 : * If bForce is TRUE, and results are quickly available without scanning the
4358 : * image, they will be used. If bForce is TRUE and results are not quickly
4359 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
4360 : * which will scan the image.
4361 : *
4362 : * To always force recomputation of statistics, use ComputeStatistics() instead
4363 : * of this method.
4364 : *
4365 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
4366 : * will generally cache statistics in the .pam file allowing fast fetch
4367 : * after the first request.
4368 : *
4369 : * This method is the same as the C function GDALGetRasterStatistics().
4370 : *
4371 : * @param bApproxOK If TRUE statistics may be computed based on overviews
4372 : * or a subset of all tiles.
4373 : *
4374 : * @param bForce If FALSE statistics will only be returned if it can
4375 : * be done without rescanning the image. If TRUE, statistics computation will
4376 : * be forced if pre-existing values are not quickly available.
4377 : *
4378 : * @param pdfMin Location into which to load image minimum (may be NULL).
4379 : *
4380 : * @param pdfMax Location into which to load image maximum (may be NULL).-
4381 : *
4382 : * @param pdfMean Location into which to load image mean (may be NULL).
4383 : *
4384 : * @param pdfStdDev Location into which to load image standard deviation
4385 : * (may be NULL).
4386 : *
4387 : * @return CE_None on success, CE_Warning if no values returned,
4388 : * CE_Failure if an error occurs.
4389 : */
4390 :
4391 588 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
4392 : double *pdfMax, double *pdfMean,
4393 : double *pdfStdDev)
4394 :
4395 : {
4396 : /* -------------------------------------------------------------------- */
4397 : /* Do we already have metadata items for the requested values? */
4398 : /* -------------------------------------------------------------------- */
4399 1176 : if ((pdfMin == nullptr ||
4400 588 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
4401 209 : (pdfMax == nullptr ||
4402 209 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
4403 1385 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
4404 209 : (pdfStdDev == nullptr ||
4405 209 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
4406 : {
4407 209 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
4408 : {
4409 202 : if (pdfMin != nullptr)
4410 202 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
4411 202 : if (pdfMax != nullptr)
4412 202 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
4413 202 : if (pdfMean != nullptr)
4414 202 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
4415 202 : if (pdfStdDev != nullptr)
4416 202 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
4417 :
4418 202 : return CE_None;
4419 : }
4420 : }
4421 :
4422 : /* -------------------------------------------------------------------- */
4423 : /* Does the driver already know the min/max? */
4424 : /* -------------------------------------------------------------------- */
4425 386 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
4426 : {
4427 0 : int bSuccessMin = FALSE;
4428 0 : int bSuccessMax = FALSE;
4429 :
4430 0 : const double dfMin = GetMinimum(&bSuccessMin);
4431 0 : const double dfMax = GetMaximum(&bSuccessMax);
4432 :
4433 0 : if (bSuccessMin && bSuccessMax)
4434 : {
4435 0 : if (pdfMin != nullptr)
4436 0 : *pdfMin = dfMin;
4437 0 : if (pdfMax != nullptr)
4438 0 : *pdfMax = dfMax;
4439 0 : return CE_None;
4440 : }
4441 : }
4442 :
4443 : /* -------------------------------------------------------------------- */
4444 : /* Either return without results, or force computation. */
4445 : /* -------------------------------------------------------------------- */
4446 386 : if (!bForce)
4447 136 : return CE_Warning;
4448 : else
4449 250 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
4450 250 : GDALDummyProgress, nullptr);
4451 : }
4452 :
4453 : /************************************************************************/
4454 : /* GDALGetRasterStatistics() */
4455 : /************************************************************************/
4456 :
4457 : /**
4458 : * \brief Fetch image statistics.
4459 : *
4460 : * @see GDALRasterBand::GetStatistics()
4461 : */
4462 :
4463 237 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
4464 : int bForce, double *pdfMin,
4465 : double *pdfMax, double *pdfMean,
4466 : double *pdfStdDev)
4467 :
4468 : {
4469 237 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
4470 :
4471 237 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4472 237 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
4473 237 : pdfStdDev);
4474 : }
4475 :
4476 : #ifdef CPL_HAS_GINT64
4477 :
4478 : /************************************************************************/
4479 : /* GDALUInt128 */
4480 : /************************************************************************/
4481 :
4482 : #ifdef HAVE_UINT128_T
4483 : class GDALUInt128
4484 : {
4485 : __uint128_t val;
4486 :
4487 603 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
4488 : {
4489 603 : }
4490 :
4491 : public:
4492 402 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
4493 : {
4494 : // Evaluates to just a single mul on x86_64
4495 402 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
4496 : }
4497 :
4498 201 : GDALUInt128 operator-(const GDALUInt128 &other) const
4499 : {
4500 201 : return GDALUInt128(val - other.val);
4501 : }
4502 :
4503 192 : operator double() const
4504 : {
4505 192 : return static_cast<double>(val);
4506 : }
4507 : };
4508 : #else
4509 :
4510 : #if defined(_MSC_VER) && defined(_M_X64)
4511 : #include <intrin.h>
4512 : #endif
4513 :
4514 : class GDALUInt128
4515 : {
4516 : GUIntBig low, high;
4517 :
4518 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
4519 : {
4520 : }
4521 :
4522 : public:
4523 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
4524 : {
4525 : #if defined(_MSC_VER) && defined(_M_X64)
4526 : GUIntBig highRes;
4527 : GUIntBig lowRes = _umul128(first, second, &highRes);
4528 : return GDALUInt128(lowRes, highRes);
4529 : #else
4530 : const GUInt32 firstLow = static_cast<GUInt32>(first);
4531 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
4532 : const GUInt32 secondLow = static_cast<GUInt32>(second);
4533 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
4534 : GUIntBig highRes = 0;
4535 : const GUIntBig firstLowSecondHigh =
4536 : static_cast<GUIntBig>(firstLow) * secondHigh;
4537 : const GUIntBig firstHighSecondLow =
4538 : static_cast<GUIntBig>(firstHigh) * secondLow;
4539 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
4540 : if (middleTerm < firstLowSecondHigh) // check for overflow
4541 : highRes += static_cast<GUIntBig>(1) << 32;
4542 : const GUIntBig firstLowSecondLow =
4543 : static_cast<GUIntBig>(firstLow) * secondLow;
4544 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
4545 : if (lowRes < firstLowSecondLow) // check for overflow
4546 : highRes++;
4547 : highRes +=
4548 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
4549 : return GDALUInt128(lowRes, highRes);
4550 : #endif
4551 : }
4552 :
4553 : GDALUInt128 operator-(const GDALUInt128 &other) const
4554 : {
4555 : GUIntBig highRes = high - other.high;
4556 : GUIntBig lowRes = low - other.low;
4557 : if (lowRes > low) // check for underflow
4558 : --highRes;
4559 : return GDALUInt128(lowRes, highRes);
4560 : }
4561 :
4562 : operator double() const
4563 : {
4564 : const double twoPow64 = 18446744073709551616.0;
4565 : return high * twoPow64 + low;
4566 : }
4567 : };
4568 : #endif
4569 :
4570 : /************************************************************************/
4571 : /* ComputeStatisticsInternal() */
4572 : /************************************************************************/
4573 :
4574 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
4575 : // not needed.
4576 : #define static_cast_for_coverity_scan static_cast
4577 :
4578 : // The rationale for below optimizations is detailed in statistics.txt
4579 :
4580 : // Use with T = GByte or GUInt16 only !
4581 : template <class T, bool COMPUTE_OTHER_STATS>
4582 : struct ComputeStatisticsInternalGeneric
4583 : {
4584 179 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
4585 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
4586 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
4587 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
4588 : {
4589 : static_assert(std::is_same<T, GByte>::value ||
4590 : std::is_same<T, GUInt16>::value,
4591 : "bad type for T");
4592 179 : if (bHasNoData)
4593 : {
4594 : // General case
4595 386 : for (int iY = 0; iY < nYCheck; iY++)
4596 : {
4597 81751 : for (int iX = 0; iX < nXCheck; iX++)
4598 : {
4599 81468 : const GPtrDiff_t iOffset =
4600 81468 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4601 81468 : const GUInt32 nValue = pData[iOffset];
4602 81468 : if (nValue == nNoDataValue)
4603 175 : continue;
4604 81293 : if (nValue < nMin)
4605 26 : nMin = nValue;
4606 81293 : if (nValue > nMax)
4607 57 : nMax = nValue;
4608 : if constexpr (COMPUTE_OTHER_STATS)
4609 : {
4610 79657 : nValidCount++;
4611 79657 : nSum += nValue;
4612 79657 : nSumSquare +=
4613 79657 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
4614 79657 : nValue;
4615 : }
4616 : }
4617 : }
4618 : if constexpr (COMPUTE_OTHER_STATS)
4619 : {
4620 20 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4621 : }
4622 : }
4623 84 : else if (nMin == std::numeric_limits<T>::min() &&
4624 8 : nMax == std::numeric_limits<T>::max())
4625 : {
4626 : if constexpr (COMPUTE_OTHER_STATS)
4627 : {
4628 : // Optimization when there is no nodata and we know we have already
4629 : // reached the min and max
4630 208 : for (int iY = 0; iY < nYCheck; iY++)
4631 : {
4632 : int iX;
4633 1002 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
4634 : {
4635 800 : const GPtrDiff_t iOffset =
4636 800 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4637 800 : const GUIntBig nValue = pData[iOffset];
4638 800 : const GUIntBig nValue2 = pData[iOffset + 1];
4639 800 : const GUIntBig nValue3 = pData[iOffset + 2];
4640 800 : const GUIntBig nValue4 = pData[iOffset + 3];
4641 800 : nSum += nValue;
4642 800 : nSumSquare += nValue * nValue;
4643 800 : nSum += nValue2;
4644 800 : nSumSquare += nValue2 * nValue2;
4645 800 : nSum += nValue3;
4646 800 : nSumSquare += nValue3 * nValue3;
4647 800 : nSum += nValue4;
4648 800 : nSumSquare += nValue4 * nValue4;
4649 : }
4650 207 : for (; iX < nXCheck; ++iX)
4651 : {
4652 5 : const GPtrDiff_t iOffset =
4653 5 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4654 5 : const GUIntBig nValue = pData[iOffset];
4655 5 : nSum += nValue;
4656 5 : nSumSquare += nValue * nValue;
4657 : }
4658 : }
4659 6 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4660 6 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4661 : }
4662 : }
4663 : else
4664 : {
4665 3360 : for (int iY = 0; iY < nYCheck; iY++)
4666 : {
4667 : int iX;
4668 635035 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
4669 : {
4670 631745 : const GPtrDiff_t iOffset =
4671 631745 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4672 631745 : const GUInt32 nValue = pData[iOffset];
4673 631745 : const GUInt32 nValue2 = pData[iOffset + 1];
4674 631745 : if (nValue < nValue2)
4675 : {
4676 2160 : if (nValue < nMin)
4677 48 : nMin = nValue;
4678 2160 : if (nValue2 > nMax)
4679 108 : nMax = nValue2;
4680 : }
4681 : else
4682 : {
4683 629585 : if (nValue2 < nMin)
4684 61 : nMin = nValue2;
4685 629585 : if (nValue > nMax)
4686 212 : nMax = nValue;
4687 : }
4688 : if constexpr (COMPUTE_OTHER_STATS)
4689 : {
4690 624695 : nSum += nValue;
4691 624695 : nSumSquare +=
4692 624695 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
4693 624695 : nValue;
4694 624695 : nSum += nValue2;
4695 624695 : nSumSquare +=
4696 624695 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
4697 624695 : nValue2;
4698 : }
4699 : }
4700 3290 : if (iX < nXCheck)
4701 : {
4702 9 : const GPtrDiff_t iOffset =
4703 9 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4704 9 : const GUInt32 nValue = pData[iOffset];
4705 9 : if (nValue < nMin)
4706 6 : nMin = nValue;
4707 9 : if (nValue > nMax)
4708 6 : nMax = nValue;
4709 : if (COMPUTE_OTHER_STATS)
4710 : {
4711 9 : nSum += nValue;
4712 9 : nSumSquare +=
4713 9 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
4714 9 : nValue;
4715 : }
4716 : }
4717 : }
4718 : if constexpr (COMPUTE_OTHER_STATS)
4719 : {
4720 25 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4721 25 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4722 : }
4723 : }
4724 179 : }
4725 : };
4726 :
4727 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
4728 : // using 64bit accumulators in internal loops. This also slightly helps in
4729 : // 64bit mode.
4730 : template <bool COMPUTE_OTHER_STATS>
4731 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
4732 : {
4733 11605 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
4734 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
4735 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
4736 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
4737 : {
4738 11605 : int nOuterLoops = nXCheck / 65536;
4739 11605 : if (nXCheck % 65536)
4740 11605 : nOuterLoops++;
4741 :
4742 11605 : if (bHasNoData)
4743 : {
4744 : // General case
4745 19549 : for (int iY = 0; iY < nYCheck; iY++)
4746 : {
4747 10938 : int iX = 0;
4748 21876 : for (int k = 0; k < nOuterLoops; k++)
4749 : {
4750 10938 : int iMax = iX + 65536;
4751 10938 : if (iMax > nXCheck)
4752 10938 : iMax = nXCheck;
4753 10938 : GUInt32 nSum32bit = 0;
4754 10938 : GUInt32 nSumSquare32bit = 0;
4755 10938 : GUInt32 nValidCount32bit = 0;
4756 10938 : GUInt32 nSampleCount32bit = 0;
4757 16705781 : for (; iX < iMax; iX++)
4758 : {
4759 16694931 : const GPtrDiff_t iOffset =
4760 16694931 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4761 16694931 : const GUInt32 nValue = pData[iOffset];
4762 :
4763 16694931 : nSampleCount32bit++;
4764 16694931 : if (nValue == nNoDataValue)
4765 16353480 : continue;
4766 341396 : if (nValue < nMin)
4767 343 : nMin = nValue;
4768 341396 : if (nValue > nMax)
4769 828 : nMax = nValue;
4770 : if constexpr (COMPUTE_OTHER_STATS)
4771 : {
4772 16951 : nValidCount32bit++;
4773 16951 : nSum32bit += nValue;
4774 16951 : nSumSquare32bit += nValue * nValue;
4775 : }
4776 : }
4777 : if constexpr (COMPUTE_OTHER_STATS)
4778 : {
4779 650 : nSampleCount += nSampleCount32bit;
4780 650 : nValidCount += nValidCount32bit;
4781 650 : nSum += nSum32bit;
4782 650 : nSumSquare += nSumSquare32bit;
4783 : }
4784 : }
4785 : }
4786 : }
4787 2994 : else if (nMin == 0 && nMax == 255)
4788 : {
4789 : if constexpr (COMPUTE_OTHER_STATS)
4790 : {
4791 : // Optimization when there is no nodata and we know we have already
4792 : // reached the min and max
4793 2644 : for (int iY = 0; iY < nYCheck; iY++)
4794 : {
4795 2617 : int iX = 0;
4796 5234 : for (int k = 0; k < nOuterLoops; k++)
4797 : {
4798 2617 : int iMax = iX + 65536;
4799 2617 : if (iMax > nXCheck)
4800 2617 : iMax = nXCheck;
4801 2617 : GUInt32 nSum32bit = 0;
4802 2617 : GUInt32 nSumSquare32bit = 0;
4803 176297 : for (; iX + 3 < iMax; iX += 4)
4804 : {
4805 173680 : const GPtrDiff_t iOffset =
4806 173680 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4807 173680 : const GUInt32 nValue = pData[iOffset];
4808 173680 : const GUInt32 nValue2 = pData[iOffset + 1];
4809 173680 : const GUInt32 nValue3 = pData[iOffset + 2];
4810 173680 : const GUInt32 nValue4 = pData[iOffset + 3];
4811 173680 : nSum32bit += nValue;
4812 173680 : nSumSquare32bit += nValue * nValue;
4813 173680 : nSum32bit += nValue2;
4814 173680 : nSumSquare32bit += nValue2 * nValue2;
4815 173680 : nSum32bit += nValue3;
4816 173680 : nSumSquare32bit += nValue3 * nValue3;
4817 173680 : nSum32bit += nValue4;
4818 173680 : nSumSquare32bit += nValue4 * nValue4;
4819 : }
4820 2617 : nSum += nSum32bit;
4821 2617 : nSumSquare += nSumSquare32bit;
4822 : }
4823 2620 : for (; iX < nXCheck; ++iX)
4824 : {
4825 3 : const GPtrDiff_t iOffset =
4826 3 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4827 3 : const GUIntBig nValue = pData[iOffset];
4828 3 : nSum += nValue;
4829 3 : nSumSquare += nValue * nValue;
4830 : }
4831 : }
4832 27 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4833 27 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4834 27 : }
4835 : }
4836 : else
4837 : {
4838 7335 : for (int iY = 0; iY < nYCheck; iY++)
4839 : {
4840 4368 : int iX = 0;
4841 8736 : for (int k = 0; k < nOuterLoops; k++)
4842 : {
4843 4368 : int iMax = iX + 65536;
4844 4368 : if (iMax > nXCheck)
4845 4368 : iMax = nXCheck;
4846 4368 : GUInt32 nSum32bit = 0;
4847 4368 : GUInt32 nSumSquare32bit = 0;
4848 159809 : for (; iX + 1 < iMax; iX += 2)
4849 : {
4850 155441 : const GPtrDiff_t iOffset =
4851 155441 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4852 155441 : const GUInt32 nValue = pData[iOffset];
4853 155441 : const GUInt32 nValue2 = pData[iOffset + 1];
4854 155441 : if (nValue < nValue2)
4855 : {
4856 8844 : if (nValue < nMin)
4857 248 : nMin = nValue;
4858 8844 : if (nValue2 > nMax)
4859 236 : nMax = nValue2;
4860 : }
4861 : else
4862 : {
4863 146597 : if (nValue2 < nMin)
4864 290 : nMin = nValue2;
4865 146597 : if (nValue > nMax)
4866 839 : nMax = nValue;
4867 : }
4868 : if constexpr (COMPUTE_OTHER_STATS)
4869 : {
4870 132239 : nSum32bit += nValue;
4871 132239 : nSumSquare32bit += nValue * nValue;
4872 132239 : nSum32bit += nValue2;
4873 132239 : nSumSquare32bit += nValue2 * nValue2;
4874 : }
4875 : }
4876 : if constexpr (COMPUTE_OTHER_STATS)
4877 : {
4878 1582 : nSum += nSum32bit;
4879 1582 : nSumSquare += nSumSquare32bit;
4880 : }
4881 : }
4882 4368 : if (iX < nXCheck)
4883 : {
4884 1104 : const GPtrDiff_t iOffset =
4885 1104 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4886 1104 : const GUInt32 nValue = pData[iOffset];
4887 1104 : if (nValue < nMin)
4888 37 : nMin = nValue;
4889 1104 : if (nValue > nMax)
4890 47 : nMax = nValue;
4891 : if constexpr (COMPUTE_OTHER_STATS)
4892 : {
4893 312 : nSum += nValue;
4894 312 : nSumSquare +=
4895 312 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
4896 312 : nValue;
4897 : }
4898 : }
4899 : }
4900 : if constexpr (COMPUTE_OTHER_STATS)
4901 : {
4902 881 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4903 881 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4904 : }
4905 : }
4906 11605 : }
4907 : };
4908 :
4909 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
4910 : {
4911 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
4912 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
4913 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
4914 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
4915 : {
4916 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
4917 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
4918 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
4919 : }
4920 : };
4921 :
4922 : #if (defined(__x86_64__) || defined(_M_X64)) && \
4923 : (defined(__GNUC__) || defined(_MSC_VER))
4924 :
4925 : #include "gdal_avx2_emulation.hpp"
4926 :
4927 : #define ZERO256 GDALmm256_setzero_si256()
4928 :
4929 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
4930 : static void
4931 18897 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
4932 : // assumed to be aligned on 256 bits
4933 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
4934 : GUIntBig &nSum, GUIntBig &nSumSquare,
4935 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
4936 : {
4937 : // 32-byte alignment may not be enforced by linker, so do it at hand
4938 : GByte
4939 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
4940 18897 : GByte *paby32ByteAligned =
4941 : aby32ByteUnaligned +
4942 18897 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
4943 18897 : GByte *pabyMin = paby32ByteAligned;
4944 18897 : GByte *pabyMax = paby32ByteAligned + 32;
4945 18897 : GUInt32 *panSum =
4946 : COMPUTE_OTHER_STATS
4947 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
4948 : : nullptr;
4949 18897 : GUInt32 *panSumSquare =
4950 : COMPUTE_OTHER_STATS
4951 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
4952 : : nullptr;
4953 :
4954 18897 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
4955 :
4956 18897 : GPtrDiff_t i = 0;
4957 : // Make sure that sumSquare can fit on uint32
4958 : // * 8 since we can hold 8 sums per vector register
4959 18897 : const int nMaxIterationsPerInnerLoop =
4960 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
4961 18897 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
4962 18897 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
4963 18897 : nOuterLoops++;
4964 :
4965 : GDALm256i ymm_min =
4966 18897 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
4967 18897 : GDALm256i ymm_max = ymm_min;
4968 18897 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
4969 :
4970 37794 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
4971 : {
4972 18897 : const auto iMax =
4973 18897 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
4974 :
4975 : // holds 4 uint32 sums in [0], [2], [4] and [6]
4976 18897 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
4977 : [[maybe_unused]] GDALm256i ymm_sumsquare =
4978 18897 : ZERO256; // holds 8 uint32 sums
4979 625620 : for (; i + 31 < iMax; i += 32)
4980 : {
4981 606723 : const GDALm256i ymm = GDALmm256_load_si256(
4982 606723 : reinterpret_cast<const GDALm256i *>(pData + i));
4983 : if (COMPUTE_MIN)
4984 : {
4985 153148 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
4986 : }
4987 : if (COMPUTE_MAX)
4988 : {
4989 515841 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
4990 : }
4991 :
4992 : if constexpr (COMPUTE_OTHER_STATS)
4993 : {
4994 : // Extract even-8bit values
4995 : const GDALm256i ymm_even =
4996 493355 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
4997 : // Compute square of those 16 values as 32 bit result
4998 : // and add adjacent pairs
4999 : const GDALm256i ymm_even_square =
5000 493355 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5001 : // Add to the sumsquare accumulator
5002 : ymm_sumsquare =
5003 493355 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5004 :
5005 : // Extract odd-8bit values
5006 493355 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5007 : const GDALm256i ymm_odd_square =
5008 493355 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5009 : ymm_sumsquare =
5010 493355 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5011 :
5012 : // Now compute the sums
5013 493355 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5014 : GDALmm256_sad_epu8(ymm, ZERO256));
5015 : }
5016 : }
5017 :
5018 : if constexpr (COMPUTE_OTHER_STATS)
5019 : {
5020 10584 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5021 : ymm_sum);
5022 10584 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5023 : ymm_sumsquare);
5024 :
5025 10584 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5026 10584 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5027 10584 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5028 10584 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5029 : panSumSquare[7];
5030 : }
5031 : }
5032 :
5033 : if constexpr (COMPUTE_MIN)
5034 : {
5035 5949 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5036 : }
5037 : if constexpr (COMPUTE_MAX)
5038 : {
5039 14901 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5040 : }
5041 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5042 : {
5043 509190 : for (int j = 0; j < 32; j++)
5044 : {
5045 : if constexpr (COMPUTE_MIN)
5046 : {
5047 190368 : if (pabyMin[j] < nMin)
5048 1239 : nMin = pabyMin[j];
5049 : }
5050 : if constexpr (COMPUTE_MAX)
5051 : {
5052 476832 : if (pabyMax[j] > nMax)
5053 1745 : nMax = pabyMax[j];
5054 : }
5055 : }
5056 : }
5057 :
5058 211431 : for (; i < nBlockPixels; i++)
5059 : {
5060 192534 : const GUInt32 nValue = pData[i];
5061 : if constexpr (COMPUTE_MIN)
5062 : {
5063 66094 : if (nValue < nMin)
5064 1 : nMin = nValue;
5065 : }
5066 : if constexpr (COMPUTE_MAX)
5067 : {
5068 189771 : if (nValue > nMax)
5069 1167 : nMax = nValue;
5070 : }
5071 : if constexpr (COMPUTE_OTHER_STATS)
5072 : {
5073 77179 : nSum += nValue;
5074 77179 : nSumSquare +=
5075 77179 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5076 : }
5077 : }
5078 :
5079 : if constexpr (COMPUTE_OTHER_STATS)
5080 : {
5081 10584 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5082 10584 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5083 : }
5084 18897 : }
5085 :
5086 : // SSE2/AVX2 optimization for GByte case
5087 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5088 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5089 : // there are strictly equivalent to 2 parallel SSE2 streams.
5090 : template <bool COMPUTE_OTHER_STATS>
5091 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5092 : {
5093 27813 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5094 : // assumed to be aligned on 256 bits
5095 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5096 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5097 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5098 : GUIntBig &nValidCount)
5099 : {
5100 27813 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5101 27813 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5102 9352 : nMin <= nMax)
5103 : {
5104 : // 32-byte alignment may not be enforced by linker, so do it at hand
5105 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5106 1240 : GByte *paby32ByteAligned =
5107 : aby32ByteUnaligned +
5108 1240 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5109 1240 : GByte *pabyMin = paby32ByteAligned;
5110 1240 : GByte *pabyMax = paby32ByteAligned + 32;
5111 1240 : GUInt32 *panSum =
5112 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5113 1240 : GUInt32 *panSumSquare =
5114 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5115 :
5116 1240 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5117 :
5118 1240 : GPtrDiff_t i = 0;
5119 : // Make sure that sumSquare can fit on uint32
5120 : // * 8 since we can hold 8 sums per vector register
5121 1240 : const int nMaxIterationsPerInnerLoop =
5122 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5123 1240 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5124 1240 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5125 1240 : nOuterLoops++;
5126 :
5127 : const GDALm256i ymm_nodata =
5128 1240 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5129 : // any non noData value in [min,max] would do.
5130 : const GDALm256i ymm_neutral =
5131 1240 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5132 1240 : GDALm256i ymm_min = ymm_neutral;
5133 1240 : GDALm256i ymm_max = ymm_neutral;
5134 : [[maybe_unused]] const auto ymm_mask_8bits =
5135 1240 : GDALmm256_set1_epi16(0xFF);
5136 :
5137 1240 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5138 1240 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5139 1240 : const bool bComputeMinMax =
5140 1240 : nMin > nMinThreshold || nMax < nMaxThreshold;
5141 :
5142 2480 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5143 : {
5144 1240 : const auto iMax =
5145 1240 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5146 :
5147 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5148 1240 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5149 : // holds 8 uint32 sums
5150 1240 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5151 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5152 1240 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5153 1240 : const auto iInit = i;
5154 13799 : for (; i + 31 < iMax; i += 32)
5155 : {
5156 12559 : const GDALm256i ymm = GDALmm256_load_si256(
5157 12559 : reinterpret_cast<const GDALm256i *>(pData + i));
5158 :
5159 : // Check which values are nodata
5160 : const GDALm256i ymm_eq_nodata =
5161 12559 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5162 : if constexpr (COMPUTE_OTHER_STATS)
5163 : {
5164 : // Count how many values are nodata (due to cmpeq
5165 : // putting 255 when condition is met, this will actually
5166 : // be 255 times the number of nodata value, spread in 4
5167 : // 64 bits words). We can use add_epi32 as the counter
5168 : // will not overflow uint32
5169 4514 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5170 : ymm_count_nodata_mul_255,
5171 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5172 : }
5173 : // Replace all nodata values by zero for the purpose of sum
5174 : // and sumquare.
5175 : const GDALm256i ymm_nodata_by_zero =
5176 12559 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5177 12559 : if (bComputeMinMax)
5178 : {
5179 : // Replace all nodata values by a neutral value for the
5180 : // purpose of min and max.
5181 : const GDALm256i ymm_nodata_by_neutral =
5182 8174 : GDALmm256_or_si256(
5183 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5184 : ymm_nodata_by_zero);
5185 :
5186 : ymm_min =
5187 8174 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5188 : ymm_max =
5189 8174 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
5190 : }
5191 :
5192 : if constexpr (COMPUTE_OTHER_STATS)
5193 : {
5194 : // Extract even-8bit values
5195 4514 : const GDALm256i ymm_even = GDALmm256_and_si256(
5196 : ymm_nodata_by_zero, ymm_mask_8bits);
5197 : // Compute square of those 16 values as 32 bit result
5198 : // and add adjacent pairs
5199 : const GDALm256i ymm_even_square =
5200 4514 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5201 : // Add to the sumsquare accumulator
5202 : ymm_sumsquare =
5203 4514 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5204 :
5205 : // Extract odd-8bit values
5206 : const GDALm256i ymm_odd =
5207 4514 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
5208 : const GDALm256i ymm_odd_square =
5209 4514 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5210 : ymm_sumsquare =
5211 4514 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5212 :
5213 : // Now compute the sums
5214 4514 : ymm_sum = GDALmm256_add_epi32(
5215 : ymm_sum,
5216 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
5217 : }
5218 : }
5219 :
5220 : if constexpr (COMPUTE_OTHER_STATS)
5221 : {
5222 33 : GUInt32 *panCoutNoDataMul255 = panSum;
5223 33 : GDALmm256_store_si256(
5224 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
5225 : ymm_count_nodata_mul_255);
5226 :
5227 33 : nSampleCount += (i - iInit);
5228 :
5229 33 : nValidCount +=
5230 33 : (i - iInit) -
5231 33 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
5232 33 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
5233 : 255;
5234 :
5235 33 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5236 : ymm_sum);
5237 33 : GDALmm256_store_si256(
5238 : reinterpret_cast<GDALm256i *>(panSumSquare),
5239 : ymm_sumsquare);
5240 33 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5241 33 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5242 33 : panSumSquare[1] + panSumSquare[2] +
5243 33 : panSumSquare[3] + panSumSquare[4] +
5244 33 : panSumSquare[5] + panSumSquare[6] +
5245 : panSumSquare[7];
5246 : }
5247 : }
5248 :
5249 1240 : if (bComputeMinMax)
5250 : {
5251 1209 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
5252 : ymm_min);
5253 1209 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
5254 : ymm_max);
5255 39897 : for (int j = 0; j < 32; j++)
5256 : {
5257 38688 : if (pabyMin[j] < nMin)
5258 32 : nMin = pabyMin[j];
5259 38688 : if (pabyMax[j] > nMax)
5260 157 : nMax = pabyMax[j];
5261 : }
5262 : }
5263 :
5264 : if constexpr (COMPUTE_OTHER_STATS)
5265 : {
5266 33 : nSampleCount += nBlockPixels - i;
5267 : }
5268 29810 : for (; i < nBlockPixels; i++)
5269 : {
5270 28570 : const GUInt32 nValue = pData[i];
5271 28570 : if (nValue == nNoDataValue)
5272 24923 : continue;
5273 3647 : if (nValue < nMin)
5274 1 : nMin = nValue;
5275 3647 : if (nValue > nMax)
5276 13 : nMax = nValue;
5277 : if constexpr (COMPUTE_OTHER_STATS)
5278 : {
5279 110 : nValidCount++;
5280 110 : nSum += nValue;
5281 110 : nSumSquare +=
5282 110 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5283 110 : nValue;
5284 : }
5285 1240 : }
5286 : }
5287 26573 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
5288 : {
5289 14941 : if (nMin > 0)
5290 : {
5291 1993 : if (nMax < 255)
5292 : {
5293 : ComputeStatisticsByteNoNodata<true, true,
5294 1464 : COMPUTE_OTHER_STATS>(
5295 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5296 : nSampleCount, nValidCount);
5297 : }
5298 : else
5299 : {
5300 : ComputeStatisticsByteNoNodata<true, false,
5301 529 : COMPUTE_OTHER_STATS>(
5302 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5303 : nSampleCount, nValidCount);
5304 : }
5305 : }
5306 : else
5307 : {
5308 12948 : if (nMax < 255)
5309 : {
5310 : ComputeStatisticsByteNoNodata<false, true,
5311 9481 : COMPUTE_OTHER_STATS>(
5312 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5313 : nSampleCount, nValidCount);
5314 : }
5315 : else
5316 : {
5317 : ComputeStatisticsByteNoNodata<false, false,
5318 3467 : COMPUTE_OTHER_STATS>(
5319 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5320 : nSampleCount, nValidCount);
5321 : }
5322 : }
5323 : }
5324 10407 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
5325 27 : (nBlockXSize % 32) == 0)
5326 : {
5327 3983 : for (int iY = 0; iY < nYCheck; iY++)
5328 : {
5329 3956 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
5330 3956 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
5331 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5332 27 : }
5333 : }
5334 : else
5335 : {
5336 11605 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
5337 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5338 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5339 : }
5340 27813 : }
5341 : };
5342 :
5343 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
5344 286 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
5345 : GUIntBig i)
5346 : {
5347 286 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
5348 286 : }
5349 :
5350 : // AVX2/SSE2 optimization for GUInt16 case
5351 : template <bool COMPUTE_OTHER_STATS>
5352 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
5353 : {
5354 1227 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5355 : // assumed to be aligned on 128 bits
5356 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
5357 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5358 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5359 : GUIntBig &nValidCount)
5360 : {
5361 1227 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5362 1227 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
5363 : {
5364 1048 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
5365 :
5366 1048 : GPtrDiff_t i = 0;
5367 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
5368 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
5369 : // Furthermore the shift is also needed to use madd_epi16
5370 1048 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
5371 1048 : GDALm256i ymm_min = GDALmm256_load_si256(
5372 1048 : reinterpret_cast<const GDALm256i *>(pData + i));
5373 1048 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
5374 1048 : GDALm256i ymm_max = ymm_min;
5375 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5376 1048 : ZERO256; // holds 4 uint64 sums
5377 :
5378 : // Make sure that sum can fit on uint32
5379 : // * 8 since we can hold 8 sums per vector register
5380 1048 : const int nMaxIterationsPerInnerLoop =
5381 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
5382 1048 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5383 1048 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5384 1048 : nOuterLoops++;
5385 :
5386 1048 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
5387 : [[maybe_unused]] const auto ymm_mask_16bits =
5388 1048 : GDALmm256_set1_epi32(0xFFFF);
5389 : [[maybe_unused]] const auto ymm_mask_32bits =
5390 1048 : GDALmm256_set1_epi64x(0xFFFFFFFF);
5391 :
5392 1048 : GUIntBig nSumThis = 0;
5393 2120 : for (int k = 0; k < nOuterLoops; k++)
5394 : {
5395 1072 : const auto iMax =
5396 1072 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5397 :
5398 : [[maybe_unused]] GDALm256i ymm_sum =
5399 1072 : ZERO256; // holds 8 uint32 sums
5400 957276 : for (; i + 15 < iMax; i += 16)
5401 : {
5402 956204 : const GDALm256i ymm = GDALmm256_load_si256(
5403 956204 : reinterpret_cast<const GDALm256i *>(pData + i));
5404 : const GDALm256i ymm_shifted =
5405 956204 : GDALmm256_add_epi16(ymm, ymm_m32768);
5406 956204 : if (bComputeMinMax)
5407 : {
5408 947185 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
5409 947185 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
5410 : }
5411 :
5412 : if constexpr (COMPUTE_OTHER_STATS)
5413 : {
5414 : // Note: the int32 range can overflow for (0-32768)^2 +
5415 : // (0-32768)^2 = 0x80000000, but as we know the result
5416 : // is positive, this is OK as we interpret is a uint32.
5417 : const GDALm256i ymm_square =
5418 97378 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
5419 97378 : ymm_sumsquare = GDALmm256_add_epi64(
5420 : ymm_sumsquare,
5421 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
5422 97378 : ymm_sumsquare = GDALmm256_add_epi64(
5423 : ymm_sumsquare,
5424 : GDALmm256_srli_epi64(ymm_square, 32));
5425 :
5426 : // Now compute the sums
5427 97378 : ymm_sum = GDALmm256_add_epi32(
5428 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
5429 97378 : ymm_sum = GDALmm256_add_epi32(
5430 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
5431 : }
5432 : }
5433 :
5434 : if constexpr (COMPUTE_OTHER_STATS)
5435 : {
5436 : GUInt32 anSum[8];
5437 286 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
5438 : ymm_sum);
5439 286 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
5440 286 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
5441 286 : anSum[6] + anSum[7];
5442 : }
5443 : }
5444 :
5445 1048 : if (bComputeMinMax)
5446 : {
5447 : GUInt16 anMin[16];
5448 : GUInt16 anMax[16];
5449 :
5450 : // Unshift the result
5451 1007 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
5452 1007 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
5453 1007 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
5454 : ymm_min);
5455 1007 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
5456 : ymm_max);
5457 17119 : for (int j = 0; j < 16; j++)
5458 : {
5459 16112 : if (anMin[j] < nMin)
5460 339 : nMin = anMin[j];
5461 16112 : if (anMax[j] > nMax)
5462 479 : nMax = anMax[j];
5463 : }
5464 : }
5465 :
5466 : if constexpr (COMPUTE_OTHER_STATS)
5467 : {
5468 : GUIntBig anSumSquare[4];
5469 286 : GDALmm256_storeu_si256(
5470 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
5471 286 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
5472 : anSumSquare[3];
5473 :
5474 : // Unshift the sum of squares
5475 286 : UnshiftSumSquare(nSumSquare, nSumThis,
5476 : static_cast<GUIntBig>(i));
5477 :
5478 286 : nSum += nSumThis;
5479 :
5480 608 : for (; i < nBlockPixels; i++)
5481 : {
5482 322 : const GUInt32 nValue = pData[i];
5483 322 : if (nValue < nMin)
5484 1 : nMin = nValue;
5485 322 : if (nValue > nMax)
5486 1 : nMax = nValue;
5487 322 : nSum += nValue;
5488 322 : nSumSquare +=
5489 322 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5490 322 : nValue;
5491 : }
5492 :
5493 286 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5494 286 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5495 1048 : }
5496 : }
5497 : else
5498 : {
5499 179 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
5500 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5501 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5502 : }
5503 1227 : }
5504 : };
5505 :
5506 : #endif
5507 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
5508 : // defined(_MSC_VER))
5509 :
5510 : #endif // CPL_HAS_GINT64
5511 :
5512 : /************************************************************************/
5513 : /* GetPixelValue() */
5514 : /************************************************************************/
5515 :
5516 19828500 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
5517 : const void *pData, GPtrDiff_t iOffset,
5518 : bool bGotNoDataValue, double dfNoDataValue,
5519 : bool bGotFloatNoDataValue,
5520 : float fNoDataValue, bool &bValid)
5521 : {
5522 19828500 : bValid = true;
5523 19828500 : double dfValue = 0;
5524 19828500 : switch (eDataType)
5525 : {
5526 1413670 : case GDT_Byte:
5527 : {
5528 1413670 : if (bSignedByte)
5529 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
5530 : else
5531 1413480 : dfValue = static_cast<const GByte *>(pData)[iOffset];
5532 1413670 : break;
5533 : }
5534 10405 : case GDT_Int8:
5535 10405 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
5536 10405 : break;
5537 4000 : case GDT_UInt16:
5538 4000 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
5539 4000 : break;
5540 60192 : case GDT_Int16:
5541 60192 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
5542 60192 : break;
5543 27596 : case GDT_UInt32:
5544 27596 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
5545 27596 : break;
5546 460158 : case GDT_Int32:
5547 460158 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
5548 460158 : break;
5549 2598 : case GDT_UInt64:
5550 2598 : dfValue = static_cast<double>(
5551 2598 : static_cast<const std::uint64_t *>(pData)[iOffset]);
5552 2598 : break;
5553 2598 : case GDT_Int64:
5554 2598 : dfValue = static_cast<double>(
5555 2598 : static_cast<const std::int64_t *>(pData)[iOffset]);
5556 2598 : break;
5557 17482900 : case GDT_Float32:
5558 : {
5559 17482900 : const float fValue = static_cast<const float *>(pData)[iOffset];
5560 30693000 : if (CPLIsNan(fValue) ||
5561 13210000 : (bGotFloatNoDataValue && ARE_REAL_EQUAL(fValue, fNoDataValue)))
5562 : {
5563 119858 : bValid = false;
5564 119858 : return 0.0;
5565 : }
5566 17363100 : dfValue = fValue;
5567 17363100 : return dfValue;
5568 : }
5569 347293 : case GDT_Float64:
5570 347293 : dfValue = static_cast<const double *>(pData)[iOffset];
5571 347293 : if (CPLIsNan(dfValue))
5572 : {
5573 50 : bValid = false;
5574 50 : return 0.0;
5575 : }
5576 347243 : break;
5577 2692 : case GDT_CInt16:
5578 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
5579 2692 : break;
5580 2692 : case GDT_CInt32:
5581 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
5582 2692 : break;
5583 5812 : case GDT_CFloat32:
5584 5812 : dfValue = static_cast<const float *>(pData)[iOffset * 2];
5585 5812 : if (CPLIsNan(dfValue))
5586 : {
5587 0 : bValid = false;
5588 0 : return 0.0;
5589 : }
5590 5812 : break;
5591 5892 : case GDT_CFloat64:
5592 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
5593 5892 : if (CPLIsNan(dfValue))
5594 : {
5595 0 : bValid = false;
5596 0 : return 0.0;
5597 : }
5598 5892 : break;
5599 0 : case GDT_Unknown:
5600 : case GDT_TypeCount:
5601 0 : CPLAssert(false);
5602 : break;
5603 : }
5604 :
5605 2345550 : if (bGotNoDataValue && ARE_REAL_EQUAL(dfValue, dfNoDataValue))
5606 : {
5607 28624 : bValid = false;
5608 28624 : return 0.0;
5609 : }
5610 2316920 : return dfValue;
5611 : }
5612 :
5613 : /************************************************************************/
5614 : /* SetValidPercent() */
5615 : /************************************************************************/
5616 :
5617 : //! @cond Doxygen_Suppress
5618 : /**
5619 : * \brief Set percentage of valid (not nodata) pixels.
5620 : *
5621 : * Stores the percentage of valid pixels in the metadata item
5622 : * STATISTICS_VALID_PERCENT
5623 : *
5624 : * @param nSampleCount Number of sampled pixels.
5625 : *
5626 : * @param nValidCount Number of valid pixels.
5627 : */
5628 :
5629 455 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
5630 : GUIntBig nValidCount)
5631 : {
5632 455 : if (nValidCount == 0)
5633 : {
5634 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
5635 : }
5636 443 : else if (nValidCount == nSampleCount)
5637 : {
5638 402 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
5639 : }
5640 : else /* nValidCount < nSampleCount */
5641 : {
5642 41 : char szValue[128] = {0};
5643 :
5644 : /* percentage is only an indicator: limit precision */
5645 41 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
5646 41 : 100. * static_cast<double>(nValidCount) / nSampleCount);
5647 :
5648 41 : if (EQUAL(szValue, "100"))
5649 : {
5650 : /* don't set 100 percent valid
5651 : * because some of the sampled pixels were nodata */
5652 0 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
5653 : }
5654 : else
5655 : {
5656 41 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
5657 : }
5658 : }
5659 455 : }
5660 :
5661 : //! @endcond
5662 :
5663 : /************************************************************************/
5664 : /* ComputeStatistics() */
5665 : /************************************************************************/
5666 :
5667 : /**
5668 : * \brief Compute image statistics.
5669 : *
5670 : * Returns the minimum, maximum, mean and standard deviation of all
5671 : * pixel values in this band. If approximate statistics are sufficient,
5672 : * the bApproxOK flag can be set to true in which case overviews, or a
5673 : * subset of image tiles may be used in computing the statistics.
5674 : *
5675 : * Once computed, the statistics will generally be "set" back on the
5676 : * raster band using SetStatistics().
5677 : *
5678 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
5679 : *
5680 : * This method is the same as the C function GDALComputeRasterStatistics().
5681 : *
5682 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5683 : * or a subset of all tiles.
5684 : *
5685 : * @param pdfMin Location into which to load image minimum (may be NULL).
5686 : *
5687 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5688 : *
5689 : * @param pdfMean Location into which to load image mean (may be NULL).
5690 : *
5691 : * @param pdfStdDev Location into which to load image standard deviation
5692 : * (may be NULL).
5693 : *
5694 : * @param pfnProgress a function to call to report progress, or NULL.
5695 : *
5696 : * @param pProgressData application data to pass to the progress function.
5697 : *
5698 : * @return CE_None on success, or CE_Failure if an error occurs or processing
5699 : * is terminated by the user.
5700 : */
5701 :
5702 440 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
5703 : double *pdfMax, double *pdfMean,
5704 : double *pdfStdDev,
5705 : GDALProgressFunc pfnProgress,
5706 : void *pProgressData)
5707 :
5708 : {
5709 440 : if (pfnProgress == nullptr)
5710 151 : pfnProgress = GDALDummyProgress;
5711 :
5712 : /* -------------------------------------------------------------------- */
5713 : /* If we have overview bands, use them for statistics. */
5714 : /* -------------------------------------------------------------------- */
5715 440 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
5716 : {
5717 : GDALRasterBand *poBand =
5718 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
5719 :
5720 3 : if (poBand != this)
5721 : {
5722 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
5723 : pdfMean, pdfStdDev,
5724 3 : pfnProgress, pProgressData);
5725 3 : if (eErr == CE_None)
5726 : {
5727 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
5728 : {
5729 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
5730 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
5731 : }
5732 :
5733 : /* transfer metadata from overview band to this */
5734 : const char *pszPercentValid =
5735 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
5736 :
5737 3 : if (pszPercentValid != nullptr)
5738 : {
5739 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
5740 3 : pszPercentValid);
5741 : }
5742 : }
5743 3 : return eErr;
5744 : }
5745 : }
5746 :
5747 437 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
5748 : {
5749 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5750 0 : return CE_Failure;
5751 : }
5752 :
5753 : /* -------------------------------------------------------------------- */
5754 : /* Read actual data and compute statistics. */
5755 : /* -------------------------------------------------------------------- */
5756 : // Using Welford algorithm:
5757 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
5758 : // to compute standard deviation in a more numerically robust way than
5759 : // the difference of the sum of square values with the square of the sum.
5760 : // dfMean and dfM2 are updated at each sample.
5761 : // dfM2 is the sum of square of differences to the current mean.
5762 437 : double dfMin = std::numeric_limits<double>::max();
5763 437 : double dfMax = -std::numeric_limits<double>::max();
5764 437 : double dfMean = 0.0;
5765 437 : double dfM2 = 0.0;
5766 :
5767 : GDALRasterIOExtraArg sExtraArg;
5768 437 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
5769 :
5770 437 : int bGotNoDataValue = FALSE;
5771 437 : const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
5772 437 : bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
5773 437 : bool bGotFloatNoDataValue = false;
5774 437 : float fNoDataValue = 0.0f;
5775 437 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
5776 : fNoDataValue, bGotFloatNoDataValue);
5777 :
5778 437 : GDALRasterBand *poMaskBand = nullptr;
5779 437 : if (!bGotNoDataValue)
5780 : {
5781 412 : const int l_nMaskFlags = GetMaskFlags();
5782 428 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
5783 16 : GetColorInterpretation() != GCI_AlphaBand)
5784 : {
5785 16 : poMaskBand = GetMaskBand();
5786 : }
5787 : }
5788 :
5789 437 : bool bSignedByte = false;
5790 437 : if (eDataType == GDT_Byte)
5791 : {
5792 191 : EnablePixelTypeSignedByteWarning(false);
5793 : const char *pszPixelType =
5794 191 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
5795 191 : EnablePixelTypeSignedByteWarning(true);
5796 191 : bSignedByte =
5797 191 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
5798 : }
5799 :
5800 437 : GUIntBig nSampleCount = 0;
5801 437 : GUIntBig nValidCount = 0;
5802 :
5803 437 : if (bApproxOK && HasArbitraryOverviews())
5804 : {
5805 : /* --------------------------------------------------------------------
5806 : */
5807 : /* Figure out how much the image should be reduced to get an */
5808 : /* approximate value. */
5809 : /* --------------------------------------------------------------------
5810 : */
5811 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
5812 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
5813 :
5814 0 : int nXReduced = nRasterXSize;
5815 0 : int nYReduced = nRasterYSize;
5816 0 : if (dfReduction > 1.0)
5817 : {
5818 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
5819 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
5820 :
5821 : // Catch the case of huge resizing ratios here
5822 0 : if (nXReduced == 0)
5823 0 : nXReduced = 1;
5824 0 : if (nYReduced == 0)
5825 0 : nYReduced = 1;
5826 : }
5827 :
5828 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
5829 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
5830 :
5831 : const CPLErr eErr =
5832 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
5833 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
5834 0 : if (eErr != CE_None)
5835 : {
5836 0 : CPLFree(pData);
5837 0 : return eErr;
5838 : }
5839 :
5840 0 : GByte *pabyMaskData = nullptr;
5841 0 : if (poMaskBand)
5842 : {
5843 : pabyMaskData =
5844 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
5845 0 : if (!pabyMaskData)
5846 : {
5847 0 : CPLFree(pData);
5848 0 : return CE_Failure;
5849 : }
5850 :
5851 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
5852 : pabyMaskData, nXReduced, nYReduced,
5853 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
5854 : {
5855 0 : CPLFree(pData);
5856 0 : CPLFree(pabyMaskData);
5857 0 : return CE_Failure;
5858 : }
5859 : }
5860 :
5861 : /* this isn't the fastest way to do this, but is easier for now */
5862 0 : for (int iY = 0; iY < nYReduced; iY++)
5863 : {
5864 0 : for (int iX = 0; iX < nXReduced; iX++)
5865 : {
5866 0 : const int iOffset = iX + iY * nXReduced;
5867 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
5868 0 : continue;
5869 :
5870 0 : bool bValid = true;
5871 : double dfValue =
5872 0 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
5873 0 : CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
5874 0 : bGotFloatNoDataValue, fNoDataValue, bValid);
5875 0 : if (!bValid)
5876 0 : continue;
5877 :
5878 0 : dfMin = std::min(dfMin, dfValue);
5879 0 : dfMax = std::max(dfMax, dfValue);
5880 :
5881 0 : nValidCount++;
5882 0 : const double dfDelta = dfValue - dfMean;
5883 0 : dfMean += dfDelta / nValidCount;
5884 0 : dfM2 += dfDelta * (dfValue - dfMean);
5885 : }
5886 : }
5887 :
5888 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
5889 :
5890 0 : CPLFree(pData);
5891 0 : CPLFree(pabyMaskData);
5892 : }
5893 :
5894 : else // No arbitrary overviews.
5895 : {
5896 437 : if (!InitBlockInfo())
5897 0 : return CE_Failure;
5898 :
5899 : /* --------------------------------------------------------------------
5900 : */
5901 : /* Figure out the ratio of blocks we will read to get an */
5902 : /* approximate value. */
5903 : /* --------------------------------------------------------------------
5904 : */
5905 437 : int nSampleRate = 1;
5906 437 : if (bApproxOK)
5907 : {
5908 40 : nSampleRate = static_cast<int>(std::max(
5909 80 : 1.0,
5910 40 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
5911 : // We want to avoid probing only the first column of blocks for
5912 : // a square shaped raster, because it is not unlikely that it may
5913 : // be padding only (#6378)
5914 40 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
5915 2 : nSampleRate += 1;
5916 : }
5917 437 : if (nSampleRate == 1)
5918 404 : bApproxOK = false;
5919 :
5920 : #ifdef CPL_HAS_GINT64
5921 : // Particular case for GDT_Byte that only use integral types for all
5922 : // intermediate computations. Only possible if the number of pixels
5923 : // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
5924 : // can fit on a uint64. Should be 99.99999% of cases.
5925 : // For GUInt16, this limits to raster of 4 giga pixels
5926 437 : if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
5927 176 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
5928 176 : nSampleRate <
5929 176 : GUINTBIG_MAX / (255U * 255U) /
5930 176 : (static_cast<GUInt64>(nBlockXSize) *
5931 176 : static_cast<GUInt64>(nBlockYSize))) ||
5932 261 : (eDataType == GDT_UInt16 &&
5933 25 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
5934 25 : nSampleRate <
5935 25 : GUINTBIG_MAX / (65535U * 65535U) /
5936 25 : (static_cast<GUInt64>(nBlockXSize) *
5937 25 : static_cast<GUInt64>(nBlockYSize))))
5938 : {
5939 201 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
5940 201 : GUInt32 nMin = nMaxValueType;
5941 201 : GUInt32 nMax = 0;
5942 201 : GUIntBig nSum = 0;
5943 201 : GUIntBig nSumSquare = 0;
5944 : // If no valid nodata, map to invalid value (256 for Byte)
5945 201 : const GUInt32 nNoDataValue =
5946 21 : (bGotNoDataValue && dfNoDataValue >= 0 &&
5947 21 : dfNoDataValue <= nMaxValueType &&
5948 21 : fabs(dfNoDataValue -
5949 21 : static_cast<GUInt32>(dfNoDataValue + 1e-10)) < 1e-10)
5950 222 : ? static_cast<GUInt32>(dfNoDataValue + 1e-10)
5951 : : nMaxValueType + 1;
5952 :
5953 201 : for (int iSampleBlock = 0;
5954 12380 : iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
5955 12179 : iSampleBlock += nSampleRate)
5956 : {
5957 12179 : const int iYBlock = iSampleBlock / nBlocksPerRow;
5958 12179 : const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
5959 :
5960 : GDALRasterBlock *const poBlock =
5961 12179 : GetLockedBlockRef(iXBlock, iYBlock);
5962 12179 : if (poBlock == nullptr)
5963 0 : return CE_Failure;
5964 :
5965 12179 : void *const pData = poBlock->GetDataRef();
5966 :
5967 12179 : int nXCheck = 0, nYCheck = 0;
5968 12179 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
5969 :
5970 12179 : if (eDataType == GDT_Byte)
5971 : {
5972 : ComputeStatisticsInternal<
5973 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
5974 11842 : f(nXCheck, nBlockXSize, nYCheck,
5975 : static_cast<const GByte *>(pData),
5976 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
5977 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5978 : }
5979 : else
5980 : {
5981 : ComputeStatisticsInternal<
5982 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
5983 337 : f(nXCheck, nBlockXSize, nYCheck,
5984 : static_cast<const GUInt16 *>(pData),
5985 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
5986 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5987 : }
5988 :
5989 12179 : poBlock->DropLock();
5990 :
5991 12179 : if (!pfnProgress(iSampleBlock /
5992 12179 : static_cast<double>(nBlocksPerRow *
5993 12179 : nBlocksPerColumn),
5994 : "Compute Statistics", pProgressData))
5995 : {
5996 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
5997 : "User terminated");
5998 0 : return CE_Failure;
5999 : }
6000 : }
6001 :
6002 201 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6003 : {
6004 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6005 0 : return CE_Failure;
6006 : }
6007 :
6008 : /* --------------------------------------------------------------------
6009 : */
6010 : /* Save computed information. */
6011 : /* --------------------------------------------------------------------
6012 : */
6013 201 : if (nValidCount)
6014 192 : dfMean = static_cast<double>(nSum) / nValidCount;
6015 :
6016 : // To avoid potential precision issues when doing the difference,
6017 : // we need to do that computation on 128 bit rather than casting
6018 : // to double
6019 : const GDALUInt128 nTmpForStdDev(
6020 201 : GDALUInt128::Mul(nSumSquare, nValidCount) -
6021 402 : GDALUInt128::Mul(nSum, nSum));
6022 : const double dfStdDev =
6023 201 : nValidCount > 0
6024 201 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6025 201 : : 0.0;
6026 :
6027 201 : if (nValidCount > 0)
6028 : {
6029 192 : if (bApproxOK)
6030 : {
6031 23 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6032 : }
6033 169 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6034 : {
6035 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6036 : }
6037 192 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
6038 : }
6039 :
6040 201 : SetValidPercent(nSampleCount, nValidCount);
6041 :
6042 : /* --------------------------------------------------------------------
6043 : */
6044 : /* Record results. */
6045 : /* --------------------------------------------------------------------
6046 : */
6047 201 : if (pdfMin != nullptr)
6048 198 : *pdfMin = nValidCount ? nMin : 0;
6049 201 : if (pdfMax != nullptr)
6050 198 : *pdfMax = nValidCount ? nMax : 0;
6051 :
6052 201 : if (pdfMean != nullptr)
6053 194 : *pdfMean = dfMean;
6054 :
6055 201 : if (pdfStdDev != nullptr)
6056 194 : *pdfStdDev = dfStdDev;
6057 :
6058 201 : if (nValidCount > 0)
6059 192 : return CE_None;
6060 :
6061 9 : ReportError(CE_Failure, CPLE_AppDefined,
6062 : "Failed to compute statistics, no valid pixels found "
6063 : "in sampling.");
6064 9 : return CE_Failure;
6065 : }
6066 : #endif
6067 :
6068 236 : GByte *pabyMaskData = nullptr;
6069 236 : if (poMaskBand)
6070 : {
6071 : pabyMaskData = static_cast<GByte *>(
6072 16 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6073 16 : if (!pabyMaskData)
6074 : {
6075 0 : return CE_Failure;
6076 : }
6077 : }
6078 :
6079 236 : for (int iSampleBlock = 0;
6080 5483 : iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
6081 5247 : iSampleBlock += nSampleRate)
6082 : {
6083 5247 : const int iYBlock = iSampleBlock / nBlocksPerRow;
6084 5247 : const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
6085 :
6086 : GDALRasterBlock *const poBlock =
6087 5247 : GetLockedBlockRef(iXBlock, iYBlock);
6088 5247 : if (poBlock == nullptr)
6089 : {
6090 0 : CPLFree(pabyMaskData);
6091 0 : return CE_Failure;
6092 : }
6093 :
6094 5247 : void *const pData = poBlock->GetDataRef();
6095 :
6096 5247 : int nXCheck = 0, nYCheck = 0;
6097 5247 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6098 :
6099 5348 : if (poMaskBand &&
6100 101 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6101 101 : iYBlock * nBlockYSize, nXCheck, nYCheck,
6102 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6103 101 : 0, nBlockXSize, nullptr) != CE_None)
6104 : {
6105 0 : CPLFree(pabyMaskData);
6106 0 : poBlock->DropLock();
6107 0 : return CE_Failure;
6108 : }
6109 :
6110 : // This isn't the fastest way to do this, but is easier for now.
6111 10678 : for (int iY = 0; iY < nYCheck; iY++)
6112 : {
6113 4342130 : for (int iX = 0; iX < nXCheck; iX++)
6114 : {
6115 4336700 : const GPtrDiff_t iOffset =
6116 4336700 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6117 4336700 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6118 109939 : continue;
6119 :
6120 4326820 : bool bValid = true;
6121 4326820 : double dfValue = GetPixelValue(
6122 : eDataType, bSignedByte, pData, iOffset,
6123 4326820 : CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
6124 4326820 : bGotFloatNoDataValue, fNoDataValue, bValid);
6125 :
6126 4326820 : if (!bValid)
6127 100068 : continue;
6128 :
6129 4226760 : dfMin = std::min(dfMin, dfValue);
6130 4226760 : dfMax = std::max(dfMax, dfValue);
6131 :
6132 4226760 : nValidCount++;
6133 4226760 : const double dfDelta = dfValue - dfMean;
6134 4226760 : dfMean += dfDelta / nValidCount;
6135 4226760 : dfM2 += dfDelta * (dfValue - dfMean);
6136 : }
6137 : }
6138 :
6139 5247 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6140 :
6141 5247 : poBlock->DropLock();
6142 :
6143 5247 : if (!pfnProgress(
6144 : iSampleBlock /
6145 5247 : static_cast<double>(nBlocksPerRow * nBlocksPerColumn),
6146 : "Compute Statistics", pProgressData))
6147 : {
6148 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6149 0 : CPLFree(pabyMaskData);
6150 0 : return CE_Failure;
6151 : }
6152 : }
6153 :
6154 236 : CPLFree(pabyMaskData);
6155 : }
6156 :
6157 236 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6158 : {
6159 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6160 0 : return CE_Failure;
6161 : }
6162 :
6163 : /* -------------------------------------------------------------------- */
6164 : /* Save computed information. */
6165 : /* -------------------------------------------------------------------- */
6166 236 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
6167 :
6168 236 : if (nValidCount > 0)
6169 : {
6170 235 : if (bApproxOK)
6171 : {
6172 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6173 : }
6174 227 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6175 : {
6176 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6177 : }
6178 235 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6179 : }
6180 : else
6181 : {
6182 1 : dfMin = 0.0;
6183 1 : dfMax = 0.0;
6184 : }
6185 :
6186 236 : SetValidPercent(nSampleCount, nValidCount);
6187 :
6188 : /* -------------------------------------------------------------------- */
6189 : /* Record results. */
6190 : /* -------------------------------------------------------------------- */
6191 236 : if (pdfMin != nullptr)
6192 233 : *pdfMin = dfMin;
6193 236 : if (pdfMax != nullptr)
6194 233 : *pdfMax = dfMax;
6195 :
6196 236 : if (pdfMean != nullptr)
6197 231 : *pdfMean = dfMean;
6198 :
6199 236 : if (pdfStdDev != nullptr)
6200 231 : *pdfStdDev = dfStdDev;
6201 :
6202 236 : if (nValidCount > 0)
6203 235 : return CE_None;
6204 :
6205 1 : ReportError(
6206 : CE_Failure, CPLE_AppDefined,
6207 : "Failed to compute statistics, no valid pixels found in sampling.");
6208 1 : return CE_Failure;
6209 : }
6210 :
6211 : /************************************************************************/
6212 : /* GDALComputeRasterStatistics() */
6213 : /************************************************************************/
6214 :
6215 : /**
6216 : * \brief Compute image statistics.
6217 : *
6218 : * @see GDALRasterBand::ComputeStatistics()
6219 : */
6220 :
6221 137 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
6222 : int bApproxOK, double *pdfMin,
6223 : double *pdfMax, double *pdfMean,
6224 : double *pdfStdDev,
6225 : GDALProgressFunc pfnProgress,
6226 : void *pProgressData)
6227 :
6228 : {
6229 137 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
6230 :
6231 137 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6232 :
6233 137 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
6234 137 : pdfStdDev, pfnProgress, pProgressData);
6235 : }
6236 :
6237 : /************************************************************************/
6238 : /* SetStatistics() */
6239 : /************************************************************************/
6240 :
6241 : /**
6242 : * \brief Set statistics on band.
6243 : *
6244 : * This method can be used to store min/max/mean/standard deviation
6245 : * statistics on a raster band.
6246 : *
6247 : * The default implementation stores them as metadata, and will only work
6248 : * on formats that can save arbitrary metadata. This method cannot detect
6249 : * whether metadata will be properly saved and so may return CE_None even
6250 : * if the statistics will never be saved.
6251 : *
6252 : * This method is the same as the C function GDALSetRasterStatistics().
6253 : *
6254 : * @param dfMin minimum pixel value.
6255 : *
6256 : * @param dfMax maximum pixel value.
6257 : *
6258 : * @param dfMean mean (average) of all pixel values.
6259 : *
6260 : * @param dfStdDev Standard deviation of all pixel values.
6261 : *
6262 : * @return CE_None on success or CE_Failure on failure.
6263 : */
6264 :
6265 453 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
6266 : double dfStdDev)
6267 :
6268 : {
6269 453 : char szValue[128] = {0};
6270 :
6271 453 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
6272 453 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
6273 :
6274 453 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
6275 453 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
6276 :
6277 453 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
6278 453 : SetMetadataItem("STATISTICS_MEAN", szValue);
6279 :
6280 453 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
6281 453 : SetMetadataItem("STATISTICS_STDDEV", szValue);
6282 :
6283 453 : return CE_None;
6284 : }
6285 :
6286 : /************************************************************************/
6287 : /* GDALSetRasterStatistics() */
6288 : /************************************************************************/
6289 :
6290 : /**
6291 : * \brief Set statistics on band.
6292 : *
6293 : * @see GDALRasterBand::SetStatistics()
6294 : */
6295 :
6296 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
6297 : double dfMax, double dfMean,
6298 : double dfStdDev)
6299 :
6300 : {
6301 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
6302 :
6303 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6304 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
6305 : }
6306 :
6307 : /************************************************************************/
6308 : /* ComputeRasterMinMax() */
6309 : /************************************************************************/
6310 :
6311 : template <class T, bool HAS_NODATA>
6312 133584 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
6313 : T *pMax)
6314 : {
6315 133584 : T min0 = *pMin;
6316 133584 : T max0 = *pMax;
6317 133584 : T min1 = *pMin;
6318 133584 : T max1 = *pMax;
6319 : size_t i;
6320 950452 : for (i = 0; i + 1 < nElts; i += 2)
6321 : {
6322 804394 : if (!HAS_NODATA || buffer[i] != nodataValue)
6323 : {
6324 815689 : min0 = std::min(min0, buffer[i]);
6325 815689 : max0 = std::max(max0, buffer[i]);
6326 : }
6327 804394 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
6328 : {
6329 815902 : min1 = std::min(min1, buffer[i + 1]);
6330 815902 : max1 = std::max(max1, buffer[i + 1]);
6331 : }
6332 : }
6333 133584 : T min = std::min(min0, min1);
6334 133584 : T max = std::max(max0, max1);
6335 133584 : if (i < nElts)
6336 : {
6337 118171 : if (!HAS_NODATA || buffer[i] != nodataValue)
6338 : {
6339 118171 : min = std::min(min, buffer[i]);
6340 118171 : max = std::max(max, buffer[i]);
6341 : }
6342 : }
6343 133584 : *pMin = min;
6344 133584 : *pMax = max;
6345 133584 : }
6346 :
6347 : template <GDALDataType eDataType, bool bSignedByte>
6348 9390 : static void ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
6349 : int nBlockXSize, bool bGotNoDataValue,
6350 : double dfNoDataValue,
6351 : bool bGotFloatNoDataValue, float fNoDataValue,
6352 : const GByte *pabyMaskData, double &dfMin,
6353 : double &dfMax)
6354 : {
6355 9390 : double dfLocalMin = dfMin;
6356 9390 : double dfLocalMax = dfMax;
6357 :
6358 38900 : for (int iY = 0; iY < nYCheck; iY++)
6359 : {
6360 15625520 : for (int iX = 0; iX < nXCheck; iX++)
6361 : {
6362 15595996 : const GPtrDiff_t iOffset =
6363 15595996 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6364 15595996 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6365 142705 : continue;
6366 15501755 : bool bValid = true;
6367 15501755 : double dfValue = GetPixelValue(
6368 : eDataType, bSignedByte, pData, iOffset, bGotNoDataValue,
6369 : dfNoDataValue, bGotFloatNoDataValue, fNoDataValue, bValid);
6370 15501755 : if (!bValid)
6371 48464 : continue;
6372 :
6373 15453245 : dfLocalMin = std::min(dfLocalMin, dfValue);
6374 15453245 : dfLocalMax = std::max(dfLocalMax, dfValue);
6375 : }
6376 : }
6377 :
6378 9390 : dfMin = dfLocalMin;
6379 9390 : dfMax = dfLocalMax;
6380 9390 : }
6381 :
6382 9390 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
6383 : bool bSignedByte, int nXCheck, int nYCheck,
6384 : int nBlockXSize, bool bGotNoDataValue,
6385 : double dfNoDataValue,
6386 : bool bGotFloatNoDataValue, float fNoDataValue,
6387 : const GByte *pabyMaskData, double &dfMin,
6388 : double &dfMax)
6389 : {
6390 9390 : switch (eDataType)
6391 : {
6392 0 : case GDT_Unknown:
6393 0 : CPLAssert(false);
6394 : break;
6395 672 : case GDT_Byte:
6396 672 : if (bSignedByte)
6397 : {
6398 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
6399 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6400 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6401 : }
6402 : else
6403 : {
6404 669 : ComputeMinMaxGeneric<GDT_Byte, false>(
6405 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6406 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6407 : }
6408 672 : break;
6409 102 : case GDT_Int8:
6410 102 : ComputeMinMaxGeneric<GDT_Int8, false>(
6411 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6412 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6413 102 : break;
6414 200 : case GDT_UInt16:
6415 200 : ComputeMinMaxGeneric<GDT_UInt16, false>(
6416 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6417 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6418 200 : break;
6419 1 : case GDT_Int16:
6420 1 : ComputeMinMaxGeneric<GDT_Int16, false>(
6421 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6422 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6423 1 : break;
6424 197 : case GDT_UInt32:
6425 197 : ComputeMinMaxGeneric<GDT_UInt32, false>(
6426 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6427 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6428 197 : break;
6429 1105 : case GDT_Int32:
6430 1105 : ComputeMinMaxGeneric<GDT_Int32, false>(
6431 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6432 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6433 1105 : break;
6434 12 : case GDT_UInt64:
6435 12 : ComputeMinMaxGeneric<GDT_UInt64, false>(
6436 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6437 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6438 12 : break;
6439 12 : case GDT_Int64:
6440 12 : ComputeMinMaxGeneric<GDT_Int64, false>(
6441 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6442 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6443 12 : break;
6444 5664 : case GDT_Float32:
6445 5664 : ComputeMinMaxGeneric<GDT_Float32, false>(
6446 : pData, nXCheck, nYCheck, nBlockXSize, false, 0,
6447 : bGotFloatNoDataValue, fNoDataValue, pabyMaskData, dfMin, dfMax);
6448 5664 : break;
6449 1315 : case GDT_Float64:
6450 1315 : ComputeMinMaxGeneric<GDT_Float64, false>(
6451 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6452 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6453 1315 : break;
6454 9 : case GDT_CInt16:
6455 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(
6456 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6457 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6458 9 : break;
6459 9 : case GDT_CInt32:
6460 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(
6461 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6462 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6463 9 : break;
6464 75 : case GDT_CFloat32:
6465 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
6466 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6467 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6468 75 : break;
6469 17 : case GDT_CFloat64:
6470 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
6471 : pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6472 : dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6473 17 : break;
6474 0 : case GDT_TypeCount:
6475 0 : CPLAssert(false);
6476 : break;
6477 : }
6478 9390 : }
6479 :
6480 675 : static bool ComputeMinMaxGenericIterBlocks(
6481 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
6482 : int nTotalBlocks, int nSampleRate, int nBlocksPerRow, bool bGotNoDataValue,
6483 : double dfNoDataValue, bool bGotFloatNoDataValue, float fNoDataValue,
6484 : GDALRasterBand *poMaskBand, double &dfMin, double &dfMax)
6485 :
6486 : {
6487 675 : GByte *pabyMaskData = nullptr;
6488 : int nBlockXSize, nBlockYSize;
6489 675 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
6490 :
6491 675 : if (poMaskBand)
6492 : {
6493 : pabyMaskData =
6494 40 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6495 40 : if (!pabyMaskData)
6496 : {
6497 0 : return false;
6498 : }
6499 : }
6500 :
6501 10065 : for (int iSampleBlock = 0; iSampleBlock < nTotalBlocks;
6502 9390 : iSampleBlock += nSampleRate)
6503 : {
6504 9390 : const int iYBlock = iSampleBlock / nBlocksPerRow;
6505 9390 : const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
6506 :
6507 9390 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
6508 9390 : if (poBlock == nullptr)
6509 : {
6510 0 : CPLFree(pabyMaskData);
6511 0 : return false;
6512 : }
6513 :
6514 9390 : void *const pData = poBlock->GetDataRef();
6515 :
6516 9390 : int nXCheck = 0, nYCheck = 0;
6517 9390 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6518 :
6519 10261 : if (poMaskBand &&
6520 871 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6521 : iYBlock * nBlockYSize, nXCheck, nYCheck,
6522 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
6523 : nBlockXSize, nullptr) != CE_None)
6524 : {
6525 0 : poBlock->DropLock();
6526 0 : CPLFree(pabyMaskData);
6527 0 : return false;
6528 : }
6529 :
6530 9390 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
6531 9390 : nBlockXSize, CPL_TO_BOOL(bGotNoDataValue),
6532 : dfNoDataValue, bGotFloatNoDataValue, fNoDataValue,
6533 : pabyMaskData, dfMin, dfMax);
6534 :
6535 9390 : poBlock->DropLock();
6536 : }
6537 :
6538 675 : CPLFree(pabyMaskData);
6539 675 : return true;
6540 : }
6541 :
6542 : /**
6543 : * \brief Compute the min/max values for a band.
6544 : *
6545 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
6546 : * be trusted. If it doesn't work, a subsample of blocks will be read to
6547 : * get an approximate min/max. If the band has a nodata value it will
6548 : * be excluded from the minimum and maximum.
6549 : *
6550 : * If bApprox is FALSE, then all pixels will be read and used to compute
6551 : * an exact range.
6552 : *
6553 : * This method is the same as the C function GDALComputeRasterMinMax().
6554 : *
6555 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
6556 : * FALSE.
6557 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
6558 : * maximum (adfMinMax[1]) are returned.
6559 : *
6560 : * @return CE_None on success or CE_Failure on failure.
6561 : */
6562 :
6563 1487 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
6564 : {
6565 : /* -------------------------------------------------------------------- */
6566 : /* Does the driver already know the min/max? */
6567 : /* -------------------------------------------------------------------- */
6568 1487 : if (bApproxOK)
6569 : {
6570 12 : int bSuccessMin = FALSE;
6571 12 : int bSuccessMax = FALSE;
6572 :
6573 12 : double dfMin = GetMinimum(&bSuccessMin);
6574 12 : double dfMax = GetMaximum(&bSuccessMax);
6575 :
6576 12 : if (bSuccessMin && bSuccessMax)
6577 : {
6578 1 : adfMinMax[0] = dfMin;
6579 1 : adfMinMax[1] = dfMax;
6580 1 : return CE_None;
6581 : }
6582 : }
6583 :
6584 : /* -------------------------------------------------------------------- */
6585 : /* If we have overview bands, use them for min/max. */
6586 : /* -------------------------------------------------------------------- */
6587 : // cppcheck-suppress knownConditionTrueFalse
6588 1486 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6589 : {
6590 : GDALRasterBand *poBand =
6591 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6592 :
6593 0 : if (poBand != this)
6594 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
6595 : }
6596 :
6597 : /* -------------------------------------------------------------------- */
6598 : /* Read actual data and compute minimum and maximum. */
6599 : /* -------------------------------------------------------------------- */
6600 1486 : int bGotNoDataValue = FALSE;
6601 1486 : const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
6602 1486 : bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
6603 1486 : bool bGotFloatNoDataValue = false;
6604 1486 : float fNoDataValue = 0.0f;
6605 1486 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
6606 : fNoDataValue, bGotFloatNoDataValue);
6607 :
6608 1486 : GDALRasterBand *poMaskBand = nullptr;
6609 1486 : if (!bGotNoDataValue)
6610 : {
6611 1233 : const int l_nMaskFlags = GetMaskFlags();
6612 1273 : if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
6613 40 : GetColorInterpretation() != GCI_AlphaBand)
6614 : {
6615 40 : poMaskBand = GetMaskBand();
6616 : }
6617 : }
6618 :
6619 1486 : bool bSignedByte = false;
6620 1486 : if (eDataType == GDT_Byte)
6621 : {
6622 610 : EnablePixelTypeSignedByteWarning(false);
6623 : const char *pszPixelType =
6624 610 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6625 610 : EnablePixelTypeSignedByteWarning(true);
6626 610 : bSignedByte =
6627 610 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6628 : }
6629 :
6630 : GDALRasterIOExtraArg sExtraArg;
6631 1486 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6632 :
6633 2972 : GUInt32 nMin = (eDataType == GDT_Byte)
6634 1486 : ? 255
6635 : : 65535; // used for GByte & GUInt16 cases
6636 1486 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
6637 1486 : GInt16 nMinInt16 =
6638 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
6639 1486 : GInt16 nMaxInt16 =
6640 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
6641 1486 : double dfMin =
6642 : std::numeric_limits<double>::max(); // used for generic code path
6643 1486 : double dfMax =
6644 : -std::numeric_limits<double>::max(); // used for generic code path
6645 1486 : const bool bUseOptimizedPath =
6646 2353 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
6647 867 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
6648 :
6649 : const auto ComputeMinMaxForBlock =
6650 18348 : [this, bSignedByte, bGotNoDataValue, dfNoDataValue, &nMin, &nMax,
6651 : &nMinInt16, &nMaxInt16](const void *pData, int nXCheck,
6652 239679 : int nBufferWidth, int nYCheck)
6653 : {
6654 18348 : if (eDataType == GDT_Byte && !bSignedByte)
6655 : {
6656 : const bool bHasNoData =
6657 25472 : bGotNoDataValue && GDALIsValueInRange<GByte>(dfNoDataValue) &&
6658 9501 : static_cast<GByte>(dfNoDataValue) == dfNoDataValue;
6659 15971 : const GUInt32 nNoDataValue =
6660 15971 : bHasNoData ? static_cast<GByte>(dfNoDataValue) : 0;
6661 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
6662 : ComputeStatisticsInternal<GByte,
6663 : /* COMPUTE_OTHER_STATS = */ false>::
6664 15971 : f(nXCheck, nBufferWidth, nYCheck,
6665 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
6666 15971 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6667 : }
6668 2377 : else if (eDataType == GDT_UInt16)
6669 : {
6670 : const bool bHasNoData =
6671 973 : bGotNoDataValue && GDALIsValueInRange<GUInt16>(dfNoDataValue) &&
6672 83 : static_cast<GUInt16>(dfNoDataValue) == dfNoDataValue;
6673 890 : const GUInt32 nNoDataValue =
6674 890 : bHasNoData ? static_cast<GUInt16>(dfNoDataValue) : 0;
6675 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
6676 : ComputeStatisticsInternal<GUInt16,
6677 : /* COMPUTE_OTHER_STATS = */ false>::
6678 890 : f(nXCheck, nBufferWidth, nYCheck,
6679 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
6680 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6681 : }
6682 1487 : else if (eDataType == GDT_Int16)
6683 : {
6684 : const bool bHasNoData =
6685 2804 : bGotNoDataValue && GDALIsValueInRange<int16_t>(dfNoDataValue) &&
6686 1317 : static_cast<int16_t>(dfNoDataValue) == dfNoDataValue;
6687 1487 : if (bHasNoData)
6688 : {
6689 1317 : const int16_t nNoDataValue =
6690 : static_cast<int16_t>(dfNoDataValue);
6691 133629 : for (int iY = 0; iY < nYCheck; iY++)
6692 : {
6693 132312 : ComputeMinMax<int16_t, true>(
6694 132312 : static_cast<const int16_t *>(pData) +
6695 132312 : static_cast<size_t>(iY) * nBufferWidth,
6696 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
6697 : }
6698 : }
6699 : else
6700 : {
6701 1442 : for (int iY = 0; iY < nYCheck; iY++)
6702 : {
6703 1272 : ComputeMinMax<int16_t, false>(
6704 1272 : static_cast<const int16_t *>(pData) +
6705 1272 : static_cast<size_t>(iY) * nBufferWidth,
6706 : nXCheck, 0, &nMinInt16, &nMaxInt16);
6707 : }
6708 : }
6709 : }
6710 18348 : };
6711 :
6712 1486 : if (bApproxOK && HasArbitraryOverviews())
6713 : {
6714 : /* --------------------------------------------------------------------
6715 : */
6716 : /* Figure out how much the image should be reduced to get an */
6717 : /* approximate value. */
6718 : /* --------------------------------------------------------------------
6719 : */
6720 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6721 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6722 :
6723 0 : int nXReduced = nRasterXSize;
6724 0 : int nYReduced = nRasterYSize;
6725 0 : if (dfReduction > 1.0)
6726 : {
6727 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6728 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6729 :
6730 : // Catch the case of huge resizing ratios here
6731 0 : if (nXReduced == 0)
6732 0 : nXReduced = 1;
6733 0 : if (nYReduced == 0)
6734 0 : nYReduced = 1;
6735 : }
6736 :
6737 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
6738 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6739 :
6740 : const CPLErr eErr =
6741 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6742 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6743 0 : if (eErr != CE_None)
6744 : {
6745 0 : CPLFree(pData);
6746 0 : return eErr;
6747 : }
6748 :
6749 0 : GByte *pabyMaskData = nullptr;
6750 0 : if (poMaskBand)
6751 : {
6752 : pabyMaskData =
6753 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6754 0 : if (!pabyMaskData)
6755 : {
6756 0 : CPLFree(pData);
6757 0 : return CE_Failure;
6758 : }
6759 :
6760 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6761 : pabyMaskData, nXReduced, nYReduced,
6762 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
6763 : {
6764 0 : CPLFree(pData);
6765 0 : CPLFree(pabyMaskData);
6766 0 : return CE_Failure;
6767 : }
6768 : }
6769 :
6770 0 : if (bUseOptimizedPath)
6771 : {
6772 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
6773 : }
6774 : else
6775 : {
6776 0 : ComputeMinMaxGeneric(
6777 : pData, eDataType, bSignedByte, nXReduced, nYReduced, nXReduced,
6778 0 : CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
6779 : bGotFloatNoDataValue, fNoDataValue, pabyMaskData, dfMin, dfMax);
6780 : }
6781 :
6782 0 : CPLFree(pData);
6783 0 : CPLFree(pabyMaskData);
6784 : }
6785 :
6786 : else // No arbitrary overviews
6787 : {
6788 1486 : if (!InitBlockInfo())
6789 0 : return CE_Failure;
6790 :
6791 : /* --------------------------------------------------------------------
6792 : */
6793 : /* Figure out the ratio of blocks we will read to get an */
6794 : /* approximate value. */
6795 : /* --------------------------------------------------------------------
6796 : */
6797 1486 : int nSampleRate = 1;
6798 :
6799 1486 : if (bApproxOK)
6800 : {
6801 11 : nSampleRate = static_cast<int>(std::max(
6802 22 : 1.0,
6803 11 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6804 : // We want to avoid probing only the first column of blocks for
6805 : // a square shaped raster, because it is not unlikely that it may
6806 : // be padding only (#6378).
6807 11 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6808 0 : nSampleRate += 1;
6809 : }
6810 :
6811 1486 : if (bUseOptimizedPath)
6812 : {
6813 811 : for (int iSampleBlock = 0;
6814 19086 : iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
6815 18275 : iSampleBlock += nSampleRate)
6816 : {
6817 18348 : const int iYBlock = iSampleBlock / nBlocksPerRow;
6818 18348 : const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
6819 :
6820 18348 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
6821 18348 : if (poBlock == nullptr)
6822 0 : return CE_Failure;
6823 :
6824 18348 : void *const pData = poBlock->GetDataRef();
6825 :
6826 18348 : int nXCheck = 0, nYCheck = 0;
6827 18348 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6828 :
6829 18348 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
6830 :
6831 18348 : poBlock->DropLock();
6832 :
6833 18348 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
6834 4086 : nMax == 255)
6835 73 : break;
6836 : }
6837 : }
6838 : else
6839 : {
6840 675 : const int nTotalBlocks = nBlocksPerRow * nBlocksPerColumn;
6841 675 : if (!ComputeMinMaxGenericIterBlocks(
6842 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
6843 675 : nBlocksPerRow, CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
6844 : bGotFloatNoDataValue, fNoDataValue, poMaskBand, dfMin,
6845 : dfMax))
6846 : {
6847 0 : return CE_Failure;
6848 : }
6849 : }
6850 : }
6851 :
6852 1486 : if (bUseOptimizedPath)
6853 : {
6854 811 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
6855 : {
6856 709 : dfMin = nMin;
6857 709 : dfMax = nMax;
6858 : }
6859 102 : else if (eDataType == GDT_Int16)
6860 : {
6861 102 : dfMin = nMinInt16;
6862 102 : dfMax = nMaxInt16;
6863 : }
6864 : }
6865 :
6866 1486 : if (dfMin > dfMax)
6867 : {
6868 4 : adfMinMax[0] = 0;
6869 4 : adfMinMax[1] = 0;
6870 4 : ReportError(
6871 : CE_Failure, CPLE_AppDefined,
6872 : "Failed to compute min/max, no valid pixels found in sampling.");
6873 4 : return CE_Failure;
6874 : }
6875 :
6876 1482 : adfMinMax[0] = dfMin;
6877 1482 : adfMinMax[1] = dfMax;
6878 :
6879 1482 : return CE_None;
6880 : }
6881 :
6882 : /************************************************************************/
6883 : /* GDALComputeRasterMinMax() */
6884 : /************************************************************************/
6885 :
6886 : /**
6887 : * \brief Compute the min/max values for a band.
6888 : *
6889 : * @see GDALRasterBand::ComputeRasterMinMax()
6890 : *
6891 : * @note Prior to GDAL 3.6, this function returned void
6892 : */
6893 :
6894 1409 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
6895 : double adfMinMax[2])
6896 :
6897 : {
6898 1409 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
6899 :
6900 1409 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6901 1409 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
6902 : }
6903 :
6904 : /************************************************************************/
6905 : /* SetDefaultHistogram() */
6906 : /************************************************************************/
6907 :
6908 : /* FIXME : add proper documentation */
6909 : /**
6910 : * \brief Set default histogram.
6911 : *
6912 : * This method is the same as the C function GDALSetDefaultHistogram() and
6913 : * GDALSetDefaultHistogramEx()
6914 : */
6915 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
6916 : double /* dfMax */,
6917 : int /* nBuckets */,
6918 : GUIntBig * /* panHistogram */)
6919 :
6920 : {
6921 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
6922 0 : ReportError(CE_Failure, CPLE_NotSupported,
6923 : "SetDefaultHistogram() not implemented for this format.");
6924 :
6925 0 : return CE_Failure;
6926 : }
6927 :
6928 : /************************************************************************/
6929 : /* GDALSetDefaultHistogram() */
6930 : /************************************************************************/
6931 :
6932 : /**
6933 : * \brief Set default histogram.
6934 : *
6935 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
6936 : * 2 billion.
6937 : *
6938 : * @see GDALRasterBand::SetDefaultHistogram()
6939 : * @see GDALSetRasterHistogramEx()
6940 : */
6941 :
6942 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
6943 : double dfMax, int nBuckets,
6944 : int *panHistogram)
6945 :
6946 : {
6947 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
6948 :
6949 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6950 :
6951 : GUIntBig *panHistogramTemp =
6952 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
6953 0 : if (panHistogramTemp == nullptr)
6954 : {
6955 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
6956 : "Out of memory in GDALSetDefaultHistogram().");
6957 0 : return CE_Failure;
6958 : }
6959 :
6960 0 : for (int i = 0; i < nBuckets; ++i)
6961 : {
6962 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
6963 : }
6964 :
6965 : const CPLErr eErr =
6966 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
6967 :
6968 0 : CPLFree(panHistogramTemp);
6969 :
6970 0 : return eErr;
6971 : }
6972 :
6973 : /************************************************************************/
6974 : /* GDALSetDefaultHistogramEx() */
6975 : /************************************************************************/
6976 :
6977 : /**
6978 : * \brief Set default histogram.
6979 : *
6980 : * @see GDALRasterBand::SetDefaultHistogram()
6981 : *
6982 : * @since GDAL 2.0
6983 : */
6984 :
6985 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
6986 : double dfMin, double dfMax,
6987 : int nBuckets,
6988 : GUIntBig *panHistogram)
6989 :
6990 : {
6991 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
6992 :
6993 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6994 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
6995 : }
6996 :
6997 : /************************************************************************/
6998 : /* GetDefaultRAT() */
6999 : /************************************************************************/
7000 :
7001 : /**
7002 : * \brief Fetch default Raster Attribute Table.
7003 : *
7004 : * A RAT will be returned if there is a default one associated with the
7005 : * band, otherwise NULL is returned. The returned RAT is owned by the
7006 : * band and should not be deleted by the application.
7007 : *
7008 : * This method is the same as the C function GDALGetDefaultRAT().
7009 : *
7010 : * @return NULL, or a pointer to an internal RAT owned by the band.
7011 : */
7012 :
7013 92 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
7014 :
7015 : {
7016 92 : return nullptr;
7017 : }
7018 :
7019 : /************************************************************************/
7020 : /* GDALGetDefaultRAT() */
7021 : /************************************************************************/
7022 :
7023 : /**
7024 : * \brief Fetch default Raster Attribute Table.
7025 : *
7026 : * @see GDALRasterBand::GetDefaultRAT()
7027 : */
7028 :
7029 894 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
7030 :
7031 : {
7032 894 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
7033 :
7034 894 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7035 894 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
7036 : }
7037 :
7038 : /************************************************************************/
7039 : /* SetDefaultRAT() */
7040 : /************************************************************************/
7041 :
7042 : /**
7043 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
7044 : * \brief Set default Raster Attribute Table.
7045 : *
7046 : * Associates a default RAT with the band. If not implemented for the
7047 : * format a CPLE_NotSupported error will be issued. If successful a copy
7048 : * of the RAT is made, the original remains owned by the caller.
7049 : *
7050 : * This method is the same as the C function GDALSetDefaultRAT().
7051 : *
7052 : * @param poRAT the RAT to assign to the band.
7053 : *
7054 : * @return CE_None on success or CE_Failure if unsupported or otherwise
7055 : * failing.
7056 : */
7057 :
7058 : /**/
7059 : /**/
7060 :
7061 : CPLErr
7062 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
7063 : {
7064 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
7065 : {
7066 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
7067 0 : ReportError(CE_Failure, CPLE_NotSupported,
7068 : "SetDefaultRAT() not implemented for this format.");
7069 0 : CPLPopErrorHandler();
7070 : }
7071 0 : return CE_Failure;
7072 : }
7073 :
7074 : /************************************************************************/
7075 : /* GDALSetDefaultRAT() */
7076 : /************************************************************************/
7077 :
7078 : /**
7079 : * \brief Set default Raster Attribute Table.
7080 : *
7081 : * @see GDALRasterBand::GDALSetDefaultRAT()
7082 : */
7083 :
7084 17 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
7085 : GDALRasterAttributeTableH hRAT)
7086 :
7087 : {
7088 17 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
7089 :
7090 17 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7091 :
7092 17 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
7093 : }
7094 :
7095 : /************************************************************************/
7096 : /* GetMaskBand() */
7097 : /************************************************************************/
7098 :
7099 : /**
7100 : * \brief Return the mask band associated with the band.
7101 : *
7102 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
7103 : * that returns one of four default implementations : <ul> <li>If a
7104 : * corresponding .msk file exists it will be used for the mask band.</li> <li>If
7105 : * the dataset has a NODATA_VALUES metadata item, an instance of the new
7106 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
7107 : * GMF_NODATA | GMF_PER_DATASET. @since GDAL 1.6.0</li> <li>If the band has a
7108 : * nodata value set, an instance of the new GDALNodataMaskRasterBand class will
7109 : * be returned. GetMaskFlags() will return GMF_NODATA.</li> <li>If there is no
7110 : * nodata value, but the dataset has an alpha band that seems to apply to this
7111 : * band (specific rules yet to be determined) and that is of type GDT_Byte then
7112 : * that alpha band will be returned, and the flags GMF_PER_DATASET and GMF_ALPHA
7113 : * will be returned in the flags.</li> <li>If neither of the above apply, an
7114 : * instance of the new GDALAllValidRasterBand class will be returned that has
7115 : * 255 values for all pixels. The null flags will return GMF_ALL_VALID.</li>
7116 : * </ul>
7117 : *
7118 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
7119 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
7120 : *
7121 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
7122 : * dataset, with the same name as the main dataset and suffixed with .msk,
7123 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
7124 : * main dataset.
7125 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
7126 : * level, where xx matches the band number of a band of the main dataset. The
7127 : * value of those items is a combination of the flags GMF_ALL_VALID,
7128 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
7129 : * a band, then the other rules explained above will be used to generate a
7130 : * on-the-fly mask band.
7131 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
7132 : *
7133 : * This method is the same as the C function GDALGetMaskBand().
7134 : *
7135 : * @return a valid mask band.
7136 : *
7137 : * @since GDAL 1.5.0
7138 : *
7139 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
7140 : *
7141 : */
7142 28519 : GDALRasterBand *GDALRasterBand::GetMaskBand()
7143 :
7144 : {
7145 83303 : const auto HasNoData = [this]()
7146 : {
7147 27528 : int bHaveNoDataRaw = FALSE;
7148 27528 : bool bHaveNoData = false;
7149 27528 : if (eDataType == GDT_Int64)
7150 : {
7151 23 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
7152 23 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
7153 : }
7154 27505 : else if (eDataType == GDT_UInt64)
7155 : {
7156 22 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
7157 22 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
7158 : }
7159 : else
7160 : {
7161 27483 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
7162 27481 : if (bHaveNoDataRaw &&
7163 27481 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
7164 : {
7165 713 : bHaveNoData = true;
7166 : }
7167 : }
7168 27524 : return bHaveNoData;
7169 28519 : };
7170 :
7171 28519 : if (poMask != nullptr)
7172 : {
7173 6220 : if (poMask.IsOwned())
7174 : {
7175 5663 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
7176 : {
7177 5322 : if (HasNoData())
7178 : {
7179 3 : InvalidateMaskBand();
7180 : }
7181 : }
7182 335 : else if (auto poNoDataMaskBand =
7183 337 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
7184 : {
7185 135 : int bHaveNoDataRaw = FALSE;
7186 135 : bool bIsSame = false;
7187 135 : if (eDataType == GDT_Int64)
7188 4 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
7189 5 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
7190 1 : bHaveNoDataRaw;
7191 131 : else if (eDataType == GDT_UInt64)
7192 4 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
7193 5 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
7194 1 : bHaveNoDataRaw;
7195 : else
7196 : {
7197 : const double dfNoDataValue =
7198 127 : GetNoDataValue(&bHaveNoDataRaw);
7199 127 : if (bHaveNoDataRaw)
7200 : {
7201 126 : bIsSame =
7202 126 : std::isnan(dfNoDataValue)
7203 126 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
7204 118 : : poNoDataMaskBand->m_dfNoDataValue ==
7205 : dfNoDataValue;
7206 : }
7207 : }
7208 135 : if (!bIsSame)
7209 9 : InvalidateMaskBand();
7210 : }
7211 : }
7212 :
7213 6217 : if (poMask)
7214 6206 : return poMask.get();
7215 : }
7216 :
7217 : /* -------------------------------------------------------------------- */
7218 : /* Check for a mask in a .msk file. */
7219 : /* -------------------------------------------------------------------- */
7220 22303 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
7221 : {
7222 46 : poMask.reset(poDS->oOvManager.GetMaskBand(nBand), false);
7223 46 : if (poMask != nullptr)
7224 : {
7225 44 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
7226 44 : return poMask.get();
7227 : }
7228 : }
7229 :
7230 : /* -------------------------------------------------------------------- */
7231 : /* Check for NODATA_VALUES metadata. */
7232 : /* -------------------------------------------------------------------- */
7233 22259 : if (poDS != nullptr)
7234 : {
7235 22248 : const char *pszNoDataValues = poDS->GetMetadataItem("NODATA_VALUES");
7236 22248 : if (pszNoDataValues != nullptr)
7237 : {
7238 : char **papszNoDataValues =
7239 56 : CSLTokenizeStringComplex(pszNoDataValues, " ", FALSE, FALSE);
7240 :
7241 : // Make sure we have as many values as bands.
7242 112 : if (CSLCount(papszNoDataValues) == poDS->GetRasterCount() &&
7243 56 : poDS->GetRasterCount() != 0)
7244 : {
7245 : // Make sure that all bands have the same data type
7246 : // This is clearly not a fundamental condition, just a
7247 : // condition to make implementation easier.
7248 56 : GDALDataType eDT = GDT_Unknown;
7249 56 : int i = 0; // Used after for.
7250 224 : for (; i < poDS->GetRasterCount(); ++i)
7251 : {
7252 168 : if (i == 0)
7253 56 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
7254 112 : else if (eDT !=
7255 112 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
7256 : {
7257 0 : break;
7258 : }
7259 : }
7260 56 : if (i == poDS->GetRasterCount())
7261 : {
7262 56 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
7263 : try
7264 : {
7265 56 : poMask.reset(new GDALNoDataValuesMaskBand(poDS), true);
7266 : }
7267 0 : catch (const std::bad_alloc &)
7268 : {
7269 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
7270 0 : poMask.reset();
7271 : }
7272 56 : CSLDestroy(papszNoDataValues);
7273 56 : return poMask.get();
7274 : }
7275 : else
7276 : {
7277 0 : ReportError(CE_Warning, CPLE_AppDefined,
7278 : "All bands should have the same type in "
7279 : "order the NODATA_VALUES metadata item "
7280 : "to be used as a mask.");
7281 : }
7282 : }
7283 : else
7284 : {
7285 0 : ReportError(
7286 : CE_Warning, CPLE_AppDefined,
7287 : "NODATA_VALUES metadata item doesn't have the same number "
7288 : "of values as the number of bands. "
7289 : "Ignoring it for mask.");
7290 : }
7291 :
7292 0 : CSLDestroy(papszNoDataValues);
7293 : }
7294 : }
7295 :
7296 : /* -------------------------------------------------------------------- */
7297 : /* Check for nodata case. */
7298 : /* -------------------------------------------------------------------- */
7299 22203 : if (HasNoData())
7300 : {
7301 727 : nMaskFlags = GMF_NODATA;
7302 : try
7303 : {
7304 727 : poMask.reset(new GDALNoDataMaskBand(this), true);
7305 : }
7306 0 : catch (const std::bad_alloc &)
7307 : {
7308 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
7309 0 : poMask.reset();
7310 : }
7311 727 : return poMask.get();
7312 : }
7313 :
7314 : /* -------------------------------------------------------------------- */
7315 : /* Check for alpha case. */
7316 : /* -------------------------------------------------------------------- */
7317 21466 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
7318 43454 : this == poDS->GetRasterBand(1) &&
7319 512 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
7320 : {
7321 186 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
7322 : {
7323 142 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
7324 142 : poMask.reset(poDS->GetRasterBand(2), false);
7325 142 : return poMask.get();
7326 : }
7327 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
7328 : {
7329 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
7330 : try
7331 : {
7332 23 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(2)),
7333 : true);
7334 : }
7335 0 : catch (const std::bad_alloc &)
7336 : {
7337 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
7338 0 : poMask.reset();
7339 : }
7340 23 : return poMask.get();
7341 : }
7342 : }
7343 :
7344 21301 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
7345 2574 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
7346 43230 : this == poDS->GetRasterBand(3)) &&
7347 2006 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
7348 : {
7349 1136 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
7350 : {
7351 1089 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
7352 1089 : poMask.reset(poDS->GetRasterBand(4), false);
7353 1089 : return poMask.get();
7354 : }
7355 47 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
7356 : {
7357 35 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
7358 : try
7359 : {
7360 35 : poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(4)),
7361 : true);
7362 : }
7363 0 : catch (const std::bad_alloc &)
7364 : {
7365 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
7366 0 : poMask.reset();
7367 : }
7368 35 : return poMask.get();
7369 : }
7370 : }
7371 :
7372 : /* -------------------------------------------------------------------- */
7373 : /* Fallback to all valid case. */
7374 : /* -------------------------------------------------------------------- */
7375 20187 : nMaskFlags = GMF_ALL_VALID;
7376 : try
7377 : {
7378 20187 : poMask.reset(new GDALAllValidMaskBand(this), true);
7379 : }
7380 0 : catch (const std::bad_alloc &)
7381 : {
7382 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
7383 0 : poMask.reset();
7384 : }
7385 :
7386 20187 : return poMask.get();
7387 : }
7388 :
7389 : /************************************************************************/
7390 : /* GDALGetMaskBand() */
7391 : /************************************************************************/
7392 :
7393 : /**
7394 : * \brief Return the mask band associated with the band.
7395 : *
7396 : * @see GDALRasterBand::GetMaskBand()
7397 : */
7398 :
7399 825 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
7400 :
7401 : {
7402 825 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
7403 :
7404 825 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7405 825 : return poBand->GetMaskBand();
7406 : }
7407 :
7408 : /************************************************************************/
7409 : /* GetMaskFlags() */
7410 : /************************************************************************/
7411 :
7412 : /**
7413 : * \brief Return the status flags of the mask band associated with the band.
7414 : *
7415 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
7416 : * the following available definitions that may be extended in the future:
7417 : * <ul>
7418 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
7419 : * 255. When used this will normally be the only flag set.</li>
7420 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
7421 : * dataset.</li> <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
7422 : * and may have values other than 0 and 255.</li> <li>GMF_NODATA(0x08):
7423 : * Indicates the mask is actually being generated from nodata values. (mutually
7424 : * exclusive of GMF_ALPHA)</li>
7425 : * </ul>
7426 : *
7427 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
7428 : * that returns one of four default implementations : <ul> <li>If a
7429 : * corresponding .msk file exists it will be used for the mask band.</li> <li>If
7430 : * the dataset has a NODATA_VALUES metadata item, an instance of the new
7431 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
7432 : * GMF_NODATA | GMF_PER_DATASET. @since GDAL 1.6.0</li> <li>If the band has a
7433 : * nodata value set, an instance of the new GDALNodataMaskRasterBand class will
7434 : * be returned. GetMaskFlags() will return GMF_NODATA.</li> <li>If there is no
7435 : * nodata value, but the dataset has an alpha band that seems to apply to this
7436 : * band (specific rules yet to be determined) and that is of type GDT_Byte then
7437 : * that alpha band will be returned, and the flags GMF_PER_DATASET and GMF_ALPHA
7438 : * will be returned in the flags.</li> <li>If neither of the above apply, an
7439 : * instance of the new GDALAllValidRasterBand class will be returned that has
7440 : * 255 values for all pixels. The null flags will return GMF_ALL_VALID.</li>
7441 : * </ul>
7442 : *
7443 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
7444 : * dataset, with the same name as the main dataset and suffixed with .msk,
7445 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
7446 : * main dataset.
7447 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
7448 : * level, where xx matches the band number of a band of the main dataset. The
7449 : * value of those items is a combination of the flags GMF_ALL_VALID,
7450 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
7451 : * a band, then the other rules explained above will be used to generate a
7452 : * on-the-fly mask band.
7453 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
7454 : *
7455 : * This method is the same as the C function GDALGetMaskFlags().
7456 : *
7457 : * @since GDAL 1.5.0
7458 : *
7459 : * @return a valid mask band.
7460 : *
7461 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
7462 : *
7463 : */
7464 62575 : int GDALRasterBand::GetMaskFlags()
7465 :
7466 : {
7467 : // If we don't have a band yet, force this now so that the masks value
7468 : // will be initialized.
7469 :
7470 62575 : if (poMask == nullptr)
7471 21323 : GetMaskBand();
7472 :
7473 62584 : return nMaskFlags;
7474 : }
7475 :
7476 : /************************************************************************/
7477 : /* GDALGetMaskFlags() */
7478 : /************************************************************************/
7479 :
7480 : /**
7481 : * \brief Return the status flags of the mask band associated with the band.
7482 : *
7483 : * @see GDALRasterBand::GetMaskFlags()
7484 : */
7485 :
7486 5900 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
7487 :
7488 : {
7489 5900 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
7490 :
7491 5900 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7492 5900 : return poBand->GetMaskFlags();
7493 : }
7494 :
7495 : /************************************************************************/
7496 : /* InvalidateMaskBand() */
7497 : /************************************************************************/
7498 :
7499 : //! @cond Doxygen_Suppress
7500 1041000 : void GDALRasterBand::InvalidateMaskBand()
7501 : {
7502 1041000 : poMask.reset();
7503 1041000 : nMaskFlags = 0;
7504 1041000 : }
7505 :
7506 : //! @endcond
7507 :
7508 : /************************************************************************/
7509 : /* CreateMaskBand() */
7510 : /************************************************************************/
7511 :
7512 : /**
7513 : * \brief Adds a mask band to the current band
7514 : *
7515 : * The default implementation of the CreateMaskBand() method is implemented
7516 : * based on similar rules to the .ovr handling implemented using the
7517 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
7518 : * be created with the same basename as the original file, and it will have
7519 : * as many bands as the original image (or just one for GMF_PER_DATASET).
7520 : * The mask images will be deflate compressed tiled images with the same
7521 : * block size as the original image if possible.
7522 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
7523 : * level, where xx matches the band number of a band of the main dataset. The
7524 : * value of those items will be the one of the nFlagsIn parameter.
7525 : *
7526 : * Note that if you got a mask band with a previous call to GetMaskBand(),
7527 : * it might be invalidated by CreateMaskBand(). So you have to call
7528 : * GetMaskBand() again.
7529 : *
7530 : * This method is the same as the C function GDALCreateMaskBand().
7531 : *
7532 : * @since GDAL 1.5.0
7533 : *
7534 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
7535 : *
7536 : * @return CE_None on success or CE_Failure on an error.
7537 : *
7538 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
7539 : * @see GDALDataset::CreateMaskBand()
7540 : *
7541 : */
7542 :
7543 9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
7544 :
7545 : {
7546 9 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
7547 : {
7548 9 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
7549 9 : if (eErr != CE_None)
7550 1 : return eErr;
7551 :
7552 8 : InvalidateMaskBand();
7553 :
7554 8 : return CE_None;
7555 : }
7556 :
7557 0 : ReportError(CE_Failure, CPLE_NotSupported,
7558 : "CreateMaskBand() not supported for this band.");
7559 :
7560 0 : return CE_Failure;
7561 : }
7562 :
7563 : /************************************************************************/
7564 : /* GDALCreateMaskBand() */
7565 : /************************************************************************/
7566 :
7567 : /**
7568 : * \brief Adds a mask band to the current band
7569 : *
7570 : * @see GDALRasterBand::CreateMaskBand()
7571 : */
7572 :
7573 31 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
7574 :
7575 : {
7576 31 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
7577 :
7578 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7579 31 : return poBand->CreateMaskBand(nFlags);
7580 : }
7581 :
7582 : /************************************************************************/
7583 : /* IsMaskBand() */
7584 : /************************************************************************/
7585 :
7586 : /**
7587 : * \brief Returns whether a band is a mask band.
7588 : *
7589 : * Mask band must be understood in the broad term: it can be a per-dataset
7590 : * mask band, an alpha band, or an implicit mask band.
7591 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
7592 : *
7593 : * This method is the same as the C function GDALIsMaskBand().
7594 : *
7595 : * @return true if the band is a mask band.
7596 : *
7597 : * @see GDALDataset::CreateMaskBand()
7598 : *
7599 : * @since GDAL 3.5.0
7600 : *
7601 : */
7602 :
7603 325 : bool GDALRasterBand::IsMaskBand() const
7604 : {
7605 : // The GeoTIFF driver, among others, override this method to
7606 : // also handle external .msk bands.
7607 325 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
7608 325 : GCI_AlphaBand;
7609 : }
7610 :
7611 : /************************************************************************/
7612 : /* GDALIsMaskBand() */
7613 : /************************************************************************/
7614 :
7615 : /**
7616 : * \brief Returns whether a band is a mask band.
7617 : *
7618 : * Mask band must be understood in the broad term: it can be a per-dataset
7619 : * mask band, an alpha band, or an implicit mask band.
7620 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
7621 : *
7622 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
7623 : *
7624 : * @return true if the band is a mask band.
7625 : *
7626 : * @see GDALRasterBand::IsMaskBand()
7627 : *
7628 : * @since GDAL 3.5.0
7629 : *
7630 : */
7631 :
7632 34 : bool GDALIsMaskBand(GDALRasterBandH hBand)
7633 :
7634 : {
7635 34 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
7636 :
7637 34 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7638 34 : return poBand->IsMaskBand();
7639 : }
7640 :
7641 : /************************************************************************/
7642 : /* GetMaskValueRange() */
7643 : /************************************************************************/
7644 :
7645 : /**
7646 : * \brief Returns the range of values that a mask band can take.
7647 : *
7648 : * @return the range of values that a mask band can take.
7649 : *
7650 : * @since GDAL 3.5.0
7651 : *
7652 : */
7653 :
7654 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
7655 : {
7656 0 : return GMVR_UNKNOWN;
7657 : }
7658 :
7659 : /************************************************************************/
7660 : /* GetIndexColorTranslationTo() */
7661 : /************************************************************************/
7662 :
7663 : /**
7664 : * \brief Compute translation table for color tables.
7665 : *
7666 : * When the raster band has a palette index, it may be useful to compute
7667 : * the "translation" of this palette to the palette of another band.
7668 : * The translation tries to do exact matching first, and then approximate
7669 : * matching if no exact matching is possible.
7670 : * This method returns a table such that table[i] = j where i is an index
7671 : * of the 'this' rasterband and j the corresponding index for the reference
7672 : * rasterband.
7673 : *
7674 : * This method is thought as internal to GDAL and is used for drivers
7675 : * like RPFTOC.
7676 : *
7677 : * The implementation only supports 1-byte palette rasterbands.
7678 : *
7679 : * @param poReferenceBand the raster band
7680 : * @param pTranslationTable an already allocated translation table (at least 256
7681 : * bytes), or NULL to let the method allocate it
7682 : * @param pApproximateMatching a pointer to a flag that is set if the matching
7683 : * is approximate. May be NULL.
7684 : *
7685 : * @return a translation table if the two bands are palette index and that they
7686 : * do not match or NULL in other cases. The table must be freed with CPLFree if
7687 : * NULL was passed for pTranslationTable.
7688 : */
7689 :
7690 : unsigned char *
7691 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
7692 : unsigned char *pTranslationTable,
7693 : int *pApproximateMatching)
7694 : {
7695 4 : if (poReferenceBand == nullptr)
7696 0 : return nullptr;
7697 :
7698 : // cppcheck-suppress knownConditionTrueFalse
7699 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
7700 : // cppcheck-suppress knownConditionTrueFalse
7701 4 : GetColorInterpretation() == GCI_PaletteIndex &&
7702 12 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
7703 4 : GetRasterDataType() == GDT_Byte)
7704 : {
7705 4 : const GDALColorTable *srcColorTable = GetColorTable();
7706 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
7707 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
7708 : {
7709 4 : const int nEntries = srcColorTable->GetColorEntryCount();
7710 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
7711 :
7712 4 : int bHasNoDataValueSrc = FALSE;
7713 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
7714 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
7715 3 : dfNoDataValueSrc <= 255 &&
7716 3 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
7717 1 : bHasNoDataValueSrc = FALSE;
7718 4 : const int noDataValueSrc =
7719 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
7720 :
7721 4 : int bHasNoDataValueRef = FALSE;
7722 : const double dfNoDataValueRef =
7723 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
7724 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
7725 2 : dfNoDataValueRef <= 255 &&
7726 2 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
7727 2 : bHasNoDataValueRef = FALSE;
7728 4 : const int noDataValueRef =
7729 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
7730 :
7731 4 : bool samePalette = false;
7732 :
7733 4 : if (pApproximateMatching)
7734 2 : *pApproximateMatching = FALSE;
7735 :
7736 4 : if (nEntries == nRefEntries &&
7737 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
7738 3 : (bHasNoDataValueSrc == FALSE ||
7739 : noDataValueSrc == noDataValueRef))
7740 : {
7741 3 : samePalette = true;
7742 693 : for (int i = 0; i < nEntries; ++i)
7743 : {
7744 690 : if (noDataValueSrc == i)
7745 3 : continue;
7746 : const GDALColorEntry *entry =
7747 687 : srcColorTable->GetColorEntry(i);
7748 : const GDALColorEntry *entryRef =
7749 687 : destColorTable->GetColorEntry(i);
7750 687 : if (entry->c1 != entryRef->c1 ||
7751 687 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
7752 : {
7753 0 : samePalette = false;
7754 : }
7755 : }
7756 : }
7757 :
7758 4 : if (!samePalette)
7759 : {
7760 1 : if (pTranslationTable == nullptr)
7761 : {
7762 : pTranslationTable = static_cast<unsigned char *>(
7763 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
7764 1 : if (pTranslationTable == nullptr)
7765 1 : return nullptr;
7766 : }
7767 :
7768 : // Trying to remap the product palette on the subdataset
7769 : // palette.
7770 5 : for (int i = 0; i < nEntries; ++i)
7771 : {
7772 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
7773 : noDataValueSrc == i)
7774 0 : continue;
7775 : const GDALColorEntry *entry =
7776 4 : srcColorTable->GetColorEntry(i);
7777 4 : bool bMatchFound = false;
7778 13 : for (int j = 0; j < nRefEntries; ++j)
7779 : {
7780 10 : if (bHasNoDataValueRef && noDataValueRef == j)
7781 0 : continue;
7782 : const GDALColorEntry *entryRef =
7783 10 : destColorTable->GetColorEntry(j);
7784 10 : if (entry->c1 == entryRef->c1 &&
7785 2 : entry->c2 == entryRef->c2 &&
7786 2 : entry->c3 == entryRef->c3)
7787 : {
7788 1 : pTranslationTable[i] =
7789 : static_cast<unsigned char>(j);
7790 1 : bMatchFound = true;
7791 1 : break;
7792 : }
7793 : }
7794 4 : if (!bMatchFound)
7795 : {
7796 : // No exact match. Looking for closest color now.
7797 3 : int best_j = 0;
7798 3 : int best_distance = 0;
7799 3 : if (pApproximateMatching)
7800 0 : *pApproximateMatching = TRUE;
7801 12 : for (int j = 0; j < nRefEntries; ++j)
7802 : {
7803 : const GDALColorEntry *entryRef =
7804 9 : destColorTable->GetColorEntry(j);
7805 9 : int distance = (entry->c1 - entryRef->c1) *
7806 9 : (entry->c1 - entryRef->c1) +
7807 9 : (entry->c2 - entryRef->c2) *
7808 9 : (entry->c2 - entryRef->c2) +
7809 9 : (entry->c3 - entryRef->c3) *
7810 9 : (entry->c3 - entryRef->c3);
7811 9 : if (j == 0 || distance < best_distance)
7812 : {
7813 7 : best_j = j;
7814 7 : best_distance = distance;
7815 : }
7816 : }
7817 3 : pTranslationTable[i] =
7818 : static_cast<unsigned char>(best_j);
7819 : }
7820 : }
7821 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
7822 0 : pTranslationTable[noDataValueSrc] =
7823 : static_cast<unsigned char>(noDataValueRef);
7824 :
7825 1 : return pTranslationTable;
7826 : }
7827 : }
7828 : }
7829 3 : return nullptr;
7830 : }
7831 :
7832 : /************************************************************************/
7833 : /* SetFlushBlockErr() */
7834 : /************************************************************************/
7835 :
7836 : /**
7837 : * \brief Store that an error occurred while writing a dirty block.
7838 : *
7839 : * This function stores the fact that an error occurred while writing a dirty
7840 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
7841 : * flushed when the block cache get full, it is not convenient/possible to
7842 : * report that a dirty block could not be written correctly. This function
7843 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
7844 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
7845 : * places where the user can easily match the error with the relevant dataset.
7846 : */
7847 :
7848 4 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
7849 : {
7850 4 : eFlushBlockErr = eErr;
7851 4 : }
7852 :
7853 : /************************************************************************/
7854 : /* IncDirtyBlocks() */
7855 : /************************************************************************/
7856 :
7857 : /**
7858 : * \brief Increment/decrement the number of dirty blocks
7859 : */
7860 :
7861 488710 : void GDALRasterBand::IncDirtyBlocks(int nInc)
7862 : {
7863 488710 : if (poBandBlockCache)
7864 488711 : poBandBlockCache->IncDirtyBlocks(nInc);
7865 488710 : }
7866 :
7867 : /************************************************************************/
7868 : /* ReportError() */
7869 : /************************************************************************/
7870 :
7871 : #ifndef DOXYGEN_XML
7872 : /**
7873 : * \brief Emits an error related to a raster band.
7874 : *
7875 : * This function is a wrapper for regular CPLError(). The only difference
7876 : * with CPLError() is that it prepends the error message with the dataset
7877 : * name and the band number.
7878 : *
7879 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
7880 : * @param err_no the error number (CPLE_*) from cpl_error.h.
7881 : * @param fmt a printf() style format string. Any additional arguments
7882 : * will be treated as arguments to fill in this format in a manner
7883 : * similar to printf().
7884 : *
7885 : * @since GDAL 1.9.0
7886 : */
7887 :
7888 2441 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
7889 : const char *fmt, ...)
7890 : {
7891 : va_list args;
7892 :
7893 2441 : va_start(args, fmt);
7894 :
7895 2441 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
7896 2441 : pszDSName = CPLGetFilename(pszDSName);
7897 2441 : if (pszDSName[0] != '\0')
7898 : {
7899 2389 : CPLError(eErrClass, err_no, "%s",
7900 4778 : CPLString()
7901 2389 : .Printf("%s, band %d: ", pszDSName, GetBand())
7902 4778 : .append(CPLString().vPrintf(fmt, args))
7903 : .c_str());
7904 : }
7905 : else
7906 : {
7907 52 : CPLErrorV(eErrClass, err_no, fmt, args);
7908 : }
7909 :
7910 2441 : va_end(args);
7911 2441 : }
7912 : #endif
7913 :
7914 : /************************************************************************/
7915 : /* GetVirtualMemAuto() */
7916 : /************************************************************************/
7917 :
7918 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
7919 : *
7920 : * Only supported on Linux and Unix systems with mmap() for now.
7921 : *
7922 : * This method allows creating a virtual memory object for a GDALRasterBand,
7923 : * that exposes the whole image data as a virtual array.
7924 : *
7925 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
7926 : * specialized implementation, such as for raw files, may also directly use
7927 : * mechanisms of the operating system to create a view of the underlying file
7928 : * into virtual memory ( CPLVirtualMemFileMapNew() )
7929 : *
7930 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
7931 : * offer a specialized implementation with direct file mapping, provided that
7932 : * some requirements are met :
7933 : * - for all drivers, the dataset must be backed by a "real" file in the file
7934 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
7935 : * must match the native ordering of the CPU.
7936 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
7937 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
7938 : * the file in sequential order, and be equally spaced (which is generally the
7939 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
7940 : * GDT_Int16/GDT_UInt16, 32 for GDT_Float32 and 64 for GDT_Float64)
7941 : *
7942 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
7943 : * CPLVirtualMemFree() must be called before the raster band object is
7944 : * destroyed.
7945 : *
7946 : * If p is such a pointer and base_type the type matching
7947 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
7948 : * accessed with
7949 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
7950 : *
7951 : * This method is the same as the C GDALGetVirtualMemAuto() function.
7952 : *
7953 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
7954 : * read/write the band.
7955 : *
7956 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
7957 : * one pixel value in the buffer to the start of the next pixel value within a
7958 : * scanline.
7959 : *
7960 : * @param pnLineSpace Output parameter giving the byte offset from the start of
7961 : * one scanline in the buffer to the start of the next.
7962 : *
7963 : * @param papszOptions NULL terminated list of options.
7964 : * If a specialized implementation exists, defining
7965 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
7966 : * used. On the contrary, starting with GDAL 2.2, defining
7967 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
7968 : * being used (thus only allowing efficient implementations to be used). When
7969 : * requiring or falling back to the default implementation, the following
7970 : * options are available : CACHE_SIZE (in bytes, defaults to
7971 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
7972 : * to FALSE)
7973 : *
7974 : * @return a virtual memory object that must be unreferenced by
7975 : * CPLVirtualMemFree(), or NULL in case of failure.
7976 : *
7977 : * @since GDAL 1.11
7978 : */
7979 :
7980 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
7981 : int *pnPixelSpace,
7982 : GIntBig *pnLineSpace,
7983 : char **papszOptions)
7984 : {
7985 9 : const char *pszImpl = CSLFetchNameValueDef(
7986 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
7987 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
7988 8 : EQUAL(pszImpl, "FALSE"))
7989 : {
7990 1 : return nullptr;
7991 : }
7992 :
7993 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
7994 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
7995 8 : if (pnPixelSpace)
7996 8 : *pnPixelSpace = nPixelSpace;
7997 8 : if (pnLineSpace)
7998 8 : *pnLineSpace = nLineSpace;
7999 : const size_t nCacheSize =
8000 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
8001 : const size_t nPageSizeHint =
8002 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
8003 8 : const bool bSingleThreadUsage = CPLTestBool(
8004 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
8005 8 : return GDALRasterBandGetVirtualMem(
8006 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
8007 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
8008 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
8009 8 : papszOptions);
8010 : }
8011 :
8012 : /************************************************************************/
8013 : /* GDALGetVirtualMemAuto() */
8014 : /************************************************************************/
8015 :
8016 : /**
8017 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
8018 : *
8019 : * @see GDALRasterBand::GetVirtualMemAuto()
8020 : */
8021 :
8022 30 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
8023 : int *pnPixelSpace, GIntBig *pnLineSpace,
8024 : CSLConstList papszOptions)
8025 : {
8026 30 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
8027 :
8028 30 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8029 :
8030 30 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
8031 30 : const_cast<char **>(papszOptions));
8032 : }
8033 :
8034 : /************************************************************************/
8035 : /* GDALGetDataCoverageStatus() */
8036 : /************************************************************************/
8037 :
8038 : /**
8039 : * \brief Get the coverage status of a sub-window of the raster.
8040 : *
8041 : * Returns whether a sub-window of the raster contains only data, only empty
8042 : * blocks or a mix of both. This function can be used to determine quickly
8043 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
8044 : * be sparse.
8045 : *
8046 : * Empty blocks are blocks that are generally not physically present in the
8047 : * file, and when read through GDAL, contain only pixels whose value is the
8048 : * nodata value when it is set, or whose value is 0 when the nodata value is
8049 : * not set.
8050 : *
8051 : * The query is done in an efficient way without reading the actual pixel
8052 : * values. If not possible, or not implemented at all by the driver,
8053 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
8054 : * be returned.
8055 : *
8056 : * The values that can be returned by the function are the following,
8057 : * potentially combined with the binary or operator :
8058 : * <ul>
8059 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
8060 : * GetDataCoverageStatus(). This flag should be returned together with
8061 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
8062 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
8063 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
8064 : * the queried window. This is typically identified by the concept of missing
8065 : * block in formats that supports it.
8066 : * </li>
8067 : * </ul>
8068 : *
8069 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
8070 : * should be interpreted more as hint of potential presence of data. For example
8071 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
8072 : * nodata value), instead of using the missing block mechanism,
8073 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
8074 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
8075 : *
8076 : * The nMaskFlagStop should be generally set to 0. It can be set to a
8077 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
8078 : * the function as soon as the computed mask matches the nMaskFlagStop. For
8079 : * example, you can issue a request on the whole raster with nMaskFlagStop =
8080 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
8081 : * the function will exit, so that you can potentially refine the requested area
8082 : * to find which particular region(s) have missing blocks.
8083 : *
8084 : * @see GDALRasterBand::GetDataCoverageStatus()
8085 : *
8086 : * @param hBand raster band
8087 : *
8088 : * @param nXOff The pixel offset to the top left corner of the region
8089 : * of the band to be queried. This would be zero to start from the left side.
8090 : *
8091 : * @param nYOff The line offset to the top left corner of the region
8092 : * of the band to be queried. This would be zero to start from the top.
8093 : *
8094 : * @param nXSize The width of the region of the band to be queried in pixels.
8095 : *
8096 : * @param nYSize The height of the region of the band to be queried in lines.
8097 : *
8098 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
8099 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8100 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
8101 : * as the computation of the coverage matches the mask, the computation will be
8102 : * stopped. *pdfDataPct will not be valid in that case.
8103 : *
8104 : * @param pdfDataPct Optional output parameter whose pointed value will be set
8105 : * to the (approximate) percentage in [0,100] of pixels in the queried
8106 : * sub-window that have valid values. The implementation might not always be
8107 : * able to compute it, in which case it will be set to a negative value.
8108 : *
8109 : * @return a binary-or'ed combination of possible values
8110 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8111 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
8112 : *
8113 : * @note Added in GDAL 2.2
8114 : */
8115 :
8116 8 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
8117 : int nYOff, int nXSize, int nYSize,
8118 : int nMaskFlagStop, double *pdfDataPct)
8119 : {
8120 8 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
8121 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
8122 :
8123 8 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8124 :
8125 8 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
8126 8 : nMaskFlagStop, pdfDataPct);
8127 : }
8128 :
8129 : /************************************************************************/
8130 : /* GetDataCoverageStatus() */
8131 : /************************************************************************/
8132 :
8133 : /**
8134 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
8135 : * int nYOff,
8136 : * int nXSize,
8137 : * int nYSize,
8138 : * int nMaskFlagStop,
8139 : * double* pdfDataPct)
8140 : * \brief Get the coverage status of a sub-window of the raster.
8141 : *
8142 : * Returns whether a sub-window of the raster contains only data, only empty
8143 : * blocks or a mix of both. This function can be used to determine quickly
8144 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
8145 : * be sparse.
8146 : *
8147 : * Empty blocks are blocks that contain only pixels whose value is the nodata
8148 : * value when it is set, or whose value is 0 when the nodata value is not set.
8149 : *
8150 : * The query is done in an efficient way without reading the actual pixel
8151 : * values. If not possible, or not implemented at all by the driver,
8152 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
8153 : * be returned.
8154 : *
8155 : * The values that can be returned by the function are the following,
8156 : * potentially combined with the binary or operator :
8157 : * <ul>
8158 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
8159 : * GetDataCoverageStatus(). This flag should be returned together with
8160 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
8161 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
8162 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
8163 : * the queried window. This is typically identified by the concept of missing
8164 : * block in formats that supports it.
8165 : * </li>
8166 : * </ul>
8167 : *
8168 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
8169 : * should be interpreted more as hint of potential presence of data. For example
8170 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
8171 : * nodata value), instead of using the missing block mechanism,
8172 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
8173 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
8174 : *
8175 : * The nMaskFlagStop should be generally set to 0. It can be set to a
8176 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
8177 : * the function as soon as the computed mask matches the nMaskFlagStop. For
8178 : * example, you can issue a request on the whole raster with nMaskFlagStop =
8179 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
8180 : * the function will exit, so that you can potentially refine the requested area
8181 : * to find which particular region(s) have missing blocks.
8182 : *
8183 : * @see GDALGetDataCoverageStatus()
8184 : *
8185 : * @param nXOff The pixel offset to the top left corner of the region
8186 : * of the band to be queried. This would be zero to start from the left side.
8187 : *
8188 : * @param nYOff The line offset to the top left corner of the region
8189 : * of the band to be queried. This would be zero to start from the top.
8190 : *
8191 : * @param nXSize The width of the region of the band to be queried in pixels.
8192 : *
8193 : * @param nYSize The height of the region of the band to be queried in lines.
8194 : *
8195 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
8196 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8197 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
8198 : * as the computation of the coverage matches the mask, the computation will be
8199 : * stopped. *pdfDataPct will not be valid in that case.
8200 : *
8201 : * @param pdfDataPct Optional output parameter whose pointed value will be set
8202 : * to the (approximate) percentage in [0,100] of pixels in the queried
8203 : * sub-window that have valid values. The implementation might not always be
8204 : * able to compute it, in which case it will be set to a negative value.
8205 : *
8206 : * @return a binary-or'ed combination of possible values
8207 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8208 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
8209 : *
8210 : * @note Added in GDAL 2.2
8211 : */
8212 :
8213 : /**
8214 : * \brief Get the coverage status of a sub-window of the raster.
8215 : *
8216 : * Returns whether a sub-window of the raster contains only data, only empty
8217 : * blocks or a mix of both. This function can be used to determine quickly
8218 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
8219 : * be sparse.
8220 : *
8221 : * Empty blocks are blocks that contain only pixels whose value is the nodata
8222 : * value when it is set, or whose value is 0 when the nodata value is not set.
8223 : *
8224 : * The query is done in an efficient way without reading the actual pixel
8225 : * values. If not possible, or not implemented at all by the driver,
8226 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
8227 : * be returned.
8228 : *
8229 : * The values that can be returned by the function are the following,
8230 : * potentially combined with the binary or operator :
8231 : * <ul>
8232 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
8233 : * GetDataCoverageStatus(). This flag should be returned together with
8234 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
8235 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
8236 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
8237 : * the queried window. This is typically identified by the concept of missing
8238 : * block in formats that supports it.
8239 : * </li>
8240 : * </ul>
8241 : *
8242 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
8243 : * should be interpreted more as hint of potential presence of data. For example
8244 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
8245 : * nodata value), instead of using the missing block mechanism,
8246 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
8247 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
8248 : *
8249 : * The nMaskFlagStop should be generally set to 0. It can be set to a
8250 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
8251 : * the function as soon as the computed mask matches the nMaskFlagStop. For
8252 : * example, you can issue a request on the whole raster with nMaskFlagStop =
8253 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
8254 : * the function will exit, so that you can potentially refine the requested area
8255 : * to find which particular region(s) have missing blocks.
8256 : *
8257 : * @see GDALGetDataCoverageStatus()
8258 : *
8259 : * @param nXOff The pixel offset to the top left corner of the region
8260 : * of the band to be queried. This would be zero to start from the left side.
8261 : *
8262 : * @param nYOff The line offset to the top left corner of the region
8263 : * of the band to be queried. This would be zero to start from the top.
8264 : *
8265 : * @param nXSize The width of the region of the band to be queried in pixels.
8266 : *
8267 : * @param nYSize The height of the region of the band to be queried in lines.
8268 : *
8269 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
8270 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8271 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
8272 : * as the computation of the coverage matches the mask, the computation will be
8273 : * stopped. *pdfDataPct will not be valid in that case.
8274 : *
8275 : * @param pdfDataPct Optional output parameter whose pointed value will be set
8276 : * to the (approximate) percentage in [0,100] of pixels in the queried
8277 : * sub-window that have valid values. The implementation might not always be
8278 : * able to compute it, in which case it will be set to a negative value.
8279 : *
8280 : * @return a binary-or'ed combination of possible values
8281 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8282 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
8283 : *
8284 : * @note Added in GDAL 2.2
8285 : */
8286 :
8287 1349 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
8288 : int nYSize, int nMaskFlagStop,
8289 : double *pdfDataPct)
8290 : {
8291 1349 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
8292 1349 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
8293 1349 : nYOff + nYSize > nRasterYSize)
8294 : {
8295 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
8296 0 : if (pdfDataPct)
8297 0 : *pdfDataPct = 0.0;
8298 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
8299 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
8300 : }
8301 1349 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
8302 1349 : pdfDataPct);
8303 : }
8304 :
8305 : /************************************************************************/
8306 : /* IGetDataCoverageStatus() */
8307 : /************************************************************************/
8308 :
8309 342 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
8310 : int /*nXSize*/, int /*nYSize*/,
8311 : int /*nMaskFlagStop*/,
8312 : double *pdfDataPct)
8313 : {
8314 342 : if (pdfDataPct != nullptr)
8315 0 : *pdfDataPct = 100.0;
8316 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
8317 342 : GDAL_DATA_COVERAGE_STATUS_DATA;
8318 : }
8319 :
8320 : //! @cond Doxygen_Suppress
8321 : /************************************************************************/
8322 : /* EnterReadWrite() */
8323 : /************************************************************************/
8324 :
8325 5749470 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
8326 : {
8327 5749470 : if (poDS != nullptr)
8328 5733190 : return poDS->EnterReadWrite(eRWFlag);
8329 16276 : return FALSE;
8330 : }
8331 :
8332 : /************************************************************************/
8333 : /* LeaveReadWrite() */
8334 : /************************************************************************/
8335 :
8336 594044 : void GDALRasterBand::LeaveReadWrite()
8337 : {
8338 594044 : if (poDS != nullptr)
8339 594012 : poDS->LeaveReadWrite();
8340 594019 : }
8341 :
8342 : /************************************************************************/
8343 : /* InitRWLock() */
8344 : /************************************************************************/
8345 :
8346 3618850 : void GDALRasterBand::InitRWLock()
8347 : {
8348 3618850 : if (poDS != nullptr)
8349 3618450 : poDS->InitRWLock();
8350 3618850 : }
8351 :
8352 : //! @endcond
8353 :
8354 : /**
8355 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char *
8356 : * pszDomain) \brief Set metadata.
8357 : *
8358 : * CAUTION: depending on the format, older values of the updated information
8359 : * might still be found in the file in a "ghost" state, even if no longer
8360 : * accessible through the GDAL API. This is for example the case of the GTiff
8361 : * format (this is not a exhaustive list)
8362 : *
8363 : * The C function GDALSetMetadata() does the same thing as this method.
8364 : *
8365 : * @param papszMetadata the metadata in name=value string list format to
8366 : * apply.
8367 : * @param pszDomain the domain of interest. Use "" or NULL for the default
8368 : * domain.
8369 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
8370 : * metadata has been accepted, but is likely not maintained persistently
8371 : * by the underlying object between sessions.
8372 : */
8373 :
8374 : /**
8375 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char *
8376 : * pszValue, const char * pszDomain) \brief Set single metadata item.
8377 : *
8378 : * CAUTION: depending on the format, older values of the updated information
8379 : * might still be found in the file in a "ghost" state, even if no longer
8380 : * accessible through the GDAL API. This is for example the case of the GTiff
8381 : * format (this is not a exhaustive list)
8382 : *
8383 : * The C function GDALSetMetadataItem() does the same thing as this method.
8384 : *
8385 : * @param pszName the key for the metadata item to fetch.
8386 : * @param pszValue the value to assign to the key.
8387 : * @param pszDomain the domain to set within, use NULL for the default domain.
8388 : *
8389 : * @return CE_None on success, or an error code on failure.
8390 : */
8391 :
8392 : //! @cond Doxygen_Suppress
8393 : /************************************************************************/
8394 : /* EnablePixelTypeSignedByteWarning() */
8395 : /************************************************************************/
8396 :
8397 18789 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
8398 : {
8399 18789 : m_bEnablePixelTypeSignedByteWarning = b;
8400 18789 : }
8401 :
8402 6588 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
8403 : {
8404 6588 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
8405 6588 : }
8406 :
8407 : //! @endcond
8408 :
8409 : /************************************************************************/
8410 : /* GetMetadataItem() */
8411 : /************************************************************************/
8412 :
8413 46693 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
8414 : const char *pszDomain)
8415 : {
8416 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
8417 46693 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
8418 25945 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
8419 11728 : EQUAL(pszName, "PIXELTYPE"))
8420 : {
8421 2 : CPLError(CE_Warning, CPLE_AppDefined,
8422 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
8423 : "used to signal signed 8-bit raster. Change your code to "
8424 : "test for the new GDT_Int8 data type instead.");
8425 : }
8426 46693 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
8427 : }
8428 :
8429 : /************************************************************************/
8430 : /* GDALMDArrayFromRasterBand */
8431 : /************************************************************************/
8432 :
8433 : class GDALMDArrayFromRasterBand final : public GDALMDArray
8434 : {
8435 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
8436 :
8437 : GDALDataset *m_poDS;
8438 : GDALRasterBand *m_poBand;
8439 : GDALExtendedDataType m_dt;
8440 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
8441 : std::string m_osUnit;
8442 : std::vector<GByte> m_pabyNoData{};
8443 : std::shared_ptr<GDALMDArray> m_varX{};
8444 : std::shared_ptr<GDALMDArray> m_varY{};
8445 : std::string m_osFilename{};
8446 :
8447 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
8448 : const size_t *count, const GInt64 *arrayStep,
8449 : const GPtrDiff_t *bufferStride,
8450 : const GDALExtendedDataType &bufferDataType,
8451 : void *pBuffer) const;
8452 :
8453 : protected:
8454 23 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
8455 46 : : GDALAbstractMDArray(std::string(),
8456 46 : std::string(poDS->GetDescription()) +
8457 : CPLSPrintf(" band %d", poBand->GetBand())),
8458 46 : GDALMDArray(std::string(),
8459 46 : std::string(poDS->GetDescription()) +
8460 : CPLSPrintf(" band %d", poBand->GetBand())),
8461 : m_poDS(poDS), m_poBand(poBand),
8462 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
8463 115 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
8464 : {
8465 23 : m_poDS->Reference();
8466 :
8467 23 : int bHasNoData = false;
8468 23 : if (m_poBand->GetRasterDataType() == GDT_Int64)
8469 : {
8470 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
8471 0 : if (bHasNoData)
8472 : {
8473 0 : m_pabyNoData.resize(m_dt.GetSize());
8474 0 : GDALCopyWords(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
8475 : m_dt.GetNumericDataType(), 0, 1);
8476 : }
8477 : }
8478 23 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
8479 : {
8480 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
8481 0 : if (bHasNoData)
8482 : {
8483 0 : m_pabyNoData.resize(m_dt.GetSize());
8484 0 : GDALCopyWords(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
8485 : m_dt.GetNumericDataType(), 0, 1);
8486 : }
8487 : }
8488 : else
8489 : {
8490 23 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
8491 23 : if (bHasNoData)
8492 : {
8493 1 : m_pabyNoData.resize(m_dt.GetSize());
8494 1 : GDALCopyWords(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
8495 : m_dt.GetNumericDataType(), 0, 1);
8496 : }
8497 : }
8498 :
8499 23 : const int nXSize = poBand->GetXSize();
8500 23 : const int nYSize = poBand->GetYSize();
8501 :
8502 23 : auto poSRS = m_poDS->GetSpatialRef();
8503 46 : std::string osTypeY;
8504 46 : std::string osTypeX;
8505 46 : std::string osDirectionY;
8506 46 : std::string osDirectionX;
8507 23 : if (poSRS && poSRS->GetAxesCount() == 2)
8508 : {
8509 21 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
8510 21 : OGRAxisOrientation eOrientation1 = OAO_Other;
8511 21 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
8512 21 : OGRAxisOrientation eOrientation2 = OAO_Other;
8513 21 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
8514 21 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
8515 : {
8516 5 : if (mapping == std::vector<int>{1, 2})
8517 : {
8518 5 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
8519 5 : osDirectionY = "NORTH";
8520 5 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
8521 5 : osDirectionX = "EAST";
8522 : }
8523 : }
8524 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
8525 : {
8526 16 : if (mapping == std::vector<int>{2, 1})
8527 : {
8528 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
8529 16 : osDirectionY = "NORTH";
8530 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
8531 16 : osDirectionX = "EAST";
8532 : }
8533 : }
8534 : }
8535 :
8536 115 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
8537 : "/", "Y", osTypeY, osDirectionY, nYSize),
8538 46 : std::make_shared<GDALDimensionWeakIndexingVar>(
8539 69 : "/", "X", osTypeX, osDirectionX, nXSize)};
8540 :
8541 : double adfGeoTransform[6];
8542 23 : if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
8543 23 : adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
8544 : {
8545 44 : m_varX = GDALMDArrayRegularlySpaced::Create(
8546 22 : "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
8547 22 : 0.5);
8548 22 : m_dims[1]->SetIndexingVariable(m_varX);
8549 :
8550 44 : m_varY = GDALMDArrayRegularlySpaced::Create(
8551 22 : "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
8552 22 : 0.5);
8553 22 : m_dims[0]->SetIndexingVariable(m_varY);
8554 : }
8555 23 : }
8556 :
8557 32 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
8558 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
8559 : const GDALExtendedDataType &bufferDataType,
8560 : void *pDstBuffer) const override
8561 : {
8562 32 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
8563 32 : bufferDataType, pDstBuffer);
8564 : }
8565 :
8566 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
8567 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
8568 : const GDALExtendedDataType &bufferDataType,
8569 : const void *pSrcBuffer) override
8570 : {
8571 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
8572 : bufferStride, bufferDataType,
8573 1 : const_cast<void *>(pSrcBuffer));
8574 : }
8575 :
8576 : public:
8577 46 : ~GDALMDArrayFromRasterBand()
8578 23 : {
8579 23 : m_poDS->ReleaseRef();
8580 46 : }
8581 :
8582 23 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
8583 : GDALRasterBand *poBand)
8584 : {
8585 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
8586 46 : new GDALMDArrayFromRasterBand(poDS, poBand)));
8587 23 : array->SetSelf(array);
8588 46 : return array;
8589 : }
8590 :
8591 2 : bool IsWritable() const override
8592 : {
8593 2 : return m_poDS->GetAccess() == GA_Update;
8594 : }
8595 :
8596 97 : const std::string &GetFilename() const override
8597 : {
8598 97 : return m_osFilename;
8599 : }
8600 :
8601 : const std::vector<std::shared_ptr<GDALDimension>> &
8602 300 : GetDimensions() const override
8603 : {
8604 300 : return m_dims;
8605 : }
8606 :
8607 139 : const GDALExtendedDataType &GetDataType() const override
8608 : {
8609 139 : return m_dt;
8610 : }
8611 :
8612 3 : const std::string &GetUnit() const override
8613 : {
8614 3 : return m_osUnit;
8615 : }
8616 :
8617 29 : const void *GetRawNoDataValue() const override
8618 : {
8619 29 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
8620 : }
8621 :
8622 2 : double GetOffset(bool *pbHasOffset,
8623 : GDALDataType *peStorageType) const override
8624 : {
8625 2 : int bHasOffset = false;
8626 2 : double dfRes = m_poBand->GetOffset(&bHasOffset);
8627 2 : if (pbHasOffset)
8628 2 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
8629 2 : if (peStorageType)
8630 1 : *peStorageType = GDT_Unknown;
8631 2 : return dfRes;
8632 : }
8633 :
8634 2 : double GetScale(bool *pbHasScale,
8635 : GDALDataType *peStorageType) const override
8636 : {
8637 2 : int bHasScale = false;
8638 2 : double dfRes = m_poBand->GetScale(&bHasScale);
8639 2 : if (pbHasScale)
8640 2 : *pbHasScale = CPL_TO_BOOL(bHasScale);
8641 2 : if (peStorageType)
8642 1 : *peStorageType = GDT_Unknown;
8643 2 : return dfRes;
8644 : }
8645 :
8646 84 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
8647 : {
8648 84 : auto poSrcSRS = m_poDS->GetSpatialRef();
8649 84 : if (!poSrcSRS)
8650 2 : return nullptr;
8651 164 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
8652 :
8653 164 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
8654 82 : constexpr int iYDim = 0;
8655 82 : constexpr int iXDim = 1;
8656 246 : for (auto &m : axisMapping)
8657 : {
8658 164 : if (m == 1)
8659 82 : m = iXDim + 1;
8660 82 : else if (m == 2)
8661 82 : m = iYDim + 1;
8662 : else
8663 0 : m = 0;
8664 : }
8665 82 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
8666 82 : return poSRS;
8667 : }
8668 :
8669 29 : std::vector<GUInt64> GetBlockSize() const override
8670 : {
8671 29 : int nBlockXSize = 0;
8672 29 : int nBlockYSize = 0;
8673 29 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8674 29 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
8675 29 : static_cast<GUInt64>(nBlockXSize)};
8676 : }
8677 :
8678 : class MDIAsAttribute : public GDALAttribute
8679 : {
8680 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
8681 : const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
8682 : std::string m_osValue;
8683 :
8684 : public:
8685 2 : MDIAsAttribute(const std::string &name, const std::string &value)
8686 2 : : GDALAbstractMDArray(std::string(), name),
8687 4 : GDALAttribute(std::string(), name), m_osValue(value)
8688 : {
8689 2 : }
8690 :
8691 : const std::vector<std::shared_ptr<GDALDimension>> &
8692 3 : GetDimensions() const override
8693 : {
8694 3 : return m_dims;
8695 : }
8696 :
8697 2 : const GDALExtendedDataType &GetDataType() const override
8698 : {
8699 2 : return m_dt;
8700 : }
8701 :
8702 1 : bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
8703 : const GPtrDiff_t *,
8704 : const GDALExtendedDataType &bufferDataType,
8705 : void *pDstBuffer) const override
8706 : {
8707 1 : const char *pszStr = m_osValue.c_str();
8708 1 : GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
8709 : bufferDataType);
8710 1 : return true;
8711 : }
8712 : };
8713 :
8714 : std::vector<std::shared_ptr<GDALAttribute>>
8715 14 : GetAttributes(CSLConstList) const override
8716 : {
8717 14 : std::vector<std::shared_ptr<GDALAttribute>> res;
8718 14 : auto papszMD = m_poBand->GetMetadata();
8719 16 : for (auto iter = papszMD; iter && iter[0]; ++iter)
8720 : {
8721 2 : char *pszKey = nullptr;
8722 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
8723 2 : if (pszKey && pszValue)
8724 : {
8725 : res.emplace_back(
8726 2 : std::make_shared<MDIAsAttribute>(pszKey, pszValue));
8727 : }
8728 2 : CPLFree(pszKey);
8729 : }
8730 14 : return res;
8731 : }
8732 : };
8733 :
8734 : /************************************************************************/
8735 : /* ReadWrite() */
8736 : /************************************************************************/
8737 :
8738 33 : bool GDALMDArrayFromRasterBand::ReadWrite(
8739 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
8740 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
8741 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
8742 : {
8743 33 : constexpr size_t iDimX = 1;
8744 33 : constexpr size_t iDimY = 0;
8745 33 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
8746 : arrayStartIdx, count, arrayStep, bufferStride,
8747 33 : bufferDataType, pBuffer);
8748 : }
8749 :
8750 : /************************************************************************/
8751 : /* GDALMDRasterIOFromBand() */
8752 : /************************************************************************/
8753 :
8754 66 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
8755 : size_t iDimX, size_t iDimY,
8756 : const GUInt64 *arrayStartIdx, const size_t *count,
8757 : const GInt64 *arrayStep,
8758 : const GPtrDiff_t *bufferStride,
8759 : const GDALExtendedDataType &bufferDataType,
8760 : void *pBuffer)
8761 : {
8762 66 : const auto eDT(bufferDataType.GetNumericDataType());
8763 66 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
8764 66 : const int nX =
8765 66 : arrayStep[iDimX] > 0
8766 66 : ? static_cast<int>(arrayStartIdx[iDimX])
8767 2 : : static_cast<int>(arrayStartIdx[iDimX] -
8768 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
8769 66 : const int nY =
8770 66 : arrayStep[iDimY] > 0
8771 66 : ? static_cast<int>(arrayStartIdx[iDimY])
8772 2 : : static_cast<int>(arrayStartIdx[iDimY] -
8773 2 : (count[iDimY] - 1) * -arrayStep[iDimY]);
8774 66 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
8775 66 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
8776 66 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
8777 66 : int nStrideXSign = 1;
8778 66 : if (arrayStep[iDimX] < 0)
8779 : {
8780 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
8781 2 : nStrideXSign = -1;
8782 : }
8783 66 : int nStrideYSign = 1;
8784 66 : if (arrayStep[iDimY] < 0)
8785 : {
8786 2 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
8787 2 : nStrideYSign = -1;
8788 : }
8789 :
8790 132 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
8791 66 : static_cast<int>(count[iDimX]),
8792 66 : static_cast<int>(count[iDimY]), eDT,
8793 : static_cast<GSpacing>(
8794 66 : nStrideXSign * bufferStride[iDimX] * nDTSize),
8795 : static_cast<GSpacing>(
8796 66 : nStrideYSign * bufferStride[iDimY] * nDTSize),
8797 66 : nullptr) == CE_None;
8798 : }
8799 :
8800 : /************************************************************************/
8801 : /* AsMDArray() */
8802 : /************************************************************************/
8803 :
8804 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
8805 : *
8806 : * The band must be linked to a GDALDataset. If this dataset is not already
8807 : * marked as shared, it will be, so that the returned array holds a reference
8808 : * to it.
8809 : *
8810 : * If the dataset has a geotransform attached, the X and Y dimensions of the
8811 : * returned array will have an associated indexing variable.
8812 : *
8813 : * This is the same as the C function GDALRasterBandAsMDArray().
8814 : *
8815 : * The "reverse" method is GDALMDArray::AsClassicDataset().
8816 : *
8817 : * @return a new array, or nullptr.
8818 : *
8819 : * @since GDAL 3.1
8820 : */
8821 23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
8822 : {
8823 23 : if (!poDS)
8824 : {
8825 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
8826 0 : return nullptr;
8827 : }
8828 23 : if (!poDS->GetShared())
8829 : {
8830 23 : poDS->MarkAsShared();
8831 : }
8832 : return GDALMDArrayFromRasterBand::Create(
8833 23 : poDS, const_cast<GDALRasterBand *>(this));
8834 : }
|