QgsRasterBlock *QgsBrightnessContrastFilter::block( int bandNo, QgsRectangle const &extent, int width, int height, QgsRasterBlockFeedback *feedback ) { Q_UNUSED( bandNo ) QgsDebugMsgLevel( QStringLiteral( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ), 4 ); std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() ); if ( !mInput ) { return outputBlock.release(); } // At this moment we know that we read rendered image int bandNumber = 1; std::unique_ptr< QgsRasterBlock > inputBlock( mInput->block( bandNumber, extent, width, height, feedback ) ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( QStringLiteral( "No raster data!" ) ); return outputBlock.release(); } if ( mBrightness == 0 && mContrast == 0 ) { QgsDebugMsgLevel( QStringLiteral( "No brightness changes." ), 4 ); return inputBlock.release(); } if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) ) { return outputBlock.release(); } // adjust image QRgb myNoDataColor = qRgba( 0, 0, 0, 0 ); QRgb myColor; int r, g, b, alpha; double f = std::pow( ( mContrast + 100 ) / 100.0, 2 ); for ( qgssize i = 0; i < ( qgssize )width * height; i++ ) { if ( inputBlock->color( i ) == myNoDataColor ) { outputBlock->setColor( i, myNoDataColor ); continue; } myColor = inputBlock->color( i ); alpha = qAlpha( myColor ); r = adjustColorComponent( qRed( myColor ), alpha, mBrightness, f ); g = adjustColorComponent( qGreen( myColor ), alpha, mBrightness, f ); b = adjustColorComponent( qBlue( myColor ), alpha, mBrightness, f ); outputBlock->setColor( i, qRgba( r, g, b, alpha ) ); } return outputBlock.release(); }
void convertUiToUib( QDomDocument& doc, QDataStream& out ) { QByteArray introBlock; QByteArray actionsBlock; QByteArray buddiesBlock; QByteArray connectionsBlock; QByteArray functionsBlock; QByteArray imagesBlock; QByteArray menubarBlock; QByteArray slotsBlock; QByteArray tabstopsBlock; QByteArray toolbarsBlock; QByteArray variablesBlock; QByteArray widgetBlock; QDomElement actionsElem; QDomElement connectionsElem; QDomElement imagesElem; QDomElement menubarElem; QDomElement tabstopsElem; QDomElement toolbarsElem; QDomElement widgetElem; QMap<int, QStringList> buddies; UibStrTable strings; UibIndexMap objects; int widgetNo = -1; QCString className; Q_INT16 defaultMargin = -32768; Q_INT16 defaultSpacing = -32768; Q_UINT8 introFlags = 0; QDomElement elem = doc.firstChild().toElement().firstChild().toElement(); while ( !elem.isNull() ) { QString tag = elem.tagName(); switch ( tag[0].latin1() ) { case 'a': if ( tag == "actions" ) actionsElem = elem; break; case 'c': if ( tag == "class" ) { className = elem.firstChild().toText().data().latin1(); } else if ( tag == "connections" ) { connectionsElem = elem; } break; case 'f': if ( tag == "functions" ) { QDataStream out2( functionsBlock, IO_WriteOnly ); QDomElement f = elem.firstChild().toElement(); while ( !f.isNull() ) { if ( f.tagName() == "function" ) { packStringSplit( strings, out2, f.attribute("name").latin1(), '(' ); packString( strings, out2, f.firstChild().toText().data() ); } f = f.nextSibling().toElement(); } } break; case 'i': if ( tag == "images" ) { QDataStream out2( imagesBlock, IO_WriteOnly ); QDomElement f = elem.firstChild().toElement(); while ( !f.isNull() ) { if ( f.tagName() == "image" ) { QString name = f.attribute( "name" ); QDomElement g = f.firstChild().toElement(); if ( g.tagName() == "data" ) { QString format = g.attribute( "format", "PNG" ); QString hex = g.firstChild().toText().data(); int n = hex.length() / 2; QByteArray data( n ); for ( int i = 0; i < n; i++ ) data[i] = (char) hex.mid( 2 * i, 2 ) .toUInt( 0, 16 ); packString( strings, out2, name ); packString( strings, out2, format ); packUInt32( out2, g.attribute("length").toInt() ); packByteArray( out2, data ); } } f = f.nextSibling().toElement(); } } break; case 'l': if ( tag == "layoutdefaults" ) { QString margin = elem.attribute( "margin" ); if ( !margin.isEmpty() ) defaultMargin = margin.toInt(); QString spacing = elem.attribute( "spacing" ); if ( !spacing.isEmpty() ) defaultSpacing = spacing.toInt(); } break; case 'm': if ( tag == "menubar" ) menubarElem = elem; break; case 'p': if ( tag == "pixmapinproject" ) introFlags |= Intro_Pixmapinproject; break; case 's': if ( tag == "slots" ) { QDataStream out2( slotsBlock, IO_WriteOnly ); QDomElement f = elem.firstChild().toElement(); while ( !f.isNull() ) { if ( f.tagName() == "slot" ) { QString language = f.attribute( "language", "C++" ); QString slot = UibHack::normalize( f.firstChild().toText().data() ); packString( strings, out2, language ); packStringSplit( strings, out2, slot, '(' ); } f = f.nextSibling().toElement(); } } break; case 't': if ( tag == "tabstops" ) { tabstopsElem = elem; } else if ( tag == "toolbars" ) { toolbarsElem = elem; } break; case 'v': if ( tag == "variable" ) { QDataStream out2( variablesBlock, IO_WriteOnly | IO_Append ); packString( strings, out2, elem.firstChild().toText().data() ); } else if ( tag == "variables" ) { QDataStream out2( variablesBlock, IO_WriteOnly ); QDomElement f = elem.firstChild().toElement(); while ( !f.isNull() ) { if ( f.tagName() == "variable" ) packString( strings, out2, f.firstChild().toText().data() ); f = f.nextSibling().toElement(); } } break; case 'w': if ( tag == "widget" ) widgetElem = elem; } elem = elem.nextSibling().toElement(); } { QDataStream out2( widgetBlock, IO_WriteOnly ); widgetNo = outputObject( buddies, objects, strings, out2, widgetElem, "QWidget" ); } if ( !tabstopsElem.isNull() ) { QDataStream out2( tabstopsBlock, IO_WriteOnly ); QDomElement f = tabstopsElem.firstChild().toElement(); while ( !f.isNull() ) { if ( f.tagName() == "tabstop" ) { QString widgetName = f.firstChild().toText().data(); int no = objects.find( widgetName ); if ( no != -1 ) packUInt16( out2, no ); } f = f.nextSibling().toElement(); } } if ( !actionsElem.isNull() ) { QDataStream out2( actionsBlock, IO_WriteOnly ); outputObject( buddies, objects, strings, out2, actionsElem ); } if ( !menubarElem.isNull() ) { QDataStream out2( menubarBlock, IO_WriteOnly ); outputObject( buddies, objects, strings, out2, menubarElem, "QMenuBar" ); } if ( !toolbarsElem.isNull() ) { QDataStream out2( toolbarsBlock, IO_WriteOnly ); QDomElement f = toolbarsElem.firstChild().toElement(); while ( !f.isNull() ) { if ( f.tagName() == "toolbar" ) outputObject( buddies, objects, strings, out2, f, "QToolBar" ); f = f.nextSibling().toElement(); } } if ( !buddies.isEmpty() ) { QDataStream out2( buddiesBlock, IO_WriteOnly ); QMap<int, QStringList>::ConstIterator a = buddies.begin(); while ( a != buddies.end() ) { QStringList::ConstIterator b = (*a).begin(); while ( b != (*a).end() ) { int no = objects.find( *b ); if ( no != -1 ) { packUInt16( out2, a.key() ); packUInt16( out2, no ); } ++b; } ++a; } } if ( !connectionsElem.isNull() ) { QString prevLanguage = "C++"; int prevSenderNo = 0; QString prevSignal = "clicked()"; int prevReceiverNo = 0; QString prevSlot = "accept()"; QDataStream out2( connectionsBlock, IO_WriteOnly ); QDomElement f = connectionsElem.firstChild().toElement(); while ( !f.isNull() ) { if ( f.tagName() == "connection" ) { QMap<QString, QString> argMap; QDomElement g = f.firstChild().toElement(); while ( !g.isNull() ) { argMap[g.tagName()] = g.firstChild().toText().data(); g = g.nextSibling().toElement(); } QString language = f.attribute( "language", "C++" ); int senderNo = objects.find( argMap["sender"], widgetNo ); int receiverNo = objects.find( argMap["receiver"], widgetNo ); QString signal = UibHack::normalize( argMap["signal"] ); QString slot = UibHack::normalize( argMap["slot"] ); Q_UINT8 connectionFlags = 0; if ( language != prevLanguage ) connectionFlags |= Connection_Language; if ( senderNo != prevSenderNo ) connectionFlags |= Connection_Sender; if ( signal != prevSignal ) connectionFlags |= Connection_Signal; if ( receiverNo != prevReceiverNo ) connectionFlags |= Connection_Receiver; if ( slot != prevSlot ) connectionFlags |= Connection_Slot; out2 << connectionFlags; if ( connectionFlags & Connection_Language ) packString( strings, out2, language ); if ( connectionFlags & Connection_Sender ) packUInt16( out2, senderNo ); if ( connectionFlags & Connection_Signal ) packStringSplit( strings, out2, signal, '(' ); if ( connectionFlags & Connection_Receiver ) packUInt16( out2, receiverNo ); if ( connectionFlags & Connection_Slot ) packStringSplit( strings, out2, slot, '(' ); prevLanguage = language; prevSenderNo = senderNo; prevSignal = signal; prevReceiverNo = receiverNo; prevSlot = slot; } else if ( f.tagName() == "slot" ) { // ### } f = f.nextSibling().toElement(); } } { QDataStream out2( introBlock, IO_WriteOnly ); out2 << introFlags; out2 << defaultMargin; out2 << defaultSpacing; packUInt16( out2, objects.count() ); packCString( strings, out2, className ); } out << UibMagic; out << (Q_UINT8) '\n'; out << (Q_UINT8) '\r'; out << (Q_UINT8) out.version(); outputBlock( out, Block_Strings, strings.block() ); outputBlock( out, Block_Intro, introBlock ); outputBlock( out, Block_Images, imagesBlock ); outputBlock( out, Block_Widget, widgetBlock ); outputBlock( out, Block_Slots, slotsBlock ); outputBlock( out, Block_Tabstops, tabstopsBlock ); outputBlock( out, Block_Actions, actionsBlock ); outputBlock( out, Block_Menubar, menubarBlock ); outputBlock( out, Block_Toolbars, toolbarsBlock ); outputBlock( out, Block_Variables, variablesBlock ); outputBlock( out, Block_Functions, functionsBlock ); outputBlock( out, Block_Buddies, buddiesBlock ); outputBlock( out, Block_Connections, connectionsBlock ); out << (Q_UINT8) Block_End; }
QgsRasterBlock *QgsRasterProjector::block( int bandNo, QgsRectangle const &extent, int width, int height, QgsRasterBlockFeedback *feedback ) { QgsDebugMsgLevel( QStringLiteral( "extent:\n%1" ).arg( extent.toString() ), 4 ); QgsDebugMsgLevel( QStringLiteral( "width = %1 height = %2" ).arg( width ).arg( height ), 4 ); if ( !mInput ) { QgsDebugMsgLevel( QStringLiteral( "Input not set" ), 4 ); return new QgsRasterBlock(); } if ( feedback && feedback->isCanceled() ) return new QgsRasterBlock(); if ( ! mSrcCRS.isValid() || ! mDestCRS.isValid() || mSrcCRS == mDestCRS ) { QgsDebugMsgLevel( QStringLiteral( "No projection necessary" ), 4 ); return mInput->block( bandNo, extent, width, height, feedback ); } QgsCoordinateTransform inverseCt( mDestCRS, mSrcCRS, mDestDatumTransform, mSrcDatumTransform ); ProjectorData pd( extent, width, height, mInput, inverseCt, mPrecision ); QgsDebugMsgLevel( QStringLiteral( "srcExtent:\n%1" ).arg( pd.srcExtent().toString() ), 4 ); QgsDebugMsgLevel( QStringLiteral( "srcCols = %1 srcRows = %2" ).arg( pd.srcCols() ).arg( pd.srcRows() ), 4 ); // If we zoom out too much, projector srcRows / srcCols maybe 0, which can cause problems in providers if ( pd.srcRows() <= 0 || pd.srcCols() <= 0 ) { QgsDebugMsgLevel( QStringLiteral( "Zero srcRows or srcCols" ), 4 ); return new QgsRasterBlock(); } std::unique_ptr< QgsRasterBlock > inputBlock( mInput->block( bandNo, pd.srcExtent(), pd.srcCols(), pd.srcRows(), feedback ) ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( QStringLiteral( "No raster data!" ) ); return new QgsRasterBlock(); } qgssize pixelSize = QgsRasterBlock::typeSize( mInput->dataType( bandNo ) ); std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock( inputBlock->dataType(), width, height ) ); if ( inputBlock->hasNoDataValue() ) { outputBlock->setNoDataValue( inputBlock->noDataValue() ); } if ( !outputBlock->isValid() ) { QgsDebugMsg( QStringLiteral( "Cannot create block" ) ); return outputBlock.release(); } // set output to no data, it should be fast outputBlock->setIsNoData(); // No data: because isNoData()/setIsNoData() is slow with respect to simple memcpy, // we use if only if necessary: // 1) no data value exists (numerical) -> memcpy, not necessary isNoData()/setIsNoData() // 2) no data value does not exist but it may contain no data (numerical no data bitmap) // -> must use isNoData()/setIsNoData() // 3) no data are not used (no no data value, no no data bitmap) -> simple memcpy // 4) image - simple memcpy // To copy no data values stored in bitmaps we have to use isNoData()/setIsNoData(), // we cannot fill output block with no data because we use memcpy for data, not setValue(). bool doNoData = !QgsRasterBlock::typeIsNumeric( inputBlock->dataType() ) && inputBlock->hasNoData() && !inputBlock->hasNoDataValue(); outputBlock->setIsNoData(); int srcRow, srcCol; for ( int i = 0; i < height; ++i ) { if ( feedback && feedback->isCanceled() ) break; for ( int j = 0; j < width; ++j ) { bool inside = pd.srcRowCol( i, j, &srcRow, &srcCol ); if ( !inside ) continue; // we have everything set to no data qgssize srcIndex = static_cast< qgssize >( srcRow ) * pd.srcCols() + srcCol; // isNoData() may be slow so we check doNoData first if ( doNoData && inputBlock->isNoData( srcRow, srcCol ) ) { outputBlock->setIsNoData( i, j ); continue; } qgssize destIndex = static_cast< qgssize >( i ) * width + j; char *srcBits = inputBlock->bits( srcIndex ); char *destBits = outputBlock->bits( destIndex ); if ( !srcBits ) { // QgsDebugMsg( QStringLiteral( "Cannot get input block data: row = %1 col = %2" ).arg( i ).arg( j ) ); continue; } if ( !destBits ) { // QgsDebugMsg( QStringLiteral( "Cannot set output block data: srcRow = %1 srcCol = %2" ).arg( srcRow ).arg( srcCol ) ); continue; } memcpy( destBits, srcBits, pixelSize ); outputBlock->setIsData( i, j ); } } return outputBlock.release(); }
QgsRasterBlock *QgsSingleBandGrayRenderer::block( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback ) { Q_UNUSED( bandNo ); QgsDebugMsgLevel( QStringLiteral( "width = %1 height = %2" ).arg( width ).arg( height ), 4 ); std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() ); if ( !mInput ) { return outputBlock.release(); } std::shared_ptr< QgsRasterBlock > inputBlock( mInput->block( mGrayBand, extent, width, height, feedback ) ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( QStringLiteral( "No raster data!" ) ); return outputBlock.release(); } std::shared_ptr< QgsRasterBlock > alphaBlock; if ( mAlphaBand > 0 && mGrayBand != mAlphaBand ) { alphaBlock.reset( mInput->block( mAlphaBand, extent, width, height, feedback ) ); if ( !alphaBlock || alphaBlock->isEmpty() ) { // TODO: better to render without alpha return outputBlock.release(); } } else if ( mAlphaBand > 0 ) { alphaBlock = inputBlock; } if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) ) { return outputBlock.release(); } QRgb myDefaultColor = NODATA_COLOR; bool isNoData = false; for ( qgssize i = 0; i < ( qgssize )width * height; i++ ) { double grayVal = inputBlock->valueAndNoData( i, isNoData ); if ( isNoData ) { outputBlock->setColor( i, myDefaultColor ); continue; } double currentAlpha = mOpacity; if ( mRasterTransparency ) { currentAlpha = mRasterTransparency->alphaValue( grayVal, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentAlpha *= alphaBlock->value( i ) / 255.0; } if ( mContrastEnhancement ) { if ( !mContrastEnhancement->isValueInDisplayableRange( grayVal ) ) { outputBlock->setColor( i, myDefaultColor ); continue; } grayVal = mContrastEnhancement->enhanceContrast( grayVal ); } if ( mGradient == WhiteToBlack ) { grayVal = 255 - grayVal; } if ( qgsDoubleNear( currentAlpha, 1.0 ) ) { outputBlock->setColor( i, qRgba( grayVal, grayVal, grayVal, 255 ) ); } else { outputBlock->setColor( i, qRgba( currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * 255 ) ); } } return outputBlock.release(); }
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(); }
/** * Read in paramaters and output a maze line by line. */ int main(int argc, char *argv[]) { // read in paramaters if (argc < 3) { fprintf(stderr, "Usage: %s [width] [height] [OPTIONS]\n", argv[0]); fprintf(stderr, "\ta - ASCII style maze (default).\n"); fprintf(stderr, "\tb - BLOCK style maze.\n"); fprintf(stderr, "\tds - Turn set debug on.\n"); fprintf(stderr, "\tdr - Turn row debug on.\n"); fprintf(stderr, "\tr - Turn off random generation.\n"); return 1; } // Read in required args width = atoi(argv[1]); uint height = atoi(argv[2]); // Check to make sure they are valid if (width == 0 || height == 0) { fprintf(stderr, "Maze width and height must be greater then 0.\n"); return 1; } MAZETYPE type = ASCII; debugsets = false; srand(time(NULL)); // Read in optional args for (int i = 2; i < argc; i++) { if (0 == strcmp(argv[i], "ds")) debugsets = true; if (0 == strcmp(argv[i], "dr")) debugrows = true; // "Turn off" randomness if (0 == strcmp(argv[i], "r")) srand(1); if (0 == strcmp(argv[i], "a")) type = ASCII; if (0 == strcmp(argv[i], "b")) type = BLOCK; } // Create/init vars set = new uint[width]; row = new uint[width]; previousRow = new uint[width]; for (uint i = 0; i < width; i++) { set[i] = i + width + 1; row[i] = 0; previousRow[i] = 0; } // create & print out the rows bool isLast, isFirst; for (uint i = 0; i < height; i++) { isLast = (i == height - 1); isFirst = (i == 0); makeRow(isLast); if (type == ASCII) outputASCII(isLast, isFirst); else if (type == BLOCK) outputBlock(isLast); } // Memory cleanup; delete[]set; delete[]row; delete[]previousRow; return 0; }
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(); }
QgsRasterBlock *QgsRasterResampleFilter::block( int bandNo, QgsRectangle const &extent, int width, int height, QgsRasterBlockFeedback *feedback ) { Q_UNUSED( bandNo ); QgsDebugMsgLevel( QString( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ), 4 ); std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() ); if ( !mInput ) return outputBlock.release(); double oversampling = 1.0; // approximate global oversampling factor if ( mZoomedInResampler || mZoomedOutResampler ) { QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider *>( mInput->sourceInput() ); if ( provider && ( provider->capabilities() & QgsRasterDataProvider::Size ) ) { double xRes = extent.width() / width; double providerXRes = provider->extent().width() / provider->xSize(); double pixelRatio = xRes / providerXRes; oversampling = ( pixelRatio > mMaxOversampling ) ? mMaxOversampling : pixelRatio; QgsDebugMsgLevel( QString( "xRes = %1 providerXRes = %2 pixelRatio = %3 oversampling = %4" ).arg( xRes ).arg( providerXRes ).arg( pixelRatio ).arg( oversampling ), 4 ); } else { // We don't know exact data source resolution (WMS) so we expect that // server data have higher resolution (which is not always true) and use // mMaxOversampling oversampling = mMaxOversampling; } } QgsDebugMsgLevel( QString( "oversampling %1" ).arg( oversampling ), 4 ); int bandNumber = 1; // Do no oversampling if no resampler for zoomed in / zoomed out (nearest neighbour) // We do mZoomedInResampler if oversampling == 1 (otherwise for example reprojected // zoom in rasters are never resampled because projector limits resolution. if ( ( ( oversampling < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) && !mZoomedInResampler ) || ( oversampling > 1.0 && !mZoomedOutResampler ) ) { QgsDebugMsgLevel( "No oversampling.", 4 ); return mInput->block( bandNumber, extent, width, height, feedback ); } //effective oversampling factors are different to global one because of rounding double oversamplingX = ( static_cast< double >( width ) * oversampling ) / width; double oversamplingY = ( static_cast< double >( height ) * oversampling ) / height; // TODO: we must also increase the extent to get correct result on borders of parts int resWidth = width * oversamplingX; int resHeight = height * oversamplingY; std::unique_ptr< QgsRasterBlock > inputBlock( mInput->block( bandNumber, extent, resWidth, resHeight, feedback ) ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( "No raster data!" ); return outputBlock.release(); } if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) ) { return outputBlock.release(); } //resample image QImage img = inputBlock->image(); QImage dstImg = QImage( width, height, QImage::Format_ARGB32_Premultiplied ); if ( mZoomedInResampler && ( oversamplingX < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) ) { QgsDebugMsgLevel( "zoomed in resampling", 4 ); mZoomedInResampler->resample( img, dstImg ); } else if ( mZoomedOutResampler && oversamplingX > 1.0 ) { QgsDebugMsgLevel( "zoomed out resampling", 4 ); mZoomedOutResampler->resample( img, dstImg ); } else { // Should not happen QgsDebugMsg( "Unexpected resampling" ); dstImg = img.scaled( width, height ); } outputBlock->setImage( &dstImg ); return outputBlock.release(); // No resampling }
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(); }