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() )
48 , mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
50 ( void )
reset( mDataType, mWidth, mHeight );
55 QgsDebugMsgLevel( u
"mData = %1"_s.arg(
reinterpret_cast< quint64
>( mData ) ), 4 );
70 mNoDataBitmap =
nullptr;
75 mHasNoDataValue =
false;
76 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
94 const QImage::Format format = imageFormat(
dataType );
108 QgsDebugMsgLevel( u
"mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5"_s.arg( mWidth ).arg( mHeight ).arg(
static_cast< int>( mDataType ) )
109 .arg(
reinterpret_cast< quint64
>( mData ) ).arg(
reinterpret_cast< quint64
>( mImage ) ), 4 );
113QImage::Format QgsRasterBlock::imageFormat(
Qgis::DataType dataType )
117 return QImage::Format_ARGB32;
121 return QImage::Format_ARGB32_Premultiplied;
123 return QImage::Format_Invalid;
128 if ( format == QImage::Format_ARGB32 )
132 else if ( format == QImage::Format_ARGB32_Premultiplied )
142 .arg(
reinterpret_cast< quint64
>( mData ) ).arg(
reinterpret_cast< quint64
>( mImage ) ), 4 );
143 return mWidth == 0 || mHeight == 0 ||
249 *
noDataValue = std::numeric_limits<double>::max() * -1.0;
268 mHasNoDataValue =
true;
274 mHasNoDataValue =
false;
275 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
283 if ( mHasNoDataValue )
285 return fill( mNoDataValue );
290 if ( !mNoDataBitmap )
292 if ( !createNoDataBitmap() )
298 memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
316 mImage->fill( NO_DATA_COLOR );
323 int top = exceptRect.top();
324 int bottom = exceptRect.bottom();
325 int left = exceptRect.left();
326 int right = exceptRect.right();
327 top = std::min( std::max( top, 0 ), mHeight - 1 );
328 left = std::min( std::max( left, 0 ), mWidth - 1 );
329 bottom = std::max( 0, std::min( bottom, mHeight - 1 ) );
330 right = std::max( 0, std::min( right, mWidth - 1 ) );
336 if ( mHasNoDataValue )
345 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
347 char *nodata = noDataByteArray.data();
349 for (
int c = 0;
c < mWidth;
c++ )
355 for (
int r = 0; r < mHeight; r++ )
357 if ( r >= top && r <= bottom )
continue;
362 for (
int r = top; r <= bottom; r++ )
369 const int w = mWidth - right - 1;
377 if ( !mNoDataBitmap )
379 if ( !createNoDataBitmap() )
391 char *nodataRow =
new char[mNoDataBitmapWidth];
393 memset( nodataRow, 0, mNoDataBitmapWidth );
394 for (
int c = 0;
c < mWidth;
c ++ )
396 const int byte =
c / 8;
397 const int bit =
c % 8;
398 const char nodata = 0x80 >> bit;
399 memset( nodataRow +
byte, nodataRow[
byte] | nodata, 1 );
403 for (
int r = 0; r < mHeight; r++ )
405 if ( r >= top && r <= bottom )
continue;
406 const qgssize i =
static_cast< qgssize >( r ) * mNoDataBitmapWidth;
407 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
410 memset( nodataRow, 0, mNoDataBitmapWidth );
411 for (
int c = 0;
c < mWidth;
c ++ )
413 if (
c >= left &&
c <= right )
continue;
414 const int byte =
c / 8;
415 const int bit =
c % 8;
416 const char nodata = 0x80 >> bit;
417 memset( nodataRow +
byte, nodataRow[
byte] | nodata, 1 );
419 for (
int r = top; r <= bottom; r++ )
421 const qgssize i =
static_cast< qgssize >( r ) * mNoDataBitmapWidth;
422 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
437 if ( mImage->width() != mWidth || mImage->height() != mHeight )
446 if ( mImage->depth() != 32 )
452 const QRgb nodataRgba = NO_DATA_COLOR;
453 QRgb *nodataRow =
new QRgb[mWidth];
454 const int rgbSize =
sizeof( QRgb );
455 for (
int c = 0;
c < mWidth;
c ++ )
457 nodataRow[
c] = nodataRgba;
461 for (
int r = 0; r < mHeight; r++ )
463 if ( r >= top && r <= bottom )
continue;
465 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( mWidth ) );
468 for (
int r = top; r <= bottom; r++ )
474 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( left - 1 ) );
478 const int w = mWidth - right - 1;
479 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( w ) );
489 std::fill_n(
static_cast<T *
>( data ), count,
static_cast<T
>( value ) );
508 const std::size_t valueCount =
static_cast<size_t>( mWidth ) * mHeight;
509 const std::size_t totalSize = valueCount *
dataTypeSize;
516 memset( mData, 0, totalSize );
564 return QByteArray::fromRawData(
static_cast<const char *
>( mData ),
typeSize( mDataType ) * mWidth * mHeight );
565 else if ( mImage && mImage->constBits() )
566 return QByteArray::fromRawData(
reinterpret_cast<const char *
>( mImage->constBits() ), mImage->sizeInBytes() );
578 const int len = std::min(
static_cast<int>(
data.size() ),
typeSize( mDataType ) * mWidth * mHeight - offset );
579 ::memcpy(
static_cast<char *
>( mData ) + offset,
data.constData(), len );
581 else if ( mImage && mImage->constBits() )
583 const qsizetype len = std::min(
static_cast< qsizetype
>(
data.size() ), mImage->sizeInBytes() - offset );
584 ::memcpy( mImage->bits() + offset,
data.constData(), len );
591 if ( index >=
static_cast< qgssize >( mWidth )*mHeight )
593 QgsDebugMsgLevel( u
"Index %1 out of range (%2 x %3)"_s.arg( index ).arg( mWidth ).arg( mHeight ), 4 );
598 return reinterpret_cast< char *
>( mData ) + index * mTypeSize;
602 if ( uchar *
data = mImage->bits() )
604 return reinterpret_cast< char *
>(
data + index * 4 );
614 if ( index >=
static_cast< qgssize >( mWidth )*mHeight )
616 QgsDebugMsgLevel( u
"Index %1 out of range (%2 x %3)"_s.arg( index ).arg( mWidth ).arg( mHeight ), 4 );
621 return reinterpret_cast< const char *
>( mData ) + index * mTypeSize;
625 if (
const uchar *
data = mImage->constBits() )
627 return reinterpret_cast< const char *
>(
data + index * 4 );
636 return bits(
static_cast< qgssize >( row ) * mWidth + column );
643 return reinterpret_cast< char *
>( mData );
647 if ( uchar *
data = mImage->bits() )
649 return reinterpret_cast< char *
>(
data );
660 return reinterpret_cast< const char *
>( mData );
664 if (
const uchar *
data = mImage->constBits() )
666 return reinterpret_cast< const char *
>(
data );
676 if ( destDataType == mDataType )
return true;
680 void *
data =
convert( mData, mDataType, destDataType,
static_cast< qgssize >( mWidth ) *
static_cast< qgssize >( mHeight ) );
689 mDataType = destDataType;
694 const QImage::Format format = imageFormat( destDataType );
695 const QImage
image = mImage->convertToFormat( format );
697 mDataType = destDataType;
712 if ( scale == 1.0 && offset == 0.0 )
return;
715 for (
qgssize i = 0; i < size; ++i )
723 if ( rangeList.isEmpty() )
729 for (
qgssize i = 0; i < size; ++i )
731 const double val =
value( i );
744 return QImage( *mImage );
755 mImage =
new QImage( *
image );
756 mWidth = mImage->width();
757 mHeight = mImage->height();
758 mDataType =
dataType( mImage->format() );
760 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
790 for (
int i = 15; i <= 17; i++ )
792 s.setNum(
value,
'g', i );
793 const double doubleValue { s.toDouble( ) };
798 return QLocale().toString( doubleValue,
'g', i );
816 for (
int i = 6; i <= 9; i++ )
818 s.setNum(
value,
'g', i );
819 const float floatValue { s.toFloat() };
824 return QLocale().toString( floatValue,
'g', i );
836 const int destDataTypeSize =
typeSize( destDataType );
837 void *destData =
qgsMalloc( destDataTypeSize * size );
838 for (
qgssize i = 0; i < size; i++ )
852 ba.resize(
static_cast< int >( size ) );
853 char *
data = ba.data();
864 uc =
static_cast< quint8
>(
value );
865 memcpy(
data, &uc, size );
869 const qint8 myint8 =
static_cast< qint8
>(
value );
870 memcpy(
data, &myint8, size );
874 us =
static_cast< quint16
>(
value );
875 memcpy(
data, &us, size );
878 s =
static_cast< qint16
>(
value );
879 memcpy(
data, &s, size );
882 ui =
static_cast< quint32
>(
value );
883 memcpy(
data, &ui, size );
886 i =
static_cast< qint32
>(
value );
887 memcpy(
data, &i, size );
890 f =
static_cast< float >(
value );
891 memcpy(
data, &f, size );
894 d =
static_cast< double >(
value );
895 memcpy(
data, &d, size );
909bool QgsRasterBlock::createNoDataBitmap()
911 mNoDataBitmapWidth = mWidth / 8 + 1;
912 mNoDataBitmapSize =
static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
914 mNoDataBitmap =
reinterpret_cast< char *
>(
qgsMalloc( mNoDataBitmapSize ) );
915 if ( !mNoDataBitmap )
917 QgsDebugError( u
"Couldn't allocate no data memory of %1 bytes"_s.arg( mNoDataBitmapSize ) );
920 memset( mNoDataBitmap, 0, mNoDataBitmapSize );
926 return u
"dataType = %1 width = %2 height = %3"_s
942 int right =
width - 1;
950 bottom = std::round( ( extent.
yMaximum() - subExtent.
yMinimum() ) / yRes ) - 1;
959 right = std::round( ( subExtent.
xMaximum() - extent.
xMinimum() ) / xRes ) - 1;
961 QRect
subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
970 minimum = std::numeric_limits<double>::quiet_NaN();
974 const std::size_t offset = qgis_gdal::min_element( mData,
static_cast<std::size_t
>( mWidth ) *
static_cast< std::size_t
>( mHeight ),
977 row =
static_cast< int >( offset / mWidth );
978 column =
static_cast< int >( offset % mWidth );
988 maximum = std::numeric_limits<double>::quiet_NaN();
991 const std::size_t offset = qgis_gdal::max_element( mData,
static_cast<std::size_t
>( mWidth ) *
static_cast< std::size_t
>( mHeight ),
994 row =
static_cast< int >( offset / mWidth );
995 column =
static_cast< int >( offset % mWidth );
1005 minimum = std::numeric_limits<double>::quiet_NaN();
1006 maximum = std::numeric_limits<double>::quiet_NaN();
1010 const auto [minOffset, maxOffset] = qgis_gdal::minmax_element( mData,
static_cast<std::size_t
>( mWidth ) *
static_cast< std::size_t
>( mHeight ),
1013 minimumRow =
static_cast< int >( minOffset / mWidth );
1014 minimumColumn =
static_cast< int >( minOffset % mWidth );
1017 maximumRow =
static_cast< int >( maxOffset / mWidth );
1018 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 truncated to the sp...
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