29const QRgb QgsRasterBlock::NO_DATA_COLOR = qRgba( 0, 0, 0, 0 );
32 : mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
37 : mDataType( dataType )
40 , mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
42 ( void )
reset( mDataType, mWidth, mHeight );
47 QgsDebugMsgLevel( QStringLiteral(
"mData = %1" ).arg(
reinterpret_cast< quint64
>( mData ) ), 4 );
62 mNoDataBitmap =
nullptr;
67 mHasNoDataValue =
false;
68 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
86 const QImage::Format format = imageFormat(
dataType );
100 QgsDebugMsgLevel( QStringLiteral(
"mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg(
static_cast< int>( mDataType ) )
101 .arg(
reinterpret_cast< quint64
>( mData ) ).arg(
reinterpret_cast< quint64
>( mImage ) ), 4 );
105QImage::Format QgsRasterBlock::imageFormat(
Qgis::DataType dataType )
109 return QImage::Format_ARGB32;
113 return QImage::Format_ARGB32_Premultiplied;
115 return QImage::Format_Invalid;
120 if ( format == QImage::Format_ARGB32 )
124 else if ( format == QImage::Format_ARGB32_Premultiplied )
133 QgsDebugMsgLevel( QStringLiteral(
"mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg(
qgsEnumValueToKey( mDataType ) )
134 .arg(
reinterpret_cast< quint64
>( mData ) ).arg(
reinterpret_cast< quint64
>( mImage ) ), 4 );
135 return mWidth == 0 || mHeight == 0 ||
215 *
noDataValue = std::numeric_limits<double>::max() * -1.0;
228 QgsDebugMsgLevel( QStringLiteral(
"newDataType = %1 noDataValue = %2" ).arg( qgsEnumValueToKey< Qgis::DataType >( newDataType ) ).arg( *
noDataValue ), 4 );
234 mHasNoDataValue =
true;
240 mHasNoDataValue =
false;
241 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
250 if ( mHasNoDataValue )
254 QgsDebugError( QStringLiteral(
"Data block not allocated" ) );
259 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
260 if ( mNoDataValue == 0 )
266 const char *nodata = noDataByteArray.data();
267 for (
qgssize i = 0; i < static_cast< qgssize >( mWidth )*mHeight; i++ )
276 if ( !mNoDataBitmap )
278 if ( !createNoDataBitmap() )
284 memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
301 mImage->fill( NO_DATA_COLOR );
308 int top = exceptRect.top();
309 int bottom = exceptRect.bottom();
310 int left = exceptRect.left();
311 int right = exceptRect.right();
312 top = std::min( std::max( top, 0 ), mHeight - 1 );
313 left = std::min( std::max( left, 0 ), mWidth - 1 );
314 bottom = std::max( 0, std::min( bottom, mHeight - 1 ) );
315 right = std::max( 0, std::min( right, mWidth - 1 ) );
321 if ( mHasNoDataValue )
325 QgsDebugError( QStringLiteral(
"Data block not allocated" ) );
330 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
332 char *nodata = noDataByteArray.data();
334 for (
int c = 0;
c < mWidth;
c++ )
340 for (
int r = 0; r < mHeight; r++ )
342 if ( r >= top && r <= bottom )
continue;
347 for (
int r = top; r <= bottom; r++ )
354 const int w = mWidth - right - 1;
362 if ( !mNoDataBitmap )
364 if ( !createNoDataBitmap() )
376 char *nodataRow =
new char[mNoDataBitmapWidth];
378 memset( nodataRow, 0, mNoDataBitmapWidth );
379 for (
int c = 0;
c < mWidth;
c ++ )
381 const int byte =
c / 8;
382 const int bit =
c % 8;
383 const char nodata = 0x80 >> bit;
384 memset( nodataRow +
byte, nodataRow[
byte] | nodata, 1 );
388 for (
int r = 0; r < mHeight; r++ )
390 if ( r >= top && r <= bottom )
continue;
391 const qgssize i =
static_cast< qgssize >( r ) * mNoDataBitmapWidth;
392 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
395 memset( nodataRow, 0, mNoDataBitmapWidth );
396 for (
int c = 0;
c < mWidth;
c ++ )
398 if (
c >= left &&
c <= right )
continue;
399 const int byte =
c / 8;
400 const int bit =
c % 8;
401 const char nodata = 0x80 >> bit;
402 memset( nodataRow +
byte, nodataRow[
byte] | nodata, 1 );
404 for (
int r = top; r <= bottom; r++ )
406 const qgssize i =
static_cast< qgssize >( r ) * mNoDataBitmapWidth;
407 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
422 if ( mImage->width() != mWidth || mImage->height() != mHeight )
424 QgsDebugError( QStringLiteral(
"Image and block size differ" ) );
428 QgsDebugMsgLevel( QStringLiteral(
"Fill image depth = %1" ).arg( mImage->depth() ), 4 );
431 if ( mImage->depth() != 32 )
433 QgsDebugError( QStringLiteral(
"Unsupported image depth" ) );
437 const QRgb nodataRgba = NO_DATA_COLOR;
438 QRgb *nodataRow =
new QRgb[mWidth];
439 const int rgbSize =
sizeof( QRgb );
440 for (
int c = 0;
c < mWidth;
c ++ )
442 nodataRow[
c] = nodataRgba;
446 for (
int r = 0; r < mHeight; r++ )
448 if ( r >= top && r <= bottom )
continue;
450 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( mWidth ) );
453 for (
int r = top; r <= bottom; r++ )
459 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( left - 1 ) );
463 const int w = mWidth - right - 1;
464 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( w ) );
474 return QByteArray::fromRawData(
static_cast<const char *
>( mData ),
typeSize( mDataType ) * mWidth * mHeight );
475 else if ( mImage && mImage->constBits() )
476 return QByteArray::fromRawData(
reinterpret_cast<const char *
>( mImage->constBits() ), mImage->sizeInBytes() );
488 const int len = std::min(
static_cast<int>(
data.size() ),
typeSize( mDataType ) * mWidth * mHeight - offset );
489 ::memcpy(
static_cast<char *
>( mData ) + offset,
data.constData(), len );
491 else if ( mImage && mImage->constBits() )
493 const qsizetype len = std::min(
static_cast< qsizetype
>(
data.size() ), mImage->sizeInBytes() - offset );
494 ::memcpy( mImage->bits() + offset,
data.constData(), len );
501 if ( index >=
static_cast< qgssize >( mWidth )*mHeight )
503 QgsDebugMsgLevel( QStringLiteral(
"Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ), 4 );
508 return reinterpret_cast< char *
>( mData ) + index * mTypeSize;
512 if ( uchar *
data = mImage->bits() )
514 return reinterpret_cast< char *
>(
data + index * 4 );
524 if ( index >=
static_cast< qgssize >( mWidth )*mHeight )
526 QgsDebugMsgLevel( QStringLiteral(
"Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ), 4 );
531 return reinterpret_cast< const char *
>( mData ) + index * mTypeSize;
535 if (
const uchar *
data = mImage->constBits() )
537 return reinterpret_cast< const char *
>(
data + index * 4 );
546 return bits(
static_cast< qgssize >( row ) * mWidth + column );
553 return reinterpret_cast< char *
>( mData );
557 if ( uchar *
data = mImage->bits() )
559 return reinterpret_cast< char *
>(
data );
570 return reinterpret_cast< const char *
>( mData );
574 if (
const uchar *
data = mImage->constBits() )
576 return reinterpret_cast< const char *
>(
data );
586 if ( destDataType == mDataType )
return true;
590 void *
data =
convert( mData, mDataType, destDataType,
static_cast< qgssize >( mWidth ) *
static_cast< qgssize >( mHeight ) );
594 QgsDebugError( QStringLiteral(
"Cannot convert raster block" ) );
599 mDataType = destDataType;
604 const QImage::Format format = imageFormat( destDataType );
605 const QImage
image = mImage->convertToFormat( format );
607 mDataType = destDataType;
622 if ( scale == 1.0 && offset == 0.0 )
return;
625 for (
qgssize i = 0; i < size; ++i )
633 if ( rangeList.isEmpty() )
639 for (
qgssize i = 0; i < size; ++i )
641 const double val =
value( i );
654 return QImage( *mImage );
665 mImage =
new QImage( *
image );
666 mWidth = mImage->width();
667 mHeight = mImage->height();
668 mDataType =
dataType( mImage->format() );
670 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
700 for (
int i = 15; i <= 17; i++ )
702 s.setNum(
value,
'g', i );
703 const double doubleValue { s.toDouble( ) };
708 return QLocale().toString( doubleValue,
'g', i );
714 QgsDebugError( QStringLiteral(
"Cannot correctly parse printed value" ) );
726 for (
int i = 6; i <= 9; i++ )
728 s.setNum(
value,
'g', i );
729 const float floatValue { s.toFloat() };
734 return QLocale().toString( floatValue,
'g', i );
740 QgsDebugError( QStringLiteral(
"Cannot correctly parse printed value" ) );
746 const int destDataTypeSize =
typeSize( destDataType );
747 void *destData =
qgsMalloc( destDataTypeSize * size );
748 for (
qgssize i = 0; i < size; i++ )
762 ba.resize(
static_cast< int >( size ) );
763 char *
data = ba.data();
774 uc =
static_cast< quint8
>(
value );
775 memcpy(
data, &uc, size );
779 const qint8 myint8 =
static_cast< qint8
>(
value );
780 memcpy(
data, &myint8, size );
784 us =
static_cast< quint16
>(
value );
785 memcpy(
data, &us, size );
788 s =
static_cast< qint16
>(
value );
789 memcpy(
data, &s, size );
792 ui =
static_cast< quint32
>(
value );
793 memcpy(
data, &ui, size );
796 i =
static_cast< qint32
>(
value );
797 memcpy(
data, &i, size );
800 f =
static_cast< float >(
value );
801 memcpy(
data, &f, size );
804 d =
static_cast< double >(
value );
805 memcpy(
data, &d, size );
814 QgsDebugError( QStringLiteral(
"Data type is not supported" ) );
819bool QgsRasterBlock::createNoDataBitmap()
821 mNoDataBitmapWidth = mWidth / 8 + 1;
822 mNoDataBitmapSize =
static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
823 QgsDebugMsgLevel( QStringLiteral(
"allocate %1 bytes" ).arg( mNoDataBitmapSize ), 4 );
824 mNoDataBitmap =
reinterpret_cast< char *
>(
qgsMalloc( mNoDataBitmapSize ) );
825 if ( !mNoDataBitmap )
827 QgsDebugError( QStringLiteral(
"Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
830 memset( mNoDataBitmap, 0, mNoDataBitmapSize );
836 return QStringLiteral(
"dataType = %1 width = %2 height = %3" )
837 .arg( qgsEnumValueToKey< Qgis::DataType >( mDataType ) ).arg( mWidth ).arg( mHeight );
847 QgsDebugMsgLevel( QStringLiteral(
"theWidth = %1 height = %2 xRes = %3 yRes = %4" ).arg(
width ).arg(
height ).arg( xRes ).arg( yRes ), 4 );
852 int right =
width - 1;
860 bottom = std::round( ( extent.
yMaximum() - subExtent.
yMinimum() ) / yRes ) - 1;
869 right = std::round( ( subExtent.
xMaximum() - extent.
xMinimum() ) / xRes ) - 1;
871 QRect
subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
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)
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 data type is numeric.
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.
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".
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 data type is color.
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 contains(double value) const
Returns true if this range contains the specified value.
A rectangle specified with double values.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double width() const
Returns the width of the rectangle.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
double height() const
Returns the height of the rectangle.
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)
QList< QgsRasterRange > QgsRasterRangeList