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