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( QString(
"mData = %1" ).arg( reinterpret_cast< quint64 >( mData ) ), 4 );
54 QgsDebugMsgLevel( QString(
"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( QString(
"allocate %1 bytes" ).arg( tSize * width * height ), 4 );
75 mData =
qgsMalloc( tSize * width * height );
78 QgsDebugMsg( QString(
"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( QString(
"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( QString(
"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( QString(
"Unknown data type %1" ).arg( dataType ) );
218 QgsDebugMsgLevel( QString(
"newDataType = %1 noDataValue = %2" ).arg( newDataType ).arg( *noDataValue ), 4 );
224 return mHasNoDataValue || mNoDataBitmap;
229 mHasNoDataValue =
true;
235 mHasNoDataValue =
false;
236 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
244 return std::isnan(
value ) ||
250 return value( static_cast< qgssize >( row ) * mWidth + column );
255 int row = std::floor( static_cast< double >( index ) / mWidth );
256 int column = index % mWidth;
257 return color( row, column );
262 if ( !mImage )
return NO_DATA_COLOR;
264 return mImage->pixel( column, row );
269 if ( !mHasNoDataValue && !mNoDataBitmap )
return false;
270 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
272 QgsDebugMsg( QString(
"Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
275 if ( mHasNoDataValue )
278 return isNoDataValue( value );
281 if ( !mNoDataBitmap )
287 int row =
static_cast< int >( index ) / mWidth;
288 int column = index % mWidth;
289 qgssize byte =
static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
290 int bit = column % 8;
291 int mask = 0x80 >> bit;
294 return mNoDataBitmap[byte] & mask;
299 return isNoData( static_cast< qgssize >( row ) * mWidth + column );
309 if ( index >= static_cast< qgssize >( mWidth ) *mHeight )
311 QgsDebugMsg( QString(
"Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
320 return setValue( static_cast< qgssize >( row ) * mWidth + column, value );
325 return setColor( static_cast< qgssize >( row ) * mWidth + column, color );
336 if ( index >= static_cast< qgssize >( mImage->width() ) * mImage->height() )
338 QgsDebugMsg( QString(
"index %1 out of range" ).arg( index ) );
343 QRgb *
bits =
reinterpret_cast< QRgb *
>( mImage->bits() );
350 return setIsNoData( static_cast< qgssize >( row ) * mWidth + column );
355 if ( mHasNoDataValue )
357 return setValue( index, mNoDataValue );
361 if ( !mNoDataBitmap )
363 if ( !createNoDataBitmap() )
369 int row =
static_cast< int >( index ) / mWidth;
370 int column = index % mWidth;
371 qgssize byte =
static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
372 int bit = column % 8;
373 int nodata = 0x80 >> bit;
375 mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
385 if ( mHasNoDataValue )
395 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
397 char *nodata = noDataByteArray.data();
398 for (
qgssize i = 0; i < static_cast< qgssize >( mWidth )*mHeight; i++ )
400 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodata, dataTypeSize );
406 if ( !mNoDataBitmap )
408 if ( !createNoDataBitmap() )
414 memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
427 mImage->fill( NO_DATA_COLOR );
434 int top = exceptRect.top();
435 int bottom = exceptRect.bottom();
436 int left = exceptRect.left();
437 int right = exceptRect.right();
438 top = std::min( std::max( top, 0 ), mHeight - 1 );
439 left = std::min( std::max( left, 0 ), mWidth - 1 );
440 bottom = std::max( 0, std::min( bottom, mHeight - 1 ) );
441 right = std::max( 0, std::min( right, mWidth - 1 ) );
446 if ( mHasNoDataValue )
456 QByteArray noDataByteArray =
valueBytes( mDataType, mNoDataValue );
458 char *nodata = noDataByteArray.data();
460 for (
int c = 0; c < mWidth; c++ )
462 memcpy( nodataRow + c * dataTypeSize, nodata, dataTypeSize );
466 for (
int r = 0; r < mHeight; r++ )
468 if ( r >= top && r <= bottom )
continue;
470 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( mWidth ) );
473 for (
int r = top; r <= bottom; r++ )
477 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( left ) );
480 int w = mWidth - right - 1;
481 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( w ) );
488 if ( !mNoDataBitmap )
490 if ( !createNoDataBitmap() )
497 char *nodataRow =
new char[mNoDataBitmapWidth];
499 memset( nodataRow, 0, mNoDataBitmapWidth );
500 for (
int c = 0; c < mWidth; c ++ )
504 char nodata = 0x80 >> bit;
505 memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
509 for (
int r = 0; r < mHeight; r++ )
511 if ( r >= top && r <= bottom )
continue;
513 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
516 memset( nodataRow, 0, mNoDataBitmapWidth );
517 for (
int c = 0; c < mWidth; c ++ )
519 if ( c >= left && c <= right )
continue;
522 char nodata = 0x80 >> bit;
523 memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
525 for (
int r = top; r <= bottom; r++ )
528 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
543 if ( mImage->width() != mWidth || mImage->height() != mHeight )
549 QgsDebugMsgLevel( QString(
"Fill image depth = %1" ).arg( mImage->depth() ), 4 );
552 if ( mImage->depth() != 32 )
558 QRgb nodataRgba = NO_DATA_COLOR;
559 QRgb *nodataRow =
new QRgb[mWidth];
560 int rgbSize =
sizeof( QRgb );
561 for (
int c = 0; c < mWidth; c ++ )
563 nodataRow[c] = nodataRgba;
567 for (
int r = 0; r < mHeight; r++ )
569 if ( r >= top && r <= bottom )
continue;
571 memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( mWidth ) );
574 for (
int r = top; r <= bottom; r++ )
580 memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( left - 1 ) );
584 int w = mWidth - right - 1;
585 memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( w ) );
594 setIsData( static_cast< qgssize >( row )*mWidth + column );
599 if ( mHasNoDataValue )
605 if ( !mNoDataBitmap )
611 int row =
static_cast< int >( index ) / mWidth;
612 int column = index % mWidth;
613 qgssize byte =
static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
614 int bit = column % 8;
615 int nodata = 0x80 >> bit;
616 mNoDataBitmap[byte] = mNoDataBitmap[byte] & ~nodata;
622 return QByteArray::fromRawData( static_cast<const char *>( mData ),
typeSize( mDataType ) * mWidth * mHeight );
623 else if ( mImage && mImage->constBits() )
624 return QByteArray::fromRawData( reinterpret_cast<const char *>( mImage->constBits() ), mImage->byteCount() );
636 int len = std::min( data.size(),
typeSize( mDataType ) * mWidth * mHeight - offset );
637 ::memcpy( static_cast<char *>( mData ) + offset, data.constData(), len );
639 else if ( mImage && mImage->constBits() )
641 int len = std::min( data.size(), mImage->byteCount() - offset );
642 ::memcpy( mImage->bits() + offset, data.constData(), len );
649 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
651 QgsDebugMsgLevel( QString(
"Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ), 4 );
656 return reinterpret_cast< char *
>( mData ) + index * mTypeSize;
658 if ( mImage && mImage->bits() )
660 return reinterpret_cast< char *
>( mImage->bits() + index * 4 );
668 return bits( static_cast< qgssize >( row ) * mWidth + column );
675 return reinterpret_cast< char *
>( mData );
677 if ( mImage && mImage->bits() )
679 return reinterpret_cast< char *
>( mImage->bits() );
688 if ( destDataType == mDataType )
return true;
692 void *
data =
convert( mData, mDataType, destDataType, static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight ) );
701 mDataType = destDataType;
706 QImage::Format format = imageFormat( destDataType );
707 QImage
image = mImage->convertToFormat( format );
709 mDataType = destDataType;
724 if ( scale == 1.0 && offset == 0.0 )
return;
727 for (
qgssize i = 0; i < size; ++i )
735 if ( rangeList.isEmpty() )
740 qgssize size =
static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight );
741 for (
qgssize i = 0; i < size; ++i )
743 double val =
value( i );
756 return QImage( *mImage );
767 mImage =
new QImage( *image );
768 mWidth = mImage->width();
769 mHeight = mImage->height();
770 mDataType =
dataType( mImage->format() );
772 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
802 for (
int i = 15; i <= 17; i++ )
804 s.setNum( value,
'g', i );
811 QgsDebugMsg(
"Cannot correctly parse printed value" );
823 for (
int i = 6; i <= 9; i++ )
825 s.setNum( value,
'g', i );
832 QgsDebugMsg(
"Cannot correctly parse printed value" );
838 int destDataTypeSize =
typeSize( destDataType );
839 void *destData =
qgsMalloc( destDataTypeSize * size );
840 for (
qgssize i = 0; i < size; i++ )
843 writeValue( destData, destDataType, i, value );
854 ba.resize( static_cast< int >( size ) );
855 char *
data = ba.data();
866 uc =
static_cast< quint8
>(
value );
867 memcpy( data, &uc, size );
870 us =
static_cast< quint16
>(
value );
871 memcpy( data, &us, size );
874 s =
static_cast< qint16
>(
value );
875 memcpy( data, &s, size );
878 ui =
static_cast< quint32
>(
value );
879 memcpy( data, &ui, size );
882 i =
static_cast< qint32
>(
value );
883 memcpy( data, &i, size );
886 f =
static_cast< float >(
value );
887 memcpy( data, &f, size );
890 d =
static_cast< double >(
value );
891 memcpy( data, &d, size );
899 bool QgsRasterBlock::createNoDataBitmap()
901 mNoDataBitmapWidth = mWidth / 8 + 1;
902 mNoDataBitmapSize =
static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
903 QgsDebugMsgLevel( QString(
"allocate %1 bytes" ).arg( mNoDataBitmapSize ), 4 );
904 mNoDataBitmap =
reinterpret_cast< char *
>(
qgsMalloc( mNoDataBitmapSize ) );
905 if ( !mNoDataBitmap )
907 QgsDebugMsg( QString(
"Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
910 memset( mNoDataBitmap, 0, mNoDataBitmapSize );
916 return QStringLiteral(
"dataType = %1 width = %2 height = %3" )
917 .arg( mDataType ).arg( mWidth ).arg( mHeight );
927 QgsDebugMsgLevel( QString(
"theWidth = %1 height = %2 xRes = %3 yRes = %4" ).arg( width ).arg( height ).arg( xRes ).arg( yRes ), 4 );
930 int bottom = height - 1;
932 int right = width - 1;
940 bottom = std::round( ( extent.
yMaximum() - subExtent.
yMinimum() ) / yRes ) - 1;
949 right = std::round( ( subExtent.
xMaximum() - extent.
xMinimum() ) / xRes ) - 1;
951 QRect
subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
952 QgsDebugMsgLevel( QString(
"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)
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 bool contains(double value, const QgsRasterRangeList &rangeList)
Test if value is within the list of ranges.
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.
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)
bool isNoData(int row, int column)
Check if value at position is no data.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
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)
bool setColor(int row, int column, QRgb color)
Set color on position.
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)
set 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...
QRgb color(int row, int column) const
Read a single color.
bool reset(Qgis::DataType dataType, int width, int height)
Reset block.
void setIsData(int row, int column)
Remove no data flag on pixel.
char * bits()
Get pointer to 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)
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)
Get byte array representing a value.
QByteArray data() const
Get 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
Get image if 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).
bool hasNoData() const
Returns true if the block may contain no data.
void setData(const QByteArray &data, int offset=0)
Rewrite raw pixel data.
double noDataValue() const
Return 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.