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();
239 if ( mHasNoDataValue )
243 QgsDebugMsg( QStringLiteral(
"Data block not allocated" ) );
249 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
251 char *nodata = noDataByteArray.data();
252 for (
qgssize i = 0; i < static_cast< qgssize >( mWidth )*mHeight; i++ )
254 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodata, dataTypeSize );
260 if ( !mNoDataBitmap )
262 if ( !createNoDataBitmap() )
268 memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
277 QgsDebugMsg( QStringLiteral(
"Image not allocated" ) );
281 mImage->fill( NO_DATA_COLOR );
288 int top = exceptRect.top();
289 int bottom = exceptRect.bottom();
290 int left = exceptRect.left();
291 int right = exceptRect.right();
292 top = std::min( std::max( top, 0 ), mHeight - 1 );
293 left = std::min( std::max( left, 0 ), mWidth - 1 );
294 bottom = std::max( 0, std::min( bottom, mHeight - 1 ) );
295 right = std::max( 0, std::min( right, mWidth - 1 ) );
300 if ( mHasNoDataValue )
304 QgsDebugMsg( QStringLiteral(
"Data block not allocated" ) );
310 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
312 char *nodata = noDataByteArray.data();
314 for (
int c = 0;
c < mWidth;
c++ )
316 memcpy( nodataRow +
c * dataTypeSize, nodata, dataTypeSize );
320 for (
int r = 0; r < mHeight; r++ )
322 if ( r >= top && r <= bottom )
continue;
324 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( mWidth ) );
327 for (
int r = top; r <= bottom; r++ )
331 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( left ) );
334 int w = mWidth - right - 1;
335 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( w ) );
342 if ( !mNoDataBitmap )
344 if ( !createNoDataBitmap() )
351 char *nodataRow =
new char[mNoDataBitmapWidth];
353 memset( nodataRow, 0, mNoDataBitmapWidth );
354 for (
int c = 0;
c < mWidth;
c ++ )
358 char nodata = 0x80 >> bit;
359 memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
363 for (
int r = 0; r < mHeight; r++ )
365 if ( r >= top && r <= bottom )
continue;
367 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
370 memset( nodataRow, 0, mNoDataBitmapWidth );
371 for (
int c = 0;
c < mWidth;
c ++ )
373 if (
c >= left &&
c <= right )
continue;
376 char nodata = 0x80 >> bit;
377 memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
379 for (
int r = top; r <= bottom; r++ )
382 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
393 QgsDebugMsg( QStringLiteral(
"Image not allocated" ) );
397 if ( mImage->width() != mWidth || mImage->height() != mHeight )
399 QgsDebugMsg( QStringLiteral(
"Image and block size differ" ) );
403 QgsDebugMsgLevel( QStringLiteral(
"Fill image depth = %1" ).arg( mImage->depth() ), 4 );
406 if ( mImage->depth() != 32 )
408 QgsDebugMsg( QStringLiteral(
"Unsupported image depth" ) );
412 QRgb nodataRgba = NO_DATA_COLOR;
413 QRgb *nodataRow =
new QRgb[mWidth];
414 int rgbSize =
sizeof( QRgb );
415 for (
int c = 0;
c < mWidth;
c ++ )
417 nodataRow[
c] = nodataRgba;
421 for (
int r = 0; r < mHeight; r++ )
423 if ( r >= top && r <= bottom )
continue;
425 memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( mWidth ) );
428 for (
int r = top; r <= bottom; r++ )
434 memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( left - 1 ) );
438 int w = mWidth - right - 1;
439 memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( w ) );
449 return QByteArray::fromRawData( static_cast<const char *>( mData ),
typeSize( mDataType ) * mWidth * mHeight );
450 else if ( mImage && mImage->constBits() )
451 return QByteArray::fromRawData( reinterpret_cast<const char *>( mImage->constBits() ), mImage->byteCount() );
463 int len = std::min( data.size(),
typeSize( mDataType ) * mWidth * mHeight - offset );
464 ::memcpy( static_cast<char *>( mData ) + offset, data.constData(), len );
466 else if ( mImage && mImage->constBits() )
468 int len = std::min( data.size(), mImage->byteCount() - offset );
469 ::memcpy( mImage->bits() + offset, data.constData(), len );
476 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
478 QgsDebugMsgLevel( QStringLiteral(
"Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ), 4 );
483 return reinterpret_cast< char *
>( mData ) + index * mTypeSize;
485 if ( mImage && mImage->bits() )
487 return reinterpret_cast< char *
>( mImage->bits() + index * 4 );
495 return bits( static_cast< qgssize >( row ) * mWidth + column );
502 return reinterpret_cast< char *
>( mData );
504 if ( mImage && mImage->bits() )
506 return reinterpret_cast< char *
>( mImage->bits() );
515 if ( destDataType == mDataType )
return true;
519 void *
data =
convert( mData, mDataType, destDataType, static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight ) );
523 QgsDebugMsg( QStringLiteral(
"Cannot convert raster block" ) );
528 mDataType = destDataType;
533 QImage::Format format = imageFormat( destDataType );
534 QImage
image = mImage->convertToFormat( format );
536 mDataType = destDataType;
551 if ( scale == 1.0 && offset == 0.0 )
return;
554 for (
qgssize i = 0; i < size; ++i )
562 if ( rangeList.isEmpty() )
567 qgssize size =
static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight );
568 for (
qgssize i = 0; i < size; ++i )
570 double val =
value( i );
583 return QImage( *mImage );
594 mImage =
new QImage( *image );
595 mWidth = mImage->width();
596 mHeight = mImage->height();
597 mDataType =
dataType( mImage->format() );
599 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
629 for (
int i = 15; i <= 17; i++ )
631 s.setNum( value,
'g', i );
638 QgsDebugMsg( QStringLiteral(
"Cannot correctly parse printed value" ) );
650 for (
int i = 6; i <= 9; i++ )
652 s.setNum( value,
'g', i );
659 QgsDebugMsg( QStringLiteral(
"Cannot correctly parse printed value" ) );
665 int destDataTypeSize =
typeSize( destDataType );
666 void *destData =
qgsMalloc( destDataTypeSize * size );
667 for (
qgssize i = 0; i < size; i++ )
670 writeValue( destData, destDataType, i, value );
681 ba.resize( static_cast< int >( size ) );
682 char *
data = ba.data();
693 uc =
static_cast< quint8
>(
value );
694 memcpy( data, &uc, size );
697 us =
static_cast< quint16
>(
value );
698 memcpy( data, &us, size );
701 s =
static_cast< qint16
>(
value );
702 memcpy( data, &s, size );
705 ui =
static_cast< quint32
>(
value );
706 memcpy( data, &ui, size );
709 i =
static_cast< qint32
>(
value );
710 memcpy( data, &i, size );
713 f =
static_cast< float >(
value );
714 memcpy( data, &f, size );
717 d =
static_cast< double >(
value );
718 memcpy( data, &d, size );
721 QgsDebugMsg( QStringLiteral(
"Data type is not supported" ) );
726 bool QgsRasterBlock::createNoDataBitmap()
728 mNoDataBitmapWidth = mWidth / 8 + 1;
729 mNoDataBitmapSize =
static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
730 QgsDebugMsgLevel( QStringLiteral(
"allocate %1 bytes" ).arg( mNoDataBitmapSize ), 4 );
731 mNoDataBitmap =
reinterpret_cast< char *
>(
qgsMalloc( mNoDataBitmapSize ) );
732 if ( !mNoDataBitmap )
734 QgsDebugMsg( QStringLiteral(
"Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
737 memset( mNoDataBitmap, 0, mNoDataBitmapSize );
743 return QStringLiteral(
"dataType = %1 width = %2 height = %3" )
744 .arg( mDataType ).arg( mWidth ).arg( mHeight );
754 QgsDebugMsgLevel( QStringLiteral(
"theWidth = %1 height = %2 xRes = %3 yRes = %4" ).arg( width ).arg( height ).arg( xRes ).arg( yRes ), 4 );
757 int bottom = height - 1;
759 int right = width - 1;
767 bottom = std::round( ( extent.
yMaximum() - subExtent.
yMinimum() ) / yRes ) - 1;
776 right = std::round( ( subExtent.
xMaximum() - extent.
xMinimum() ) / xRes ) - 1;
778 QRect
subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
779 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.