28 const 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 );
54 QgsDebugMsgLevel( QStringLiteral(
"theWidth= %1 height = %2 dataType = %3" ).arg( width ).arg( height ).arg( dataType ), 4 );
61 mNoDataBitmap =
nullptr;
66 mHasNoDataValue =
false;
67 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
74 QgsDebugMsgLevel( QStringLiteral(
"allocate %1 bytes" ).arg( tSize * width * height ), 4 );
75 mData =
qgsMalloc( tSize * width * height );
78 QgsDebugMsg( QStringLiteral(
"Couldn't allocate data memory of %1 bytes" ).arg( tSize * width * height ) );
85 QImage::Format format = imageFormat( dataType );
86 mImage =
new QImage( width, height, format );
99 QgsDebugMsgLevel( QStringLiteral(
"mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg( mDataType )
100 .arg( reinterpret_cast< quint64 >( mData ) ).arg( reinterpret_cast< quint64 >( mImage ) ), 4 );
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( mDataType )
133 .arg( reinterpret_cast< quint64 >( mData ) ).arg( reinterpret_cast< quint64 >( mImage ) ), 4 );
134 return mWidth == 0 || mHeight == 0 ||
196 *noDataValue = -32768.0;
200 *noDataValue = -2147483648.0;
204 *noDataValue = -2147483648.0;
211 *noDataValue = std::numeric_limits<double>::max() * -1.0;
215 QgsDebugMsg( QStringLiteral(
"Unknown data type %1" ).arg( dataType ) );
218 QgsDebugMsgLevel( QStringLiteral(
"newDataType = %1 noDataValue = %2" ).arg( 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 )
252 memset( mData, 0, dataTypeSize * mWidth * mHeight );
256 const char *nodata = noDataByteArray.data();
257 for (
qgssize i = 0; i < static_cast< qgssize >( mWidth )*mHeight; i++ )
259 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodata, dataTypeSize );
266 if ( !mNoDataBitmap )
268 if ( !createNoDataBitmap() )
274 memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
277 memset( mData, 0, dataTypeSize * mWidth * mHeight );
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++ )
326 memcpy( nodataRow +
c * dataTypeSize, nodata, dataTypeSize );
330 for (
int r = 0; r < mHeight; r++ )
332 if ( r >= top && r <= bottom )
continue;
334 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( mWidth ) );
337 for (
int r = top; r <= bottom; r++ )
341 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( left ) );
344 int w = mWidth - right - 1;
345 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( w ) );
352 if ( !mNoDataBitmap )
354 if ( !createNoDataBitmap() )
363 memset( mData, 0, dataTypeSize * mWidth * mHeight );
366 char *nodataRow =
new char[mNoDataBitmapWidth];
368 memset( nodataRow, 0, mNoDataBitmapWidth );
369 for (
int c = 0;
c < mWidth;
c ++ )
373 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;
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;
391 char nodata = 0x80 >> bit;
392 memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
394 for (
int r = top; r <= bottom; r++ )
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 QRgb nodataRgba = NO_DATA_COLOR;
428 QRgb *nodataRow =
new QRgb[mWidth];
429 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 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 #
if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
467 return QByteArray::fromRawData( reinterpret_cast<const char *>( mImage->constBits() ), mImage->byteCount() );
469 return QByteArray::fromRawData( reinterpret_cast<const char *>( mImage->constBits() ), mImage->sizeInBytes() );
482 int len = std::min( data.size(),
typeSize( mDataType ) * mWidth * mHeight - offset );
483 ::memcpy( static_cast<char *>( mData ) + offset, data.constData(), len );
485 else if ( mImage && mImage->constBits() )
487 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) 488 int len = std::min( data.size(), mImage->byteCount() - offset );
490 qsizetype len = std::min( static_cast< qsizetype >( data.size() ), mImage->sizeInBytes() - offset );
492 ::memcpy( mImage->bits() + offset, data.constData(), len );
499 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
501 QgsDebugMsgLevel( QStringLiteral(
"Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ), 4 );
506 return reinterpret_cast< char *
>( mData ) + index * mTypeSize;
508 if ( mImage && mImage->bits() )
510 return reinterpret_cast< char *
>( mImage->bits() + index * 4 );
518 return bits( static_cast< qgssize >( row ) * mWidth + column );
525 return reinterpret_cast< char *
>( mData );
527 if ( mImage && mImage->bits() )
529 return reinterpret_cast< char *
>( mImage->bits() );
538 if ( destDataType == mDataType )
return true;
542 void *
data =
convert( mData, mDataType, destDataType, static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight ) );
546 QgsDebugMsg( QStringLiteral(
"Cannot convert raster block" ) );
551 mDataType = destDataType;
556 QImage::Format format = imageFormat( destDataType );
557 QImage
image = mImage->convertToFormat( format );
559 mDataType = destDataType;
574 if ( scale == 1.0 && offset == 0.0 )
return;
577 for (
qgssize i = 0; i < size; ++i )
585 if ( rangeList.isEmpty() )
590 qgssize size =
static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight );
591 for (
qgssize i = 0; i < size; ++i )
593 double val =
value( i );
606 return QImage( *mImage );
617 mImage =
new QImage( *image );
618 mWidth = mImage->width();
619 mHeight = mImage->height();
620 mDataType =
dataType( mImage->format() );
622 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
652 for (
int i = 15; i <= 17; i++ )
654 s.setNum( value,
'g', i );
661 QgsDebugMsg( QStringLiteral(
"Cannot correctly parse printed value" ) );
673 for (
int i = 6; i <= 9; i++ )
675 s.setNum( value,
'g', i );
682 QgsDebugMsg( QStringLiteral(
"Cannot correctly parse printed value" ) );
688 int destDataTypeSize =
typeSize( destDataType );
689 void *destData =
qgsMalloc( destDataTypeSize * size );
690 for (
qgssize i = 0; i < size; i++ )
693 writeValue( destData, destDataType, i, value );
704 ba.resize( static_cast< int >( size ) );
705 char *
data = ba.data();
716 uc =
static_cast< quint8
>(
value );
717 memcpy( data, &uc, size );
720 us =
static_cast< quint16
>(
value );
721 memcpy( data, &us, size );
724 s =
static_cast< qint16
>(
value );
725 memcpy( data, &s, size );
728 ui =
static_cast< quint32
>(
value );
729 memcpy( data, &ui, size );
732 i =
static_cast< qint32
>(
value );
733 memcpy( data, &i, size );
736 f =
static_cast< float >(
value );
737 memcpy( data, &f, size );
740 d =
static_cast< double >(
value );
741 memcpy( data, &d, size );
744 QgsDebugMsg( QStringLiteral(
"Data type is not supported" ) );
749 bool QgsRasterBlock::createNoDataBitmap()
751 mNoDataBitmapWidth = mWidth / 8 + 1;
752 mNoDataBitmapSize =
static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
753 QgsDebugMsgLevel( QStringLiteral(
"allocate %1 bytes" ).arg( mNoDataBitmapSize ), 4 );
754 mNoDataBitmap =
reinterpret_cast< char *
>(
qgsMalloc( mNoDataBitmapSize ) );
755 if ( !mNoDataBitmap )
757 QgsDebugMsg( QStringLiteral(
"Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
760 memset( mNoDataBitmap, 0, mNoDataBitmapSize );
766 return QStringLiteral(
"dataType = %1 width = %2 height = %3" )
767 .arg( mDataType ).arg( mWidth ).arg( mHeight );
777 QgsDebugMsgLevel( QStringLiteral(
"theWidth = %1 height = %2 xRes = %3 yRes = %4" ).arg( width ).arg( height ).arg( xRes ).arg( yRes ), 4 );
780 int bottom = height - 1;
782 int right = width - 1;
790 bottom = std::round( ( extent.
yMaximum() - subExtent.
yMinimum() ) / yRes ) - 1;
799 right = std::round( ( subExtent.
xMaximum() - extent.
xMinimum() ) / xRes ) - 1;
801 QRect
subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
802 QgsDebugMsgLevel( QStringLiteral(
"subRect: %1 %2 %3 %4" ).arg( subRect.x() ).arg( subRect.y() ).arg( subRect.width() ).arg( subRect.height() ), 4 );
void setNoDataValue(double noDataValue)
Sets cell value that will be considered as "no data".
A rectangle specified with double values.
Thirty two bit signed integer (qint32)
bool contains(double value) const
Returns true if this range contains the specified value.
static QString printValue(double value)
Print double value with all necessary significant digits.
void * qgsMalloc(size_t size)
Allocates size bytes and returns a pointer to the allocated memory.
bool setIsNoData()
Set the whole block to no data.
static double readValue(void *data, Qgis::DataType type, qgssize index)
Qgis::DataType dataType() const
Returns data type.
bool qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference)
static Qgis::DataType typeWithNoDataValue(Qgis::DataType dataType, double *noDataValue)
For given data type returns wider type and sets no data value.
static bool typeIsColor(Qgis::DataType type)
Returns true if data type is color.
void applyNoDataValues(const QgsRasterRangeList &rangeList)
bool setValue(int row, int column, double value)
Set value on position.
bool setIsNoDataExcept(QRect exceptRect)
Set the whole block to no data except specified rectangle.
int height() const
Returns the height (number of rows) of the raster block.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
static bool typeIsNumeric(Qgis::DataType type)
Returns true if data type is numeric.
Thirty two bit unsigned integer (quint32)
DataType
Raster data types.
Thirty two bit floating point (float)
Sixteen bit signed integer (qint16)
static QRect subRect(const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent)
For extent and width, height find rectangle covered by subextent.
Sixty four bit floating point (double)
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
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
virtual ~QgsRasterBlock()
bool convert(Qgis::DataType destDataType)
Convert data to different type.
bool setImage(const QImage *image)
Sets the block data via an image.
#define QgsDebugMsgLevel(str, level)
double width() const
Returns the width of the rectangle.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
bool reset(Qgis::DataType dataType, int width, int height)
Reset block.
char * bits()
Returns a pointer to block data.
Unknown or unspecified type.
static int typeSize(int dataType)
bool isEmpty() const
Returns true if block is empty, i.e.
Sixteen bit unsigned integer (quint16)
bool isNoData(int row, int column) const
Checks if value at position is no data.
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...
static QByteArray valueBytes(Qgis::DataType dataType, double value)
Gets byte array representing a value.
QByteArray data() const
Gets access to raw data.
int width() const
Returns the width (number of columns) of the raster block.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
QImage image() const
Returns an image containing the block data, if the block's data type is color.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
void resetNoDataValue()
Reset no data value: if there was a no data value previously set, it will be discarded.
static void writeValue(void *data, Qgis::DataType type, qgssize index, double value)
QList< QgsRasterRange > QgsRasterRangeList
void applyScaleOffset(double scale, double offset)
Apply band scale and offset to raster block values.
double value(int row, int column) const
Read a single value if type of block is numeric.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
void setData(const QByteArray &data, int offset=0)
Rewrite raw pixel data.
double noDataValue() const
Returns no data value.
void qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
Eight bit unsigned integer (quint8)
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
double height() const
Returns the height of the rectangle.