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 ||
211 *
noDataValue = std::numeric_limits<double>::max() * -1.0;
215 QgsDebugMsg( QStringLiteral(
"Unknown data type %1" ).arg(
static_cast< int >(
dataType ) ) );
218 QgsDebugMsgLevel( QStringLiteral(
"newDataType = %1 noDataValue = %2" ).arg( qgsEnumValueToKey< Qgis::DataType >( newDataType ) ).arg( *
noDataValue ), 4 );
224 mHasNoDataValue =
true;
230 mHasNoDataValue =
false;
231 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
240 if ( mHasNoDataValue )
244 QgsDebugMsg( QStringLiteral(
"Data block not allocated" ) );
249 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
250 if ( mNoDataValue == 0 )
256 const char *nodata = noDataByteArray.data();
257 for (
qgssize i = 0; i < static_cast< qgssize >( mWidth )*mHeight; i++ )
266 if ( !mNoDataBitmap )
268 if ( !createNoDataBitmap() )
274 memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
287 QgsDebugMsg( QStringLiteral(
"Image not allocated" ) );
291 mImage->fill( NO_DATA_COLOR );
298 int top = exceptRect.top();
299 int bottom = exceptRect.bottom();
300 int left = exceptRect.left();
301 int right = exceptRect.right();
302 top = std::min( std::max( top, 0 ), mHeight - 1 );
303 left = std::min( std::max( left, 0 ), mWidth - 1 );
304 bottom = std::max( 0, std::min( bottom, mHeight - 1 ) );
305 right = std::max( 0, std::min( right, mWidth - 1 ) );
311 if ( mHasNoDataValue )
315 QgsDebugMsg( QStringLiteral(
"Data block not allocated" ) );
320 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
322 char *nodata = noDataByteArray.data();
324 for (
int c = 0;
c < mWidth;
c++ )
330 for (
int r = 0; r < mHeight; r++ )
332 if ( r >= top && r <= bottom )
continue;
337 for (
int r = top; r <= bottom; r++ )
344 const int w = mWidth - right - 1;
352 if ( !mNoDataBitmap )
354 if ( !createNoDataBitmap() )
366 char *nodataRow =
new char[mNoDataBitmapWidth];
368 memset( nodataRow, 0, mNoDataBitmapWidth );
369 for (
int c = 0;
c < mWidth;
c ++ )
371 const int byte =
c / 8;
372 const int bit =
c % 8;
373 const char nodata = 0x80 >> bit;
374 memset( nodataRow +
byte, nodataRow[
byte] | nodata, 1 );
378 for (
int r = 0; r < mHeight; r++ )
380 if ( r >= top && r <= bottom )
continue;
381 const qgssize i =
static_cast< qgssize >( r ) * mNoDataBitmapWidth;
382 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
385 memset( nodataRow, 0, mNoDataBitmapWidth );
386 for (
int c = 0;
c < mWidth;
c ++ )
388 if (
c >= left &&
c <= right )
continue;
389 const int byte =
c / 8;
390 const int bit =
c % 8;
391 const char nodata = 0x80 >> bit;
392 memset( nodataRow +
byte, nodataRow[
byte] | nodata, 1 );
394 for (
int r = top; r <= bottom; r++ )
396 const qgssize i =
static_cast< qgssize >( r ) * mNoDataBitmapWidth;
397 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
408 QgsDebugMsg( QStringLiteral(
"Image not allocated" ) );
412 if ( mImage->width() != mWidth || mImage->height() != mHeight )
414 QgsDebugMsg( QStringLiteral(
"Image and block size differ" ) );
418 QgsDebugMsgLevel( QStringLiteral(
"Fill image depth = %1" ).arg( mImage->depth() ), 4 );
421 if ( mImage->depth() != 32 )
423 QgsDebugMsg( QStringLiteral(
"Unsupported image depth" ) );
427 const QRgb nodataRgba = NO_DATA_COLOR;
428 QRgb *nodataRow =
new QRgb[mWidth];
429 const int rgbSize =
sizeof( QRgb );
430 for (
int c = 0;
c < mWidth;
c ++ )
432 nodataRow[
c] = nodataRgba;
436 for (
int r = 0; r < mHeight; r++ )
438 if ( r >= top && r <= bottom )
continue;
440 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( mWidth ) );
443 for (
int r = top; r <= bottom; r++ )
449 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( left - 1 ) );
453 const int w = mWidth - right - 1;
454 memcpy(
reinterpret_cast< void *
>( mImage->bits() + rgbSize * i ), nodataRow, rgbSize *
static_cast< qgssize >( w ) );
464 return QByteArray::fromRawData(
static_cast<const char *
>( mData ),
typeSize( mDataType ) * mWidth * mHeight );
465 else if ( mImage && mImage->constBits() )
466 return QByteArray::fromRawData(
reinterpret_cast<const char *
>( mImage->constBits() ), mImage->sizeInBytes() );
478 const int len = std::min(
static_cast<int>(
data.size() ),
typeSize( mDataType ) * mWidth * mHeight - offset );
479 ::memcpy(
static_cast<char *
>( mData ) + offset,
data.constData(), len );
481 else if ( mImage && mImage->constBits() )
483 const qsizetype len = std::min(
static_cast< qsizetype
>(
data.size() ), mImage->sizeInBytes() - offset );
484 ::memcpy( mImage->bits() + offset,
data.constData(), len );
491 if ( index >=
static_cast< qgssize >( mWidth )*mHeight )
493 QgsDebugMsgLevel( QStringLiteral(
"Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ), 4 );
498 return reinterpret_cast< char *
>( mData ) + index * mTypeSize;
500 if ( mImage && mImage->bits() )
502 return reinterpret_cast< char *
>( mImage->bits() + index * 4 );
510 return bits(
static_cast< qgssize >( row ) * mWidth + column );
517 return reinterpret_cast< char *
>( mData );
519 if ( mImage && mImage->bits() )
521 return reinterpret_cast< char *
>( mImage->bits() );
530 if ( destDataType == mDataType )
return true;
534 void *
data =
convert( mData, mDataType, destDataType,
static_cast< qgssize >( mWidth ) *
static_cast< qgssize >( mHeight ) );
538 QgsDebugMsg( QStringLiteral(
"Cannot convert raster block" ) );
543 mDataType = destDataType;
548 const QImage::Format format = imageFormat( destDataType );
549 const QImage
image = mImage->convertToFormat( format );
551 mDataType = destDataType;
566 if ( scale == 1.0 && offset == 0.0 )
return;
569 for (
qgssize i = 0; i < size; ++i )
577 if ( rangeList.isEmpty() )
583 for (
qgssize i = 0; i < size; ++i )
585 const double val =
value( i );
598 return QImage( *mImage );
609 mImage =
new QImage( *
image );
610 mWidth = mImage->width();
611 mHeight = mImage->height();
612 mDataType =
dataType( mImage->format() );
614 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
644 for (
int i = 15; i <= 17; i++ )
646 s.setNum(
value,
'g', i );
653 QgsDebugMsg( QStringLiteral(
"Cannot correctly parse printed value" ) );
665 for (
int i = 6; i <= 9; i++ )
667 s.setNum(
value,
'g', i );
674 QgsDebugMsg( QStringLiteral(
"Cannot correctly parse printed value" ) );
680 const int destDataTypeSize =
typeSize( destDataType );
681 void *destData =
qgsMalloc( destDataTypeSize * size );
682 for (
qgssize i = 0; i < size; i++ )
696 ba.resize(
static_cast< int >( size ) );
697 char *
data = ba.data();
708 uc =
static_cast< quint8
>(
value );
709 memcpy(
data, &uc, size );
712 us =
static_cast< quint16
>(
value );
713 memcpy(
data, &us, size );
716 s =
static_cast< qint16
>(
value );
717 memcpy(
data, &s, size );
720 ui =
static_cast< quint32
>(
value );
721 memcpy(
data, &ui, size );
724 i =
static_cast< qint32
>(
value );
725 memcpy(
data, &i, size );
728 f =
static_cast< float >(
value );
729 memcpy(
data, &f, size );
732 d =
static_cast< double >(
value );
733 memcpy(
data, &d, size );
736 QgsDebugMsg( QStringLiteral(
"Data type is not supported" ) );
741bool QgsRasterBlock::createNoDataBitmap()
743 mNoDataBitmapWidth = mWidth / 8 + 1;
744 mNoDataBitmapSize =
static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
745 QgsDebugMsgLevel( QStringLiteral(
"allocate %1 bytes" ).arg( mNoDataBitmapSize ), 4 );
746 mNoDataBitmap =
reinterpret_cast< char *
>(
qgsMalloc( mNoDataBitmapSize ) );
747 if ( !mNoDataBitmap )
749 QgsDebugMsg( QStringLiteral(
"Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
752 memset( mNoDataBitmap, 0, mNoDataBitmapSize );
758 return QStringLiteral(
"dataType = %1 width = %2 height = %3" )
759 .arg( qgsEnumValueToKey< Qgis::DataType >( mDataType ) ).arg( mWidth ).arg( mHeight );
769 QgsDebugMsgLevel( QStringLiteral(
"theWidth = %1 height = %2 xRes = %3 yRes = %4" ).arg(
width ).arg(
height ).arg( xRes ).arg( yRes ), 4 );
774 int right =
width - 1;
782 bottom = std::round( ( extent.
yMaximum() - subExtent.
yMinimum() ) / yRes ) - 1;
791 right = std::round( ( subExtent.
xMaximum() - extent.
xMinimum() ) / xRes ) - 1;
793 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.
@ 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)
QList< QgsRasterRange > QgsRasterRangeList