QgsRasterBlock* QgsSingleBandColorDataRenderer::block( int bandNo, QgsRectangle const & extent, int width, int height, QgsRasterBlockFeedback* feedback ) { Q_UNUSED( bandNo ); QgsRasterBlock *outputBlock = new QgsRasterBlock(); if ( !mInput ) { return outputBlock; } QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height, feedback ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( "No raster data!" ); delete inputBlock; return outputBlock; } bool hasTransparency = usesTransparency(); if ( !hasTransparency ) { // Nothing to do, just retype if necessary inputBlock->convert( Qgis::ARGB32_Premultiplied ); delete outputBlock; return inputBlock; } if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) ) { delete inputBlock; return outputBlock; } // make sure input is also premultiplied! inputBlock->convert( Qgis::ARGB32_Premultiplied ); QRgb* inputBits = ( QRgb* )inputBlock->bits(); QRgb* outputBits = ( QRgb* )outputBlock->bits(); for ( qgssize i = 0; i < ( qgssize )width*height; i++ ) { QRgb c = inputBits[i]; outputBits[i] = qRgba( mOpacity * qRed( c ), mOpacity * qGreen( c ), mOpacity * qBlue( c ), mOpacity * qAlpha( c ) ); } delete inputBlock; return outputBlock; }
QgsRasterBlock* QgsSingleBandColorDataRenderer::block( int bandNo, QgsRectangle const & extent, int width, int height ) { Q_UNUSED( bandNo ); QgsRasterBlock *outputBlock = new QgsRasterBlock(); if ( !mInput ) { return outputBlock; } QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( "No raster data!" ); delete inputBlock; return outputBlock; } bool hasTransparency = usesTransparency(); if ( !hasTransparency ) { // Nothing to do, just retype if necessary inputBlock->convert( QgsRasterBlock::ARGB32_Premultiplied ); delete outputBlock; return inputBlock; } if ( !outputBlock->reset( QgsRasterBlock::ARGB32_Premultiplied, width, height ) ) { delete inputBlock; return outputBlock; } for ( size_t i = 0; i < ( size_t )width*height; i++ ) { QRgb pixelColor; double alpha = 255.0; QRgb c = inputBlock->color( i ); alpha = qAlpha( c ); pixelColor = qRgba( mOpacity * qRed( c ), mOpacity * qGreen( c ), mOpacity * qBlue( c ), mOpacity * alpha ); outputBlock->setColor( i, pixelColor ); } delete inputBlock; return outputBlock; }
QgsRasterBlock* QgsSingleBandPseudoColorRenderer::block( int bandNo, QgsRectangle const & extent, int width, int height, QgsRasterBlockFeedback* feedback ) { Q_UNUSED( bandNo ); QgsRasterBlock *outputBlock = new QgsRasterBlock(); if ( !mInput || !mShader ) { return outputBlock; } QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height, feedback ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( "No raster data!" ); delete inputBlock; return outputBlock; } //rendering is faster without considering user-defined transparency bool hasTransparency = usesTransparency(); QgsRasterBlock *alphaBlock = nullptr; if ( mAlphaBand > 0 && mAlphaBand != mBand ) { alphaBlock = mInput->block( mAlphaBand, extent, width, height, feedback ); if ( !alphaBlock || alphaBlock->isEmpty() ) { delete inputBlock; delete alphaBlock; return outputBlock; } } else if ( mAlphaBand == mBand ) { alphaBlock = inputBlock; } if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) ) { delete inputBlock; delete alphaBlock; return outputBlock; } QRgb myDefaultColor = NODATA_COLOR; for ( qgssize i = 0; i < ( qgssize )width*height; i++ ) { if ( inputBlock->isNoData( i ) ) { outputBlock->setColor( i, myDefaultColor ); continue; } double val = inputBlock->value( i ); int red, green, blue, alpha; if ( !mShader->shade( val, &red, &green, &blue, &alpha ) ) { outputBlock->setColor( i, myDefaultColor ); continue; } if ( alpha < 255 ) { // Working with premultiplied colors, so multiply values by alpha red *= ( alpha / 255.0 ); blue *= ( alpha / 255.0 ); green *= ( alpha / 255.0 ); } if ( !hasTransparency ) { outputBlock->setColor( i, qRgba( red, green, blue, alpha ) ); } else { //opacity double currentOpacity = mOpacity; if ( mRasterTransparency ) { currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentOpacity *= alphaBlock->value( i ) / 255.0; } outputBlock->setColor( i, qRgba( currentOpacity * red, currentOpacity * green, currentOpacity * blue, currentOpacity * alpha ) ); } } delete inputBlock; if ( mAlphaBand > 0 && mBand != mAlphaBand ) { delete alphaBlock; } return outputBlock; }
QgsRasterBlock * QgsPalettedRasterRenderer::block( int bandNo, QgsRectangle const & extent, int width, int height ) { QgsRasterBlock *outputBlock = new QgsRasterBlock(); if ( !mInput ) { return outputBlock; } QgsRasterBlock *inputBlock = mInput->block( bandNo, extent, width, height ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( "No raster data!" ); delete inputBlock; return outputBlock; } double currentOpacity = mOpacity; //rendering is faster without considering user-defined transparency bool hasTransparency = usesTransparency(); QgsRasterBlock *alphaBlock = 0; if ( mAlphaBand > 0 && mAlphaBand != mBand ) { alphaBlock = mInput->block( mAlphaBand, extent, width, height ); if ( !alphaBlock || alphaBlock->isEmpty() ) { delete inputBlock; delete alphaBlock; return outputBlock; } } else if ( mAlphaBand == mBand ) { alphaBlock = inputBlock; } if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) ) { delete inputBlock; delete alphaBlock; return outputBlock; } QRgb myDefaultColor = NODATA_COLOR; //use direct data access instead of QgsRasterBlock::setValue //because of performance unsigned int* outputData = ( unsigned int* )( outputBlock->bits() ); qgssize rasterSize = ( qgssize )width * height; for ( qgssize i = 0; i < rasterSize; ++i ) { if ( inputBlock->isNoData( i ) ) { outputData[i] = myDefaultColor; continue; } int val = ( int ) inputBlock->value( i ); if ( !hasTransparency ) { outputData[i] = mColors[val]; } else { currentOpacity = mOpacity; if ( mRasterTransparency ) { currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentOpacity *= alphaBlock->value( i ) / 255.0; } QColor currentColor = QColor( mColors[val] ); outputData[i] = qRgba( currentOpacity * currentColor.red(), currentOpacity * currentColor.green(), currentOpacity * currentColor.blue(), currentOpacity * 255 ); } } delete inputBlock; if ( mAlphaBand > 0 && mBand != mAlphaBand ) { delete alphaBlock; } return outputBlock; }
QgsRasterBlock *QgsPalettedRasterRenderer::block( int bandNo, QgsRectangle const &extent, int width, int height, QgsRasterBlockFeedback *feedback ) { std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() ); if ( !mInput || mClassData.isEmpty() ) { return outputBlock.release(); } std::shared_ptr< QgsRasterBlock > inputBlock( mInput->block( bandNo, extent, width, height, feedback ) ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( QStringLiteral( "No raster data!" ) ); return outputBlock.release(); } double currentOpacity = mOpacity; //rendering is faster without considering user-defined transparency bool hasTransparency = usesTransparency(); std::shared_ptr< QgsRasterBlock > alphaBlock; if ( mAlphaBand > 0 && mAlphaBand != mBand ) { alphaBlock.reset( mInput->block( mAlphaBand, extent, width, height, feedback ) ); if ( !alphaBlock || alphaBlock->isEmpty() ) { return outputBlock.release(); } } else if ( mAlphaBand == mBand ) { alphaBlock = inputBlock; } if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) ) { return outputBlock.release(); } QRgb myDefaultColor = NODATA_COLOR; //use direct data access instead of QgsRasterBlock::setValue //because of performance unsigned int *outputData = ( unsigned int * )( outputBlock->bits() ); qgssize rasterSize = ( qgssize )width * height; bool isNoData = false; for ( qgssize i = 0; i < rasterSize; ++i ) { const double value = inputBlock->valueAndNoData( i, isNoData ); if ( isNoData ) { outputData[i] = myDefaultColor; continue; } int val = static_cast< int >( value ); if ( !mColors.contains( val ) ) { outputData[i] = myDefaultColor; continue; } if ( !hasTransparency ) { outputData[i] = mColors.value( val ); } else { currentOpacity = mOpacity; if ( mRasterTransparency ) { currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentOpacity *= alphaBlock->value( i ) / 255.0; } QRgb c = mColors.value( val ); outputData[i] = qRgba( currentOpacity * qRed( c ), currentOpacity * qGreen( c ), currentOpacity * qBlue( c ), currentOpacity * qAlpha( c ) ); } } return outputBlock.release(); }
void * QgsMultiBandColorRenderer::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { Q_UNUSED( bandNo ); if ( !mInput ) { return 0; } //In some (common) cases, we can simplify the drawing loop considerably and save render time bool fastDraw = ( !usesTransparency() && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0 && mAlphaBand < 1 && !mRedContrastEnhancement && !mGreenContrastEnhancement && !mBlueContrastEnhancement && !mInvertColor ); QgsRasterInterface::DataType redType = QgsRasterInterface::UnknownDataType; if ( mRedBand > 0 ) { redType = ( QgsRasterInterface::DataType )mInput->dataType( mRedBand ); } QgsRasterInterface::DataType greenType = QgsRasterInterface::UnknownDataType; if ( mGreenBand > 0 ) { greenType = ( QgsRasterInterface::DataType )mInput->dataType( mGreenBand ); } QgsRasterInterface::DataType blueType = QgsRasterInterface::UnknownDataType; if ( mBlueBand > 0 ) { blueType = ( QgsRasterInterface::DataType )mInput->dataType( mBlueBand ); } QgsRasterInterface::DataType transparencyType = QgsRasterInterface::UnknownDataType; if ( mAlphaBand > 0 ) { transparencyType = ( QgsRasterInterface::DataType )mInput->dataType( mAlphaBand ); } QSet<int> bands; if ( mRedBand > 0 ) { bands << mRedBand; } if ( mGreenBand > 0 ) { bands << mGreenBand; } if ( mBlueBand > 0 ) { bands << mBlueBand; } if ( bands.size() < 1 ) { return 0; //no need to draw anything if no band is set } if ( mAlphaBand > 0 ) { bands << mAlphaBand; } QMap<int, void*> bandData; void* defaultPointer = 0; QSet<int>::const_iterator bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { bandData.insert( *bandIt, defaultPointer ); } void* redData = 0; void* greenData = 0; void* blueData = 0; void* alphaData = 0; bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { bandData[*bandIt] = mInput->block( *bandIt, extent, width, height ); if ( !bandData[*bandIt] ) { // We should free the alloced mem from block(). QgsDebugMsg( "No input band" ); bandIt--; for ( ; bandIt != bands.constBegin(); bandIt-- ) { VSIFree( bandData[*bandIt] ); } return 0; } } if ( mRedBand > 0 ) { redData = bandData[mRedBand]; } if ( mGreenBand > 0 ) { greenData = bandData[mGreenBand]; } if ( mBlueBand > 0 ) { blueData = bandData[mBlueBand]; } if ( mAlphaBand > 0 ) { alphaData = bandData[mAlphaBand]; } QImage img( width, height, QImage::Format_ARGB32_Premultiplied ); if ( img.isNull() ) { QgsDebugMsg( "Could not create QImage" ); bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { VSIFree( bandData[*bandIt] ); } return 0; } QRgb* imageScanLine = 0; int currentRasterPos = 0; int redVal = 0; int greenVal = 0; int blueVal = 0; QRgb defaultColor = qRgba( 255, 255, 255, 0 ); double currentOpacity = mOpacity; //opacity (between 0 and 1) for ( int i = 0; i < height; ++i ) { imageScanLine = ( QRgb* )( img.scanLine( i ) ); for ( int j = 0; j < width; ++j ) { if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc. { redVal = readValue( redData, redType, currentRasterPos ); greenVal = readValue( greenData, greenType, currentRasterPos ); blueVal = readValue( blueData, blueType, currentRasterPos ); if ( mInput->isNoDataValue( mRedBand, redVal ) || mInput->isNoDataValue( mGreenBand, greenVal ) || mInput->isNoDataValue( mBlueBand, blueVal ) ) { imageScanLine[j] = defaultColor; } else { imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 ); } ++currentRasterPos; continue; } bool isNoData = false; if ( mRedBand > 0 ) { redVal = readValue( redData, redType, currentRasterPos ); if ( mInput->isNoDataValue( mRedBand, redVal ) ) isNoData = true; } if ( mGreenBand > 0 ) { greenVal = readValue( greenData, greenType, currentRasterPos ); if ( mInput->isNoDataValue( mGreenBand, greenVal ) ) isNoData = true; } if ( mBlueBand > 0 ) { blueVal = readValue( blueData, blueType, currentRasterPos ); if ( mInput->isNoDataValue( mBlueBand, blueVal ) ) isNoData = true; } if ( isNoData ) { imageScanLine[j] = defaultColor; ++currentRasterPos; continue; } //apply default color if red, green or blue not in displayable range if (( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) ) || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) ) || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) ) { imageScanLine[j] = defaultColor; ++currentRasterPos; continue; } //stretch color values if ( mRedContrastEnhancement ) { redVal = mRedContrastEnhancement->enhanceContrast( redVal ); } if ( mGreenContrastEnhancement ) { greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal ); } if ( mBlueContrastEnhancement ) { blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal ); } if ( mInvertColor ) { redVal = 255 - redVal; greenVal = 255 - greenVal; blueVal = 255 - blueVal; } //opacity currentOpacity = mOpacity; if ( mRasterTransparency ) { currentOpacity = mRasterTransparency->alphaValue( redVal, greenVal, blueVal, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentOpacity *= ( readValue( alphaData, transparencyType, currentRasterPos ) / 255.0 ); } if ( doubleNear( currentOpacity, 1.0 ) ) { imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 ); } else { imageScanLine[j] = qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ); } ++currentRasterPos; } } bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { VSIFree( bandData[*bandIt] ); } void * data = VSIMalloc( img.byteCount() ); if ( ! data ) { QgsDebugMsg( QString( "Couldn't allocate output data memory of % bytes" ).arg( img.byteCount() ) ); return 0; } return memcpy( data, img.bits(), img.byteCount() ); }
QgsRasterBlock *QgsMultiBandColorRenderer::block( int bandNo, QgsRectangle const &extent, int width, int height, QgsRasterBlockFeedback *feedback ) { Q_UNUSED( bandNo ); std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() ); if ( !mInput ) { return outputBlock.release(); } //In some (common) cases, we can simplify the drawing loop considerably and save render time bool fastDraw = ( !usesTransparency() && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0 && mAlphaBand < 1 ); QSet<int> bands; if ( mRedBand > 0 ) { bands << mRedBand; } if ( mGreenBand > 0 ) { bands << mGreenBand; } if ( mBlueBand > 0 ) { bands << mBlueBand; } if ( bands.empty() ) { // no need to draw anything if no band is set // TODO:: we should probably return default color block return outputBlock.release(); } if ( mAlphaBand > 0 ) { bands << mAlphaBand; } QMap<int, QgsRasterBlock *> bandBlocks; QgsRasterBlock *defaultPointer = nullptr; QSet<int>::const_iterator bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { bandBlocks.insert( *bandIt, defaultPointer ); } QgsRasterBlock *redBlock = nullptr; QgsRasterBlock *greenBlock = nullptr; QgsRasterBlock *blueBlock = nullptr; QgsRasterBlock *alphaBlock = nullptr; bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { bandBlocks[*bandIt] = mInput->block( *bandIt, extent, width, height, feedback ); if ( !bandBlocks[*bandIt] ) { // We should free the alloced mem from block(). QgsDebugMsg( QStringLiteral( "No input band" ) ); --bandIt; for ( ; bandIt != bands.constBegin(); --bandIt ) { delete bandBlocks[*bandIt]; } return outputBlock.release(); } } if ( mRedBand > 0 ) { redBlock = bandBlocks[mRedBand]; } if ( mGreenBand > 0 ) { greenBlock = bandBlocks[mGreenBand]; } if ( mBlueBand > 0 ) { blueBlock = bandBlocks[mBlueBand]; } if ( mAlphaBand > 0 ) { alphaBlock = bandBlocks[mAlphaBand]; } if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) ) { for ( int i = 0; i < bandBlocks.size(); i++ ) { delete bandBlocks.value( i ); } return outputBlock.release(); } QRgb *outputBlockColorData = outputBlock->colorData(); // faster data access to data for the common case that input data are coming from RGB image with 8-bit bands bool hasByteRgb = ( redBlock && greenBlock && blueBlock && redBlock->dataType() == Qgis::Byte && greenBlock->dataType() == Qgis::Byte && blueBlock->dataType() == Qgis::Byte ); const quint8 *redData = nullptr, *greenData = nullptr, *blueData = nullptr; if ( hasByteRgb ) { redData = redBlock->byteData(); greenData = greenBlock->byteData(); blueData = blueBlock->byteData(); } QRgb myDefaultColor = NODATA_COLOR; if ( fastDraw ) { // By default RGB raster layers have contrast enhancement assigned and normally that requires us to take the slow // route that applies the enhancement. However if the algorithm type is "no enhancement" and all input bands are byte-sized, // no transform would be applied to the input values and we can take the fast route. bool hasEnhancement; if ( hasByteRgb ) { hasEnhancement = ( mRedContrastEnhancement && mRedContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement ) || ( mGreenContrastEnhancement && mGreenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement ) || ( mBlueContrastEnhancement && mBlueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement ); } else { hasEnhancement = mRedContrastEnhancement || mGreenContrastEnhancement || mBlueContrastEnhancement; } if ( hasEnhancement ) fastDraw = false; } qgssize count = ( qgssize )width * height; for ( qgssize i = 0; i < count; i++ ) { if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc. { if ( redBlock->isNoData( i ) || greenBlock->isNoData( i ) || blueBlock->isNoData( i ) ) { outputBlock->setColor( i, myDefaultColor ); } else { if ( hasByteRgb ) { outputBlockColorData[i] = qRgb( redData[i], greenData[i], blueData[i] ); } else { int redVal = static_cast<int>( redBlock->value( i ) ); int greenVal = static_cast<int>( greenBlock->value( i ) ); int blueVal = static_cast<int>( blueBlock->value( i ) ); outputBlockColorData[i] = qRgb( redVal, greenVal, blueVal ); } } continue; } bool isNoData = false; double redVal = 0; double greenVal = 0; double blueVal = 0; if ( mRedBand > 0 ) { redVal = redBlock->value( i ); if ( redBlock->isNoData( i ) ) isNoData = true; } if ( !isNoData && mGreenBand > 0 ) { greenVal = greenBlock->value( i ); if ( greenBlock->isNoData( i ) ) isNoData = true; } if ( !isNoData && mBlueBand > 0 ) { blueVal = blueBlock->value( i ); if ( blueBlock->isNoData( i ) ) isNoData = true; } if ( isNoData ) { outputBlock->setColor( i, myDefaultColor ); continue; } //apply default color if red, green or blue not in displayable range if ( ( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) ) || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) ) || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) ) { outputBlock->setColor( i, myDefaultColor ); continue; } //stretch color values if ( mRedContrastEnhancement ) { redVal = mRedContrastEnhancement->enhanceContrast( redVal ); } if ( mGreenContrastEnhancement ) { greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal ); } if ( mBlueContrastEnhancement ) { blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal ); } //opacity double currentOpacity = mOpacity; if ( mRasterTransparency ) { currentOpacity = mRasterTransparency->alphaValue( redVal, greenVal, blueVal, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentOpacity *= alphaBlock->value( i ) / 255.0; } if ( qgsDoubleNear( currentOpacity, 1.0 ) ) { outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) ); } else { outputBlock->setColor( i, qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ) ); } } //delete input blocks QMap<int, QgsRasterBlock *>::const_iterator bandDelIt = bandBlocks.constBegin(); for ( ; bandDelIt != bandBlocks.constEnd(); ++bandDelIt ) { delete bandDelIt.value(); } return outputBlock.release(); }
void QgsSingleBandPseudoColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) { if ( !p || !mProvider || !viewPort || !theQgsMapToPixel || !mShader ) { return; } double oversamplingX, oversamplingY; QgsRasterDataProvider::DataType transparencyType = QgsRasterDataProvider::UnknownDataType; if ( mAlphaBand > 0 ) { transparencyType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mAlphaBand ); } startRasterRead( mBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); //Read alpha band if necessary if ( mAlphaBand > 0 && mAlphaBand != mBand ) { startRasterRead( mAlphaBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); } //number of cols/rows in output pixels int nCols = 0; int nRows = 0; //number of raster cols/rows with oversampling int nRasterCols = 0; int nRasterRows = 0; //shift to top left point for the raster part int topLeftCol = 0; int topLeftRow = 0; void* rasterData; void* transparencyData = 0; double currentOpacity = mOpacity; QgsRasterDataProvider::DataType rasterType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mBand ); int red, green, blue; QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); //rendering is faster without considering user-defined transparency bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS ); while ( readNextRasterPart( mBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, &rasterData, topLeftCol, topLeftRow ) ) { if ( mAlphaBand > 0 && mAlphaBand != mBand ) { readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, &transparencyData, topLeftCol, topLeftRow ); } else if ( mAlphaBand == mBand ) { transparencyData = rasterData; } //create image QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied ); QRgb* imageScanLine = 0; double val = 0; int currentRasterPos = 0; for ( int i = 0; i < nRasterRows; ++i ) { imageScanLine = ( QRgb* )( img.scanLine( i ) ); for ( int j = 0; j < nRasterCols; ++j ) { val = readValue( rasterData, rasterType, currentRasterPos ); if ( !mShader->shade( val, &red, &green, &blue ) ) { imageScanLine[j] = myDefaultColor; ++currentRasterPos; continue; } if ( !hasTransparency ) { imageScanLine[j] = qRgba( red, green, blue, 255 ); } else { //opacity currentOpacity = mOpacity; if ( mRasterTransparency ) { currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 ); } imageScanLine[j] = qRgba( currentOpacity * red, currentOpacity * green, currentOpacity * blue, currentOpacity * 255 ); } ++currentRasterPos; } } drawImage( p, viewPort, img, topLeftCol, topLeftRow, nCols, nRows, oversamplingX, oversamplingY ); } stopRasterRead( mBand ); if ( mAlphaBand > 0 && mAlphaBand != mBand ) { stopRasterRead( mAlphaBand ); } }
void * QgsSingleBandPseudoColorRenderer::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { Q_UNUSED( bandNo ); if ( !mInput || !mShader ) { return 0; } QgsRasterInterface::DataType transparencyType = QgsRasterInterface::UnknownDataType; if ( mAlphaBand > 0 ) { transparencyType = ( QgsRasterInterface::DataType )mInput->dataType( mAlphaBand ); } void* transparencyData = 0; double currentOpacity = mOpacity; QgsRasterInterface::DataType rasterType = ( QgsRasterInterface::DataType )mInput->dataType( mBand ); void* rasterData = mInput->block( mBand, extent, width, height ); int red, green, blue; QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); //rendering is faster without considering user-defined transparency bool hasTransparency = usesTransparency(); if ( mAlphaBand > 0 && mAlphaBand != mBand ) { transparencyData = mInput->block( mAlphaBand, extent, width, height ); } else if ( mAlphaBand == mBand ) { transparencyData = rasterData; } //create image QImage img( width, height, QImage::Format_ARGB32_Premultiplied ); QRgb* imageScanLine = 0; double val = 0; int currentRasterPos = 0; for ( int i = 0; i < height; ++i ) { imageScanLine = ( QRgb* )( img.scanLine( i ) ); for ( int j = 0; j < width; ++j ) { val = readValue( rasterData, rasterType, currentRasterPos ); if ( !mShader->shade( val, &red, &green, &blue ) ) { imageScanLine[j] = myDefaultColor; ++currentRasterPos; continue; } if ( !hasTransparency ) { imageScanLine[j] = qRgba( red, green, blue, 255 ); } else { //opacity currentOpacity = mOpacity; if ( mRasterTransparency ) { currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 ); } imageScanLine[j] = qRgba( currentOpacity * red, currentOpacity * green, currentOpacity * blue, currentOpacity * 255 ); } ++currentRasterPos; } } VSIFree( rasterData ); void * data = VSIMalloc( img.byteCount() ); return memcpy( data, img.bits(), img.byteCount() ); }
void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) { if ( !p || !mProvider || !viewPort || !theQgsMapToPixel ) { return; } //In some (common) cases, we can simplify the drawing loop considerably and save render time bool fastDraw = ( !usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS ) && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0 && mAlphaBand < 1 && !mRedContrastEnhancement && !mGreenContrastEnhancement && !mBlueContrastEnhancement && !mInvertColor ); QgsRasterDataProvider::DataType redType = QgsRasterDataProvider::UnknownDataType; if ( mRedBand > 0 ) { redType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mRedBand ); } QgsRasterDataProvider::DataType greenType = QgsRasterDataProvider::UnknownDataType; if ( mGreenBand > 0 ) { greenType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mGreenBand ); } QgsRasterDataProvider::DataType blueType = QgsRasterDataProvider::UnknownDataType; if ( mBlueBand > 0 ) { blueType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mBlueBand ); } QgsRasterDataProvider::DataType transparencyType = QgsRasterDataProvider::UnknownDataType; if ( mAlphaBand > 0 ) { transparencyType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mAlphaBand ); } double oversamplingX = 1.0, oversamplingY = 1.0; QSet<int> bands; if ( mRedBand > 0 ) { bands << mRedBand; } if ( mGreenBand > 0 ) { bands << mGreenBand; } if ( mBlueBand > 0 ) { bands << mBlueBand; } if ( bands.size() < 1 ) { return; //no need to draw anything if no band is set } if ( mAlphaBand > 0 ) { bands << mAlphaBand; } QMap<int, void*> bandData; void* defaultPointer = 0; QSet<int>::const_iterator bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { bandData.insert( *bandIt, defaultPointer ); startRasterRead( *bandIt, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); } void* redData = 0; void* greenData = 0; void* blueData = 0; void* alphaData = 0; //number of cols/rows in output pixels int nCols = 0; int nRows = 0; //number of raster cols/rows with oversampling int nRasterCols = 0; int nRasterRows = 0; //shift to top left point for the raster part int topLeftCol = 0; int topLeftRow = 0; bool readSuccess = true; while ( true ) { QSet<int>::const_iterator bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { readSuccess = readSuccess && readNextRasterPart( *bandIt, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, &bandData[*bandIt], topLeftCol, topLeftRow ); } if ( !readSuccess ) { break; } if ( mRedBand > 0 ) { redData = bandData[mRedBand]; } if ( mGreenBand > 0 ) { greenData = bandData[mGreenBand]; } if ( mBlueBand > 0 ) { blueData = bandData[mBlueBand]; } if ( mAlphaBand > 0 ) { alphaData = bandData[mAlphaBand]; } QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied ); QRgb* imageScanLine = 0; int currentRasterPos = 0; int redVal = 0; int greenVal = 0; int blueVal = 0; int redDataVal = 0; int greenDataVal = 0; int blueDataVal = 0; QRgb defaultColor = qRgba( 255, 255, 255, 0 ); double currentOpacity = mOpacity; //opacity (between 0 and 1) for ( int i = 0; i < nRasterRows; ++i ) { imageScanLine = ( QRgb* )( img.scanLine( i ) ); for ( int j = 0; j < nRasterCols; ++j ) { if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc. { redVal = readValue( redData, redType, currentRasterPos ); greenVal = readValue( greenData, greenType, currentRasterPos ); blueVal = readValue( blueData, blueType, currentRasterPos ); imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 ); ++currentRasterPos; continue; } if ( mRedBand > 0 ) { redVal = readValue( redData, redType, currentRasterPos ); redDataVal = redVal; } if ( mGreenBand > 0 ) { greenVal = readValue( greenData, greenType, currentRasterPos ); greenDataVal = greenVal; } if ( mBlueBand > 0 ) { blueVal = readValue( blueData, blueType, currentRasterPos ); blueDataVal = blueVal; } //apply default color if red, green or blue not in displayable range if (( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) ) || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) ) || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) ) { imageScanLine[j] = defaultColor; ++currentRasterPos; continue; } //stretch color values if ( mRedContrastEnhancement ) { redVal = mRedContrastEnhancement->enhanceContrast( redVal ); } if ( mGreenContrastEnhancement ) { greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal ); } if ( mBlueContrastEnhancement ) { blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal ); } if ( mInvertColor ) { redVal = 255 - redVal; greenVal = 255 - greenVal; blueVal = 255 - blueVal; } //opacity currentOpacity = mOpacity; if ( mRasterTransparency ) { currentOpacity = mRasterTransparency->alphaValue( redDataVal, greenDataVal, blueDataVal, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentOpacity *= ( readValue( alphaData, transparencyType, currentRasterPos ) / 255.0 ); } if ( doubleNear( currentOpacity, 1.0 ) ) { imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 ); } else { imageScanLine[j] = qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ); } ++currentRasterPos; } } drawImage( p, viewPort, img, topLeftCol, topLeftRow, nCols, nRows, oversamplingX, oversamplingY ); } bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { stopRasterRead( *bandIt ); } }
QgsRasterBlock *QgsMultiBandColorRenderer::block( int bandNo, QgsRectangle const &extent, int width, int height, QgsRasterBlockFeedback *feedback ) { Q_UNUSED( bandNo ); std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() ); if ( !mInput ) { return outputBlock.release(); } //In some (common) cases, we can simplify the drawing loop considerably and save render time bool fastDraw = ( !usesTransparency() && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0 && mAlphaBand < 1 && !mRedContrastEnhancement && !mGreenContrastEnhancement && !mBlueContrastEnhancement ); QSet<int> bands; if ( mRedBand > 0 ) { bands << mRedBand; } if ( mGreenBand > 0 ) { bands << mGreenBand; } if ( mBlueBand > 0 ) { bands << mBlueBand; } if ( bands.size() < 1 ) { // no need to draw anything if no band is set // TODO:: we should probably return default color block return outputBlock.release(); } if ( mAlphaBand > 0 ) { bands << mAlphaBand; } QMap<int, QgsRasterBlock *> bandBlocks; QgsRasterBlock *defaultPointer = nullptr; QSet<int>::const_iterator bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { bandBlocks.insert( *bandIt, defaultPointer ); } QgsRasterBlock *redBlock = nullptr; QgsRasterBlock *greenBlock = nullptr; QgsRasterBlock *blueBlock = nullptr; QgsRasterBlock *alphaBlock = nullptr; bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { bandBlocks[*bandIt] = mInput->block( *bandIt, extent, width, height, feedback ); if ( !bandBlocks[*bandIt] ) { // We should free the alloced mem from block(). QgsDebugMsg( "No input band" ); --bandIt; for ( ; bandIt != bands.constBegin(); --bandIt ) { delete bandBlocks[*bandIt]; } return outputBlock.release(); } } if ( mRedBand > 0 ) { redBlock = bandBlocks[mRedBand]; } if ( mGreenBand > 0 ) { greenBlock = bandBlocks[mGreenBand]; } if ( mBlueBand > 0 ) { blueBlock = bandBlocks[mBlueBand]; } if ( mAlphaBand > 0 ) { alphaBlock = bandBlocks[mAlphaBand]; } if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) ) { for ( int i = 0; i < bandBlocks.size(); i++ ) { delete bandBlocks.value( i ); } return outputBlock.release(); } QRgb myDefaultColor = NODATA_COLOR; for ( qgssize i = 0; i < ( qgssize )width * height; i++ ) { if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc. { if ( redBlock->isNoData( i ) || greenBlock->isNoData( i ) || blueBlock->isNoData( i ) ) { outputBlock->setColor( i, myDefaultColor ); } else { int redVal = ( int )redBlock->value( i ); int greenVal = ( int )greenBlock->value( i ); int blueVal = ( int )blueBlock->value( i ); outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) ); } continue; } bool isNoData = false; double redVal = 0; double greenVal = 0; double blueVal = 0; if ( mRedBand > 0 ) { redVal = redBlock->value( i ); if ( redBlock->isNoData( i ) ) isNoData = true; } if ( !isNoData && mGreenBand > 0 ) { greenVal = greenBlock->value( i ); if ( greenBlock->isNoData( i ) ) isNoData = true; } if ( !isNoData && mBlueBand > 0 ) { blueVal = blueBlock->value( i ); if ( blueBlock->isNoData( i ) ) isNoData = true; } if ( isNoData ) { outputBlock->setColor( i, myDefaultColor ); continue; } //apply default color if red, green or blue not in displayable range if ( ( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) ) || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) ) || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) ) { outputBlock->setColor( i, myDefaultColor ); continue; } //stretch color values if ( mRedContrastEnhancement ) { redVal = mRedContrastEnhancement->enhanceContrast( redVal ); } if ( mGreenContrastEnhancement ) { greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal ); } if ( mBlueContrastEnhancement ) { blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal ); } //opacity double currentOpacity = mOpacity; if ( mRasterTransparency ) { currentOpacity = mRasterTransparency->alphaValue( redVal, greenVal, blueVal, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentOpacity *= alphaBlock->value( i ) / 255.0; } if ( qgsDoubleNear( currentOpacity, 1.0 ) ) { outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) ); } else { outputBlock->setColor( i, qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ) ); } } //delete input blocks QMap<int, QgsRasterBlock *>::const_iterator bandDelIt = bandBlocks.constBegin(); for ( ; bandDelIt != bandBlocks.constEnd(); ++bandDelIt ) { delete bandDelIt.value(); } return outputBlock.release(); }