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 );
107 QgsDebugMsgLevel( u
"mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5"_s.arg( mWidth ).arg( mHeight ).arg(
static_cast< int>( mDataType ) ).arg(
reinterpret_cast< quint64
>( mData ) ).arg(
reinterpret_cast< quint64
>( mImage ) ), 4 );
111QImage::Format QgsRasterBlock::imageFormat(
Qgis::DataType dataType )
115 return QImage::Format_ARGB32;
119 return QImage::Format_ARGB32_Premultiplied;
121 return QImage::Format_Invalid;
126 if ( format == QImage::Format_ARGB32 )
130 else if ( format == QImage::Format_ARGB32_Premultiplied )
139 QgsDebugMsgLevel( u
"mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5"_s.arg( mWidth ).arg( mHeight ).arg(
qgsEnumValueToKey( mDataType ) ).arg(
reinterpret_cast< quint64
>( mData ) ).arg(
reinterpret_cast< quint64
>( mImage ) ), 4 );
140 return mWidth == 0 || mHeight == 0 || (
typeIsNumeric( mDataType ) && !mData ) || (
typeIsColor( mDataType ) && !mImage );
244 *
noDataValue = std::numeric_limits<double>::max() * -1.0;
263 mHasNoDataValue =
true;
269 mHasNoDataValue =
false;
270 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
278 if ( mHasNoDataValue )
280 return fill( mNoDataValue );
285 if ( !mNoDataBitmap )
287 if ( !createNoDataBitmap() )
293 memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
311 mImage->fill( NO_DATA_COLOR );
318 int top = exceptRect.top();
319 int bottom = exceptRect.bottom();
320 int left = exceptRect.left();
321 int right = exceptRect.right();
322 top = std::min( std::max( top, 0 ), mHeight - 1 );
323 left = std::min( std::max( left, 0 ), mWidth - 1 );
324 bottom = std::max( 0, std::min( bottom, mHeight - 1 ) );
325 right = std::max( 0, std::min( right, mWidth - 1 ) );
331 if ( mHasNoDataValue )
340 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
342 char *nodata = noDataByteArray.data();
344 for (
int c = 0;
c < mWidth;
c++ )
350 for (
int r = 0; r < mHeight; r++ )
352 if ( r >= top && r <= bottom )
358 for (
int r = top; r <= bottom; r++ )
365 const int w = mWidth - right - 1;
373 if ( !mNoDataBitmap )
375 if ( !createNoDataBitmap() )
387 char *nodataRow =
new char[mNoDataBitmapWidth];
389 memset( nodataRow, 0, mNoDataBitmapWidth );
390 for (
int c = 0;
c < mWidth;
c++ )
392 const int byte =
c / 8;
393 const int bit =
c % 8;
394 const char nodata = 0x80 >> bit;
395 memset( nodataRow +
byte, nodataRow[
byte] | nodata, 1 );
399 for (
int r = 0; r < mHeight; r++ )
401 if ( r >= top && r <= bottom )
403 const qgssize i =
static_cast< qgssize >( r ) * mNoDataBitmapWidth;
404 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
407 memset( nodataRow, 0, mNoDataBitmapWidth );
408 for (
int c = 0;
c < mWidth;
c++ )
410 if (
c >= left &&
c <= right )
412 const int byte =
c / 8;
413 const int bit =
c % 8;
414 const char nodata = 0x80 >> bit;
415 memset( nodataRow +
byte, nodataRow[
byte] | nodata, 1 );
417 for (
int r = top; r <= bottom; r++ )
419 const qgssize i =
static_cast< qgssize >( r ) * mNoDataBitmapWidth;
420 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
435 if ( mImage->width() != mWidth || mImage->height() != mHeight )
444 if ( mImage->depth() != 32 )
450 const QRgb nodataRgba = NO_DATA_COLOR;
451 QRgb *nodataRow =
new QRgb[mWidth];
452 const int rgbSize =
sizeof( QRgb );
453 for (
int c = 0;
c < mWidth;
c++ )
455 nodataRow[
c] = nodataRgba;
459 for (
int r = 0; r < mHeight; r++ )
461 if ( r >= top && r <= bottom )
464 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( mWidth ) );
467 for (
int r = top; r <= bottom; r++ )
473 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( left - 1 ) );
477 const int w = mWidth - right - 1;
478 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( w ) );
485template<
typename T>
void fillTypedData(
double value,
void *data, std::size_t count )
487 std::fill_n(
static_cast<T *
>( data ), count,
static_cast<T
>( value ) );
506 const std::size_t valueCount =
static_cast<size_t>( mWidth ) * mHeight;
507 const std::size_t totalSize = valueCount *
dataTypeSize;
514 memset( mData, 0, totalSize );
562 return QByteArray::fromRawData(
static_cast<const char *
>( mData ),
typeSize( mDataType ) * mWidth * mHeight );
563 else if ( mImage && mImage->constBits() )
564 return QByteArray::fromRawData(
reinterpret_cast<const char *
>( mImage->constBits() ), mImage->sizeInBytes() );
576 const int len = std::min(
static_cast<int>(
data.size() ),
typeSize( mDataType ) * mWidth * mHeight - offset );
577 ::memcpy(
static_cast<char *
>( mData ) + offset,
data.constData(), len );
579 else if ( mImage && mImage->constBits() )
581 const qsizetype len = std::min(
static_cast< qsizetype
>(
data.size() ), mImage->sizeInBytes() - offset );
582 ::memcpy( mImage->bits() + offset,
data.constData(), len );
589 if ( index >=
static_cast< qgssize >( mWidth ) * mHeight )
591 QgsDebugMsgLevel( u
"Index %1 out of range (%2 x %3)"_s.arg( index ).arg( mWidth ).arg( mHeight ), 4 );
596 return reinterpret_cast< char *
>( mData ) + index * mTypeSize;
600 if ( uchar *
data = mImage->bits() )
602 return reinterpret_cast< char *
>(
data + index * 4 );
612 if ( index >=
static_cast< qgssize >( mWidth ) * mHeight )
614 QgsDebugMsgLevel( u
"Index %1 out of range (%2 x %3)"_s.arg( index ).arg( mWidth ).arg( mHeight ), 4 );
619 return reinterpret_cast< const char *
>( mData ) + index * mTypeSize;
623 if (
const uchar *
data = mImage->constBits() )
625 return reinterpret_cast< const char *
>(
data + index * 4 );
634 return bits(
static_cast< qgssize >( row ) * mWidth + column );
641 return reinterpret_cast< char *
>( mData );
645 if ( uchar *
data = mImage->bits() )
647 return reinterpret_cast< char *
>(
data );
658 return reinterpret_cast< const char *
>( mData );
662 if (
const uchar *
data = mImage->constBits() )
664 return reinterpret_cast< const char *
>(
data );
675 if ( destDataType == mDataType )
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;
714 if ( scale == 1.0 && offset == 0.0 )
718 for (
qgssize i = 0; i < size; ++i )
727 if ( rangeList.isEmpty() )
733 for (
qgssize i = 0; i < size; ++i )
735 const double val =
value( i );
748 return QImage( *mImage );
759 mImage =
new QImage( *
image );
760 mWidth = mImage->width();
761 mHeight = mImage->height();
762 mDataType =
dataType( mImage->format() );
764 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
794 for (
int i = 15; i <= 17; i++ )
796 s.setNum(
value,
'g', i );
797 const double doubleValue { s.toDouble() };
802 return QLocale().toString( doubleValue,
'g', i );
820 for (
int i = 6; i <= 9; i++ )
822 s.setNum(
value,
'g', i );
823 const float floatValue { s.toFloat() };
828 return QLocale().toString( floatValue,
'g', i );
840 const int destDataTypeSize =
typeSize( destDataType );
841 void *destData =
qgsMalloc( destDataTypeSize * size );
842 for (
qgssize i = 0; i < size; i++ )
856 ba.resize(
static_cast< int >( size ) );
857 char *
data = ba.data();
868 uc =
static_cast< quint8
>(
value );
869 memcpy(
data, &uc, size );
873 const qint8 myint8 =
static_cast< qint8
>(
value );
874 memcpy(
data, &myint8, size );
878 us =
static_cast< quint16
>(
value );
879 memcpy(
data, &us, size );
882 s =
static_cast< qint16
>(
value );
883 memcpy(
data, &s, size );
886 ui =
static_cast< quint32
>(
value );
887 memcpy(
data, &ui, size );
890 i =
static_cast< qint32
>(
value );
891 memcpy(
data, &i, size );
894 f =
static_cast< float >(
value );
895 memcpy(
data, &f, size );
898 d =
static_cast< double >(
value );
899 memcpy(
data, &d, size );
913bool QgsRasterBlock::createNoDataBitmap()
915 mNoDataBitmapWidth = mWidth / 8 + 1;
916 mNoDataBitmapSize =
static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
918 mNoDataBitmap =
reinterpret_cast< char *
>(
qgsMalloc( mNoDataBitmapSize ) );
919 if ( !mNoDataBitmap )
921 QgsDebugError( u
"Couldn't allocate no data memory of %1 bytes"_s.arg( mNoDataBitmapSize ) );
924 memset( mNoDataBitmap, 0, mNoDataBitmapSize );
945 int right =
width - 1;
953 bottom = std::round( ( extent.
yMaximum() - subExtent.
yMinimum() ) / yRes ) - 1;
962 right = std::round( ( subExtent.
xMaximum() - extent.
xMinimum() ) / xRes ) - 1;
964 QRect
subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
973 minimum = std::numeric_limits<double>::quiet_NaN();
977 const std::size_t offset
980 row =
static_cast< int >( offset / mWidth );
981 column =
static_cast< int >( offset % mWidth );
991 maximum = std::numeric_limits<double>::quiet_NaN();
994 const std::size_t offset
997 row =
static_cast< int >( offset / mWidth );
998 column =
static_cast< int >( offset % mWidth );
1008 minimum = std::numeric_limits<double>::quiet_NaN();
1009 maximum = std::numeric_limits<double>::quiet_NaN();
1013 const auto [minOffset, maxOffset]
1016 minimumRow =
static_cast< int >( minOffset / mWidth );
1017 minimumColumn =
static_cast< int >( minOffset % mWidth );
1020 maximumRow =
static_cast< int >( maxOffset / mWidth );
1021 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