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();
78 QgsDebugMsg( QStringLiteral(
"Couldn't allocate data memory of %1 bytes" ).arg( tSize *
width *
height ) );
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;
224 QgsDebugMsg( QStringLiteral(
"Unknown data type %1" ).arg(
static_cast< int >(
dataType ) ) );
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 QgsDebugMsg( 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 );
296 QgsDebugMsg( QStringLiteral(
"Image not allocated" ) );
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 QgsDebugMsg( 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 );
417 QgsDebugMsg( QStringLiteral(
"Image not allocated" ) );
421 if ( mImage->width() != mWidth || mImage->height() != mHeight )
423 QgsDebugMsg( QStringLiteral(
"Image and block size differ" ) );
427 QgsDebugMsgLevel( QStringLiteral(
"Fill image depth = %1" ).arg( mImage->depth() ), 4 );
430 if ( mImage->depth() != 32 )
432 QgsDebugMsg( 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 QgsDebugMsg( 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 QgsDebugMsg( QStringLiteral(
"Cannot correctly parse printed value" ) );
674 for (
int i = 6; i <= 9; i++ )
676 s.setNum(
value,
'g', i );
683 QgsDebugMsg( 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 QgsDebugMsg( 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 QgsDebugMsg( 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.
static bool typeIsNumeric(Qgis::DataType type)
Returns true if data type is numeric.
void setNoDataValue(double noDataValue) SIP_HOLDGIL
Sets cell value that will be considered as "no data".
bool convert(Qgis::DataType destDataType)
Convert data to different type.
bool setIsNoData()
Set the whole block to no data.
void resetNoDataValue() SIP_HOLDGIL
Reset no data value: if there was a no data value previously set, it will be discarded.
int width() const SIP_HOLDGIL
Returns the width (number of columns) of the raster block.
static int typeSize(Qgis::DataType dataType) SIP_HOLDGIL
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.
Qgis::DataType dataType() const SIP_HOLDGIL
Returns data type.
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)
double noDataValue() const SIP_HOLDGIL
Returns no data value.
char * bits()
Returns a pointer to block data.
double value(int row, int column) const SIP_HOLDGIL
Read a single value if type of block is numeric.
int dataTypeSize() const SIP_HOLDGIL
Data type size in bytes.
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.
virtual ~QgsRasterBlock()
static void writeValue(void *data, Qgis::DataType type, qgssize index, double value)
bool isNoData(int row, int column) const SIP_HOLDGIL
Checks if value at position is no data.
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.
bool setValue(int row, int column, double value) SIP_HOLDGIL
Set value on position.
int height() const SIP_HOLDGIL
Returns the height (number of rows) of the raster block.
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 yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
double width() const SIP_HOLDGIL
Returns the width 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)
QList< QgsRasterRange > QgsRasterRangeList