28const QRgb QgsRasterBlock::NO_DATA_COLOR = qRgba( 0, 0, 0, 0 );
31 : mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
36 : mDataType( dataType )
39 , mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
41 ( void )
reset( mDataType, mWidth, mHeight );
46 QgsDebugMsgLevel( QStringLiteral(
"mData = %1" ).arg(
reinterpret_cast< quint64
>( mData ) ), 4 );
61 mNoDataBitmap =
nullptr;
66 mHasNoDataValue =
false;
67 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
85 const QImage::Format format = imageFormat(
dataType );
99 QgsDebugMsgLevel( QStringLiteral(
"mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg(
static_cast< int>( mDataType ) )
100 .arg(
reinterpret_cast< quint64
>( mData ) ).arg(
reinterpret_cast< quint64
>( mImage ) ), 4 );
104QImage::Format QgsRasterBlock::imageFormat(
Qgis::DataType dataType )
108 return QImage::Format_ARGB32;
112 return QImage::Format_ARGB32_Premultiplied;
114 return QImage::Format_Invalid;
119 if ( format == QImage::Format_ARGB32 )
123 else if ( format == QImage::Format_ARGB32_Premultiplied )
132 QgsDebugMsgLevel( QStringLiteral(
"mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg(
qgsEnumValueToKey( mDataType ) )
133 .arg(
reinterpret_cast< quint64
>( mData ) ).arg(
reinterpret_cast< quint64
>( mImage ) ), 4 );
134 return mWidth == 0 || mHeight == 0 ||
214 *
noDataValue = std::numeric_limits<double>::max() * -1.0;
227 QgsDebugMsgLevel( QStringLiteral(
"newDataType = %1 noDataValue = %2" ).arg( qgsEnumValueToKey< Qgis::DataType >( newDataType ) ).arg( *
noDataValue ), 4 );
233 mHasNoDataValue =
true;
239 mHasNoDataValue =
false;
240 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
249 if ( mHasNoDataValue )
253 QgsDebugError( QStringLiteral(
"Data block not allocated" ) );
258 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
259 if ( mNoDataValue == 0 )
265 const char *nodata = noDataByteArray.data();
266 for (
qgssize i = 0; i < static_cast< qgssize >( mWidth )*mHeight; i++ )
275 if ( !mNoDataBitmap )
277 if ( !createNoDataBitmap() )
283 memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
300 mImage->fill( NO_DATA_COLOR );
307 int top = exceptRect.top();
308 int bottom = exceptRect.bottom();
309 int left = exceptRect.left();
310 int right = exceptRect.right();
311 top = std::min( std::max( top, 0 ), mHeight - 1 );
312 left = std::min( std::max( left, 0 ), mWidth - 1 );
313 bottom = std::max( 0, std::min( bottom, mHeight - 1 ) );
314 right = std::max( 0, std::min( right, mWidth - 1 ) );
320 if ( mHasNoDataValue )
324 QgsDebugError( QStringLiteral(
"Data block not allocated" ) );
329 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
331 char *nodata = noDataByteArray.data();
333 for (
int c = 0;
c < mWidth;
c++ )
339 for (
int r = 0; r < mHeight; r++ )
341 if ( r >= top && r <= bottom )
continue;
346 for (
int r = top; r <= bottom; r++ )
353 const int w = mWidth - right - 1;
361 if ( !mNoDataBitmap )
363 if ( !createNoDataBitmap() )
375 char *nodataRow =
new char[mNoDataBitmapWidth];
377 memset( nodataRow, 0, mNoDataBitmapWidth );
378 for (
int c = 0;
c < mWidth;
c ++ )
380 const int byte =
c / 8;
381 const int bit =
c % 8;
382 const char nodata = 0x80 >> bit;
383 memset( nodataRow +
byte, nodataRow[
byte] | nodata, 1 );
387 for (
int r = 0; r < mHeight; r++ )
389 if ( r >= top && r <= bottom )
continue;
390 const qgssize i =
static_cast< qgssize >( r ) * mNoDataBitmapWidth;
391 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
394 memset( nodataRow, 0, mNoDataBitmapWidth );
395 for (
int c = 0;
c < mWidth;
c ++ )
397 if (
c >= left &&
c <= right )
continue;
398 const int byte =
c / 8;
399 const int bit =
c % 8;
400 const char nodata = 0x80 >> bit;
401 memset( nodataRow +
byte, nodataRow[
byte] | nodata, 1 );
403 for (
int r = top; r <= bottom; r++ )
405 const qgssize i =
static_cast< qgssize >( r ) * mNoDataBitmapWidth;
406 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
421 if ( mImage->width() != mWidth || mImage->height() != mHeight )
423 QgsDebugError( QStringLiteral(
"Image and block size differ" ) );
427 QgsDebugMsgLevel( QStringLiteral(
"Fill image depth = %1" ).arg( mImage->depth() ), 4 );
430 if ( mImage->depth() != 32 )
432 QgsDebugError( QStringLiteral(
"Unsupported image depth" ) );
436 const QRgb nodataRgba = NO_DATA_COLOR;
437 QRgb *nodataRow =
new QRgb[mWidth];
438 const int rgbSize =
sizeof( QRgb );
439 for (
int c = 0;
c < mWidth;
c ++ )
441 nodataRow[
c] = nodataRgba;
445 for (
int r = 0; r < mHeight; r++ )
447 if ( r >= top && r <= bottom )
continue;
449 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( mWidth ) );
452 for (
int r = top; r <= bottom; r++ )
458 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( left - 1 ) );
462 const int w = mWidth - right - 1;
463 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( w ) );
473 return QByteArray::fromRawData(
static_cast<const char *
>( mData ),
typeSize( mDataType ) * mWidth * mHeight );
474 else if ( mImage && mImage->constBits() )
475 return QByteArray::fromRawData(
reinterpret_cast<const char *
>( mImage->constBits() ), mImage->sizeInBytes() );
487 const int len = std::min(
static_cast<int>(
data.size() ),
typeSize( mDataType ) * mWidth * mHeight - offset );
488 ::memcpy(
static_cast<char *
>( mData ) + offset,
data.constData(), len );
490 else if ( mImage && mImage->constBits() )
492 const qsizetype len = std::min(
static_cast< qsizetype
>(
data.size() ), mImage->sizeInBytes() - offset );
493 ::memcpy( mImage->bits() + offset,
data.constData(), len );
500 if ( index >=
static_cast< qgssize >( mWidth )*mHeight )
502 QgsDebugMsgLevel( QStringLiteral(
"Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ), 4 );
507 return reinterpret_cast< char *
>( mData ) + index * mTypeSize;
509 if ( mImage && mImage->bits() )
511 return reinterpret_cast< char *
>( mImage->bits() + index * 4 );
519 return bits(
static_cast< qgssize >( row ) * mWidth + column );
526 return reinterpret_cast< char *
>( mData );
528 if ( mImage && mImage->bits() )
530 return reinterpret_cast< char *
>( mImage->bits() );
539 if ( destDataType == mDataType )
return true;
543 void *
data =
convert( mData, mDataType, destDataType,
static_cast< qgssize >( mWidth ) *
static_cast< qgssize >( mHeight ) );
547 QgsDebugError( QStringLiteral(
"Cannot convert raster block" ) );
552 mDataType = destDataType;
557 const QImage::Format format = imageFormat( destDataType );
558 const QImage
image = mImage->convertToFormat( format );
560 mDataType = destDataType;
575 if ( scale == 1.0 && offset == 0.0 )
return;
578 for (
qgssize i = 0; i < size; ++i )
586 if ( rangeList.isEmpty() )
592 for (
qgssize i = 0; i < size; ++i )
594 const double val =
value( i );
607 return QImage( *mImage );
618 mImage =
new QImage( *
image );
619 mWidth = mImage->width();
620 mHeight = mImage->height();
621 mDataType =
dataType( mImage->format() );
623 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
653 for (
int i = 15; i <= 17; i++ )
655 s.setNum(
value,
'g', i );
662 QgsDebugError( QStringLiteral(
"Cannot correctly parse printed value" ) );
674 for (
int i = 6; i <= 9; i++ )
676 s.setNum(
value,
'g', i );
683 QgsDebugError( QStringLiteral(
"Cannot correctly parse printed value" ) );
689 const int destDataTypeSize =
typeSize( destDataType );
690 void *destData =
qgsMalloc( destDataTypeSize * size );
691 for (
qgssize i = 0; i < size; i++ )
705 ba.resize(
static_cast< int >( size ) );
706 char *
data = ba.data();
717 uc =
static_cast< quint8
>(
value );
718 memcpy(
data, &uc, size );
722 const qint8 myint8 =
static_cast< qint8
>(
value );
723 memcpy(
data, &myint8, size );
727 us =
static_cast< quint16
>(
value );
728 memcpy(
data, &us, size );
731 s =
static_cast< qint16
>(
value );
732 memcpy(
data, &s, size );
735 ui =
static_cast< quint32
>(
value );
736 memcpy(
data, &ui, size );
739 i =
static_cast< qint32
>(
value );
740 memcpy(
data, &i, size );
743 f =
static_cast< float >(
value );
744 memcpy(
data, &f, size );
747 d =
static_cast< double >(
value );
748 memcpy(
data, &d, size );
757 QgsDebugError( QStringLiteral(
"Data type is not supported" ) );
762bool QgsRasterBlock::createNoDataBitmap()
764 mNoDataBitmapWidth = mWidth / 8 + 1;
765 mNoDataBitmapSize =
static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
766 QgsDebugMsgLevel( QStringLiteral(
"allocate %1 bytes" ).arg( mNoDataBitmapSize ), 4 );
767 mNoDataBitmap =
reinterpret_cast< char *
>(
qgsMalloc( mNoDataBitmapSize ) );
768 if ( !mNoDataBitmap )
770 QgsDebugError( QStringLiteral(
"Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
773 memset( mNoDataBitmap, 0, mNoDataBitmapSize );
779 return QStringLiteral(
"dataType = %1 width = %2 height = %3" )
780 .arg( qgsEnumValueToKey< Qgis::DataType >( mDataType ) ).arg( mWidth ).arg( mHeight );
790 QgsDebugMsgLevel( QStringLiteral(
"theWidth = %1 height = %2 xRes = %3 yRes = %4" ).arg(
width ).arg(
height ).arg( xRes ).arg( yRes ), 4 );
795 int right =
width - 1;
803 bottom = std::round( ( extent.
yMaximum() - subExtent.
yMinimum() ) / yRes ) - 1;
812 right = std::round( ( subExtent.
xMaximum() - extent.
xMinimum() ) / xRes ) - 1;
814 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.
static QString printValue(double value)
Print double value with all necessary significant digits.
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 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