31using namespace Qt::StringLiterals;
33#define GDAL_MINMAXELT_NS qgis_gdal
34#include "gdal_minmax_element.hpp"
37const QRgb QgsRasterBlock::NO_DATA_COLOR = qRgba( 0, 0, 0, 0 );
40 : mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
47 , mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
49 ( void )
reset( mDataType, mWidth, mHeight );
54 QgsDebugMsgLevel( u
"mData = %1"_s.arg(
reinterpret_cast< quint64
>( mData ) ), 4 );
69 mNoDataBitmap =
nullptr;
74 mHasNoDataValue =
false;
75 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
93 const QImage::Format format = imageFormat(
dataType );
94 mImage = std::make_unique<QImage>(
width,
height, format );
108 u
"mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5"_s.arg( mWidth )
110 .arg(
static_cast< int>( mDataType ) )
111 .arg(
reinterpret_cast< quint64
>( mData ) )
112 .arg(
reinterpret_cast< quint64
>( mImage.get() ) ),
118QImage::Format QgsRasterBlock::imageFormat(
Qgis::DataType dataType )
122 return QImage::Format_ARGB32;
126 return QImage::Format_ARGB32_Premultiplied;
128 return QImage::Format_Invalid;
133 if ( format == QImage::Format_ARGB32 )
137 else if ( format == QImage::Format_ARGB32_Premultiplied )
147 u
"mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5"_s.arg( mWidth )
150 .arg(
reinterpret_cast< quint64
>( mData ) )
151 .arg(
reinterpret_cast< quint64
>( mImage.get() ) ),
154 return mWidth == 0 || mHeight == 0 || (
typeIsNumeric( mDataType ) && !mData ) || (
typeIsColor( mDataType ) && !mImage );
258 *
noDataValue = std::numeric_limits<double>::max() * -1.0;
277 mHasNoDataValue =
true;
283 mHasNoDataValue =
false;
284 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
292 if ( mHasNoDataValue )
294 return fill( mNoDataValue );
299 if ( !mNoDataBitmap )
301 if ( !createNoDataBitmap() )
307 memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
325 mImage->fill( NO_DATA_COLOR );
332 int top = exceptRect.top();
333 int bottom = exceptRect.bottom();
334 int left = exceptRect.left();
335 int right = exceptRect.right();
336 top = std::min( std::max( top, 0 ), mHeight - 1 );
337 left = std::min( std::max( left, 0 ), mWidth - 1 );
338 bottom = std::max( 0, std::min( bottom, mHeight - 1 ) );
339 right = std::max( 0, std::min( right, mWidth - 1 ) );
345 if ( mHasNoDataValue )
354 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
356 char *nodata = noDataByteArray.data();
358 for (
int c = 0;
c < mWidth;
c++ )
364 for (
int r = 0; r < mHeight; r++ )
366 if ( r >= top && r <= bottom )
372 for (
int r = top; r <= bottom; r++ )
379 const int w = mWidth - right - 1;
387 if ( !mNoDataBitmap )
389 if ( !createNoDataBitmap() )
401 char *nodataRow =
new char[mNoDataBitmapWidth];
403 memset( nodataRow, 0, mNoDataBitmapWidth );
404 for (
int c = 0;
c < mWidth;
c++ )
406 const int byte =
c / 8;
407 const int bit =
c % 8;
408 const char nodata = 0x80 >> bit;
409 memset( nodataRow +
byte, nodataRow[
byte] | nodata, 1 );
413 for (
int r = 0; r < mHeight; r++ )
415 if ( r >= top && r <= bottom )
417 const qgssize i =
static_cast< qgssize >( r ) * mNoDataBitmapWidth;
418 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
421 memset( nodataRow, 0, mNoDataBitmapWidth );
422 for (
int c = 0;
c < mWidth;
c++ )
424 if (
c >= left &&
c <= right )
426 const int byte =
c / 8;
427 const int bit =
c % 8;
428 const char nodata = 0x80 >> bit;
429 memset( nodataRow +
byte, nodataRow[
byte] | nodata, 1 );
431 for (
int r = top; r <= bottom; r++ )
433 const qgssize i =
static_cast< qgssize >( r ) * mNoDataBitmapWidth;
434 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
449 if ( mImage->width() != mWidth || mImage->height() != mHeight )
458 if ( mImage->depth() != 32 )
464 const QRgb nodataRgba = NO_DATA_COLOR;
465 QRgb *nodataRow =
new QRgb[mWidth];
466 const int rgbSize =
sizeof( QRgb );
467 for (
int c = 0;
c < mWidth;
c++ )
469 nodataRow[
c] = nodataRgba;
473 for (
int r = 0; r < mHeight; r++ )
475 if ( r >= top && r <= bottom )
478 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( mWidth ) );
481 for (
int r = top; r <= bottom; r++ )
487 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( left - 1 ) );
491 const int w = mWidth - right - 1;
492 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( w ) );
499template<
typename T>
void fillTypedData(
double value,
void *data, std::size_t count )
501 std::fill_n(
static_cast<T *
>( data ), count,
static_cast<T
>( value ) );
520 const std::size_t valueCount =
static_cast<size_t>( mWidth ) * mHeight;
521 const std::size_t totalSize = valueCount *
dataTypeSize;
528 memset( mData, 0, totalSize );
576 return QByteArray::fromRawData(
static_cast<const char *
>( mData ),
typeSize( mDataType ) * mWidth * mHeight );
577 else if ( mImage && mImage->constBits() )
578 return QByteArray::fromRawData(
reinterpret_cast<const char *
>( mImage->constBits() ), mImage->sizeInBytes() );
590 const int len = std::min(
static_cast<int>(
data.size() ),
typeSize( mDataType ) * mWidth * mHeight - offset );
591 ::memcpy(
static_cast<char *
>( mData ) + offset,
data.constData(), len );
593 else if ( mImage && mImage->constBits() )
595 const qsizetype len = std::min(
static_cast< qsizetype
>(
data.size() ), mImage->sizeInBytes() - offset );
596 ::memcpy( mImage->bits() + offset,
data.constData(), len );
603 if ( index >=
static_cast< qgssize >( mWidth ) * mHeight )
605 QgsDebugMsgLevel( u
"Index %1 out of range (%2 x %3)"_s.arg( index ).arg( mWidth ).arg( mHeight ), 4 );
610 return reinterpret_cast< char *
>( mData ) + index * mTypeSize;
614 if ( uchar *
data = mImage->bits() )
616 return reinterpret_cast< char *
>(
data + index * 4 );
626 if ( index >=
static_cast< qgssize >( mWidth ) * mHeight )
628 QgsDebugMsgLevel( u
"Index %1 out of range (%2 x %3)"_s.arg( index ).arg( mWidth ).arg( mHeight ), 4 );
633 return reinterpret_cast< const char *
>( mData ) + index * mTypeSize;
637 if (
const uchar *
data = mImage->constBits() )
639 return reinterpret_cast< const char *
>(
data + index * 4 );
648 return bits(
static_cast< qgssize >( row ) * mWidth + column );
655 return reinterpret_cast< char *
>( mData );
659 if ( uchar *
data = mImage->bits() )
661 return reinterpret_cast< char *
>(
data );
672 return reinterpret_cast< const char *
>( mData );
676 if (
const uchar *
data = mImage->constBits() )
678 return reinterpret_cast< const char *
>(
data );
689 if ( destDataType == mDataType )
694 void *
data =
convert( mData, mDataType, destDataType,
static_cast< qgssize >( mWidth ) *
static_cast< qgssize >( mHeight ) );
703 mDataType = destDataType;
708 const QImage::Format format = imageFormat( destDataType );
709 const QImage
image = mImage->convertToFormat( format );
711 mDataType = destDataType;
728 if ( scale == 1.0 && offset == 0.0 )
732 for (
qgssize i = 0; i < size; ++i )
741 if ( rangeList.isEmpty() )
747 for (
qgssize i = 0; i < size; ++i )
749 const double val =
value( i );
762 return QImage( *mImage );
772 mImage = std::make_unique<QImage>( *
image );
773 mWidth = mImage->width();
774 mHeight = mImage->height();
775 mDataType =
dataType( mImage->format() );
777 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
807 for (
int i = 15; i <= 17; i++ )
809 s.setNum(
value,
'g', i );
810 const double doubleValue { s.toDouble() };
815 return QLocale().toString( doubleValue,
'g', i );
833 for (
int i = 6; i <= 9; i++ )
835 s.setNum(
value,
'g', i );
836 const float floatValue { s.toFloat() };
841 return QLocale().toString( floatValue,
'g', i );
853 const int destDataTypeSize =
typeSize( destDataType );
854 void *destData =
qgsMalloc( destDataTypeSize * size );
855 for (
qgssize i = 0; i < size; i++ )
869 ba.resize(
static_cast< int >( size ) );
870 char *
data = ba.data();
881 uc =
static_cast< quint8
>(
value );
882 memcpy(
data, &uc, size );
886 const qint8 myint8 =
static_cast< qint8
>(
value );
887 memcpy(
data, &myint8, size );
891 us =
static_cast< quint16
>(
value );
892 memcpy(
data, &us, size );
895 s =
static_cast< qint16
>(
value );
896 memcpy(
data, &s, size );
899 ui =
static_cast< quint32
>(
value );
900 memcpy(
data, &ui, size );
903 i =
static_cast< qint32
>(
value );
904 memcpy(
data, &i, size );
907 f =
static_cast< float >(
value );
908 memcpy(
data, &f, size );
911 d =
static_cast< double >(
value );
912 memcpy(
data, &d, size );
926bool QgsRasterBlock::createNoDataBitmap()
928 mNoDataBitmapWidth = mWidth / 8 + 1;
929 mNoDataBitmapSize =
static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
931 mNoDataBitmap =
reinterpret_cast< char *
>(
qgsMalloc( mNoDataBitmapSize ) );
932 if ( !mNoDataBitmap )
934 QgsDebugError( u
"Couldn't allocate no data memory of %1 bytes"_s.arg( mNoDataBitmapSize ) );
937 memset( mNoDataBitmap, 0, mNoDataBitmapSize );
958 int right =
width - 1;
966 bottom = std::round( ( extent.
yMaximum() - subExtent.
yMinimum() ) / yRes ) - 1;
975 right = std::round( ( subExtent.
xMaximum() - extent.
xMinimum() ) / xRes ) - 1;
977 QRect
subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
986 minimum = std::numeric_limits<double>::quiet_NaN();
990 const std::size_t offset
993 row =
static_cast< int >( offset / mWidth );
994 column =
static_cast< int >( offset % mWidth );
1004 maximum = std::numeric_limits<double>::quiet_NaN();
1007 const std::size_t offset
1010 row =
static_cast< int >( offset / mWidth );
1011 column =
static_cast< int >( offset % mWidth );
1021 minimum = std::numeric_limits<double>::quiet_NaN();
1022 maximum = std::numeric_limits<double>::quiet_NaN();
1026 const auto [minOffset, maxOffset]
1029 minimumRow =
static_cast< int >( minOffset / mWidth );
1030 minimumColumn =
static_cast< int >( minOffset % mWidth );
1033 maximumRow =
static_cast< int >( maxOffset / mWidth );
1034 maximumColumn =
static_cast< int >( maxOffset % mWidth );
DataType
Raster data types.
@ Float32
Thirty two bit floating point (float).
@ CFloat64
Complex Float64.
@ Int16
Sixteen bit signed integer (qint16).
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30).
@ UInt16
Sixteen bit unsigned integer (quint16).
@ Byte
Eight bit unsigned integer (quint8).
@ UnknownDataType
Unknown or unspecified type.
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
@ Int32
Thirty two bit signed integer (qint32).
@ Float64
Sixty four bit floating point (double).
@ CFloat32
Complex Float32.
@ UInt32
Thirty two bit unsigned integer (quint32).
static GDALDataType gdalDataTypeFromQgisDataType(Qgis::DataType dataType)
Returns the GDAL data type corresponding to the QGIS data type dataType.
bool isEmpty() const
Returns true if block is empty, i.e.
double value(int row, int column) const
Read a single value if type of block is numeric.
static bool typeIsNumeric(Qgis::DataType type)
Returns true if a data type is numeric.
bool minimumMaximum(double &minimum, int &minimumRow, int &minimumColumn, double &maximum, int &maximumRow, int &maximumColumn) const
Returns the minimum and maximum value present in the raster block.
int height() const
Returns the height (number of rows) of the raster block.
bool convert(Qgis::DataType destDataType)
Convert data to different type.
bool setIsNoData()
Set the whole block to no data.
bool maximum(double &maximum, int &row, int &column) const
Returns the maximum value present in the raster block.
void resetNoDataValue()
Reset no data value: if there was a no data value previously set, it will be discarded.
int dataTypeSize() const
Data type size in bytes.
static int typeSize(Qgis::DataType dataType)
Returns the size in bytes for the specified dataType.
bool setIsNoDataExcept(QRect exceptRect)
Set the whole block to no data except specified rectangle.
bool setImage(const QImage *image)
Sets the block data via an image.
QByteArray data() const
Gets access to raw data.
double noDataValue() const
Returns no data value.
const char * constBits() const
Returns a const pointer to block data.
void setData(const QByteArray &data, int offset=0)
Rewrite raw pixel data.
void applyNoDataValues(const QgsRasterRangeList &rangeList)
bool setValue(int row, int column, double value)
Set value on position.
bool isNoData(int row, int column) const
Checks if value at position is no data.
Qgis::DataType dataType() const
Returns data type.
char * bits()
Returns a pointer to block data.
static Qgis::DataType typeWithNoDataValue(Qgis::DataType dataType, double *noDataValue)
For given data type returns wider type and sets no data value.
QImage image() const
Returns an image containing the block data, if the block's data type is color.
void setNoDataValue(double noDataValue)
Sets cell value that will be considered as "no data".
static bool typeIsComplex(Qgis::DataType type)
Returns true if a data type is a complex number type.
bool fill(double value)
Fills the whole block with a constant value.
virtual ~QgsRasterBlock()
static void writeValue(void *data, Qgis::DataType type, qgssize index, double value)
int width() const
Returns the width (number of columns) of the raster block.
void applyScaleOffset(double scale, double offset)
Apply band scale and offset to raster block values.
static QString printValue(double value, bool localized=false)
Print double value with all necessary significant digits.
static QRect subRect(const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent)
For extent and width, height find rectangle covered by subextent.
static bool typeIsColor(Qgis::DataType type)
Returns true if a data type is a color type.
static double readValue(void *data, Qgis::DataType type, qgssize index)
static QByteArray valueBytes(Qgis::DataType dataType, double value)
Gets byte array representing a value.
bool reset(Qgis::DataType dataType, int width, int height)
Reset block.
bool minimum(double &minimum, int &row, int &column) const
Returns the minimum value present in the raster block.
bool contains(double value) const
Returns true if this range contains the specified value.
A rectangle specified with double values.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be rounded to the spec...
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
void * qgsMalloc(size_t size)
Allocates size bytes and returns a pointer to the allocated memory.
void qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
bool qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference).
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
void fillTypedData(double value, void *data, std::size_t count)
QList< QgsRasterRange > QgsRasterRangeList