diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7af645dafe42..1741398191e9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -160,11 +160,13 @@ SET(QGIS_CORE_SRCS raster/qgslinearminmaxenhancement.cpp raster/qgslinearminmaxenhancementwithclip.cpp raster/qgspseudocolorshader.cpp + raster/qgsrasterface.cpp raster/qgsrasterlayer.cpp raster/qgsrastertransparency.cpp raster/qgsrastershader.cpp raster/qgsrastershaderfunction.cpp + raster/qgsrasterdrawer.cpp raster/qgsrasterrendererregistry.cpp raster/qgsrasterrenderer.cpp raster/qgsbilinearrasterresampler.cpp @@ -385,6 +387,7 @@ SET(QGIS_CORE_HDRS raster/qgspseudocolorshader.h raster/qgsrasterpyramid.h raster/qgsrasterbandstats.h + raster/qgsrasterface.h raster/qgsrasterlayer.h raster/qgsrastertransparency.h raster/qgsrastershader.h diff --git a/src/core/qgsrasterdataprovider.cpp b/src/core/qgsrasterdataprovider.cpp index 58f3e667c307..ded54f698a94 100644 --- a/src/core/qgsrasterdataprovider.cpp +++ b/src/core/qgsrasterdataprovider.cpp @@ -93,6 +93,16 @@ void QgsRasterDataProvider::readBlock( int bandNo, QgsRectangle free( mySrcData ); } +void * QgsRasterDataProvider::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) +{ + QgsDebugMsg( QString( "bandNo = %1 width = %2 height = %3" ).arg( bandNo ).arg( width ).arg( height ) ); + + // TODO: replace VSIMalloc, it is GDAL function + void * data = VSIMalloc( dataTypeSize( bandNo ) * width * height ); + readBlock( bandNo, extent, width, height, data ); + + return data; +} QgsRasterDataProvider::QgsRasterDataProvider(): mDpi( -1 ) { diff --git a/src/core/qgsrasterdataprovider.h b/src/core/qgsrasterdataprovider.h index deef25014f44..7e8391744d84 100644 --- a/src/core/qgsrasterdataprovider.h +++ b/src/core/qgsrasterdataprovider.h @@ -25,6 +25,7 @@ #include "qgslogger.h" #include "qgsrectangle.h" #include "qgsdataprovider.h" +#include "qgsrasterface.h" #include "qgscolorrampshader.h" #include "qgsrasterpyramid.h" #include "qgscoordinatereferencesystem.h" @@ -47,7 +48,7 @@ class QByteArray; * QgsVectorDataProvider, and does not yet make * sense for Raster layers. */ -class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider +class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRasterFace { Q_OBJECT @@ -328,6 +329,9 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider /** read block of data using give extent and size */ virtual void readBlock( int bandNo, QgsRectangle const & viewExtent, int width, int height, QgsCoordinateReferenceSystem theSrcCRS, QgsCoordinateReferenceSystem theDestCRS, void *data ); + /** Read block of data using given extent and size. */ + virtual void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height ); + /* Read a value from a data block at a given index. */ virtual double readValue( void *data, int type, int index ); diff --git a/src/core/raster/qgsmultibandcolorrenderer.cpp b/src/core/raster/qgsmultibandcolorrenderer.cpp index 58fd6a3f6cd2..6cbd20f1c820 100644 --- a/src/core/raster/qgsmultibandcolorrenderer.cpp +++ b/src/core/raster/qgsmultibandcolorrenderer.cpp @@ -24,11 +24,11 @@ #include #include -QgsMultiBandColorRenderer::QgsMultiBandColorRenderer( QgsRasterDataProvider* provider, int redBand, int greenBand, int blueBand, +QgsMultiBandColorRenderer::QgsMultiBandColorRenderer( QgsRasterFace* input, int redBand, int greenBand, int blueBand, QgsContrastEnhancement* redEnhancement, QgsContrastEnhancement* greenEnhancement, QgsContrastEnhancement* blueEnhancement ): - QgsRasterRenderer( provider, "multibandcolor" ), mRedBand( redBand ), mGreenBand( greenBand ), mBlueBand( blueBand ), + QgsRasterRenderer( input, "multibandcolor" ), mRedBand( redBand ), mGreenBand( greenBand ), mBlueBand( blueBand ), mRedContrastEnhancement( redEnhancement ), mGreenContrastEnhancement( greenEnhancement ), mBlueContrastEnhancement( blueEnhancement ) { } @@ -55,7 +55,7 @@ void QgsMultiBandColorRenderer::setBlueContrastEnhancement( QgsContrastEnhanceme delete mBlueContrastEnhancement; mBlueContrastEnhancement = ce; } -QgsRasterRenderer* QgsMultiBandColorRenderer::create( const QDomElement& elem, QgsRasterDataProvider* provider ) +QgsRasterRenderer* QgsMultiBandColorRenderer::create( const QDomElement& elem, QgsRasterFace* input ) { if ( elem.isNull() ) { @@ -73,7 +73,7 @@ QgsRasterRenderer* QgsMultiBandColorRenderer::create( const QDomElement& elem, Q if ( !redContrastElem.isNull() ) { redContrastEnhancement = new QgsContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )( - provider->dataType( redBand ) ) ); + input->dataType( redBand ) ) ); redContrastEnhancement->readXML( redContrastElem ); } @@ -82,7 +82,7 @@ QgsRasterRenderer* QgsMultiBandColorRenderer::create( const QDomElement& elem, Q if ( !greenContrastElem.isNull() ) { greenContrastEnhancement = new QgsContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )( - provider->dataType( greenBand ) ) ); + input->dataType( greenBand ) ) ); greenContrastEnhancement->readXML( greenContrastElem ); } @@ -91,49 +91,54 @@ QgsRasterRenderer* QgsMultiBandColorRenderer::create( const QDomElement& elem, Q if ( !blueContrastElem.isNull() ) { blueContrastEnhancement = new QgsContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )( - provider->dataType( blueBand ) ) ); + input->dataType( blueBand ) ) ); blueContrastEnhancement->readXML( blueContrastElem ); } - QgsRasterRenderer* r = new QgsMultiBandColorRenderer( provider, redBand, greenBand, blueBand, redContrastEnhancement, + QgsRasterRenderer* r = new QgsMultiBandColorRenderer( input, redBand, greenBand, blueBand, redContrastEnhancement, greenContrastEnhancement, blueContrastEnhancement ); r->readXML( elem ); return r; } -void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) +//void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) +void * QgsMultiBandColorRenderer::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { - if ( !p || !mProvider || !viewPort || !theQgsMapToPixel ) + if ( !mInput ) { - return; + return 0; } //In some (common) cases, we can simplify the drawing loop considerably and save render time + // TODO + bool fastDraw = false; + /* 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 ); + redType = ( QgsRasterFace::DataType )mInput->dataType( mRedBand ); } QgsRasterDataProvider::DataType greenType = QgsRasterDataProvider::UnknownDataType; if ( mGreenBand > 0 ) { - greenType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mGreenBand ); + greenType = ( QgsRasterFace::DataType )mInput->dataType( mGreenBand ); } QgsRasterDataProvider::DataType blueType = QgsRasterDataProvider::UnknownDataType; if ( mBlueBand > 0 ) { - blueType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mBlueBand ); + blueType = ( QgsRasterFace::DataType )mInput->dataType( mBlueBand ); } - QgsRasterDataProvider::DataType transparencyType = QgsRasterDataProvider::UnknownDataType; + QgsRasterFace::DataType transparencyType = QgsRasterFace::UnknownDataType; if ( mAlphaBand > 0 ) { - transparencyType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mAlphaBand ); + transparencyType = ( QgsRasterFace::DataType )mInput->dataType( mAlphaBand ); } double oversamplingX = 1.0, oversamplingY = 1.0; @@ -152,7 +157,7 @@ void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, } if ( bands.size() < 1 ) { - return; //no need to draw anything if no band is set + return 0; //no need to draw anything if no band is set } if ( mAlphaBand > 0 ) @@ -166,7 +171,7 @@ void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, for ( ; bandIt != bands.constEnd(); ++bandIt ) { bandData.insert( *bandIt, defaultPointer ); - startRasterRead( *bandIt, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); + //startRasterRead( *bandIt, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); } void* redData = 0; @@ -184,137 +189,174 @@ void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, int topLeftRow = 0; bool readSuccess = true; - while ( true ) - { - QSet::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; - } + //QSet::const_iterator bandIt = bands.constBegin(); + bandIt = bands.constBegin(); + for ( ; bandIt != bands.constEnd(); ++bandIt ) + { + //readSuccess = readSuccess && readNextRasterPart( *bandIt, oversamplingX, oversamplingY, viewPort, nCols, nRows, + // nRasterCols, nRasterRows, &bandData[*bandIt], topLeftCol, topLeftRow ); + bandData[*bandIt] = mInput->readBlock( *bandIt, extent, width, height ); + if ( !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]; - } + 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; - QRgb defaultColor = qRgba( 255, 255, 255, 0 ); - double currentOpacity = mOpacity; //opacity (between 0 and 1) + QImage img( width, height, QImage::Format_ARGB32_Premultiplied ); + 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 < nRasterRows; ++i ) + for ( int i = 0; i < height; ++i ) + { + imageScanLine = ( QRgb* )( img.scanLine( i ) ); + for ( int j = 0; j < width; ++j ) { - 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 ); + } + if ( mGreenBand > 0 ) + { + greenVal = readValue( greenData, greenType, currentRasterPos ); + } + if ( mBlueBand > 0 ) + { + blueVal = readValue( blueData, blueType, currentRasterPos ); + } - 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 ); - } - if ( mGreenBand > 0 ) - { - greenVal = readValue( greenData, greenType, currentRasterPos ); - } - if ( mBlueBand > 0 ) - { - blueVal = readValue( blueData, blueType, currentRasterPos ); - } - - //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 ); - } + //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 ); } - } - drawImage( p, viewPort, img, topLeftCol, topLeftRow, nCols, nRows, oversamplingX, oversamplingY ); + //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, 255 ) ) + { + 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 ) { - stopRasterRead( *bandIt ); + VSIFree( bandData[*bandIt] ); } + + void * data = VSIMalloc( img.byteCount() ); + return memcpy( data, img.bits(), img.byteCount() ); } void QgsMultiBandColorRenderer::writeXML( QDomDocument& doc, QDomElement& parentElem ) const diff --git a/src/core/raster/qgsmultibandcolorrenderer.h b/src/core/raster/qgsmultibandcolorrenderer.h index bb89002e9361..c7d1e61572b4 100644 --- a/src/core/raster/qgsmultibandcolorrenderer.h +++ b/src/core/raster/qgsmultibandcolorrenderer.h @@ -27,14 +27,15 @@ class QDomElement; class CORE_EXPORT QgsMultiBandColorRenderer: public QgsRasterRenderer { public: - QgsMultiBandColorRenderer( QgsRasterDataProvider* provider, int redBand, int greenBand, int blueBand, + QgsMultiBandColorRenderer( QgsRasterFace* input, int redBand, int greenBand, int blueBand, QgsContrastEnhancement* redEnhancement = 0, QgsContrastEnhancement* greenEnhancement = 0, QgsContrastEnhancement* blueEnhancement = 0 ); ~QgsMultiBandColorRenderer(); - static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterDataProvider* provider ); + static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterFace* input ); - void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ); + //void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ); + void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height ); int redBand() const { return mRedBand; } void setRedBand( int band ) { mRedBand = band; } diff --git a/src/core/raster/qgspalettedrasterrenderer.cpp b/src/core/raster/qgspalettedrasterrenderer.cpp index 3d69c3d60b7e..0fc638fd49a9 100644 --- a/src/core/raster/qgspalettedrasterrenderer.cpp +++ b/src/core/raster/qgspalettedrasterrenderer.cpp @@ -23,9 +23,9 @@ #include #include -QgsPalettedRasterRenderer::QgsPalettedRasterRenderer( QgsRasterDataProvider* provider, int bandNumber, +QgsPalettedRasterRenderer::QgsPalettedRasterRenderer( QgsRasterFace* input, int bandNumber, QColor* colorArray, int nColors ): - QgsRasterRenderer( provider, "paletted" ), mBandNumber( bandNumber ), mColors( colorArray ), mNColors( nColors ) + QgsRasterRenderer( input, "paletted" ), mBandNumber( bandNumber ), mColors( colorArray ), mNColors( nColors ) { } @@ -34,7 +34,7 @@ QgsPalettedRasterRenderer::~QgsPalettedRasterRenderer() delete[] mColors; } -QgsRasterRenderer* QgsPalettedRasterRenderer::create( const QDomElement& elem, QgsRasterDataProvider* provider ) +QgsRasterRenderer* QgsPalettedRasterRenderer::create( const QDomElement& elem, QgsRasterFace* input ) { if ( elem.isNull() ) { @@ -62,7 +62,7 @@ QgsRasterRenderer* QgsPalettedRasterRenderer::create( const QDomElement& elem, Q colors[value] = QColor( entryElem.attribute( "color", "#000000" ) ); } } - QgsRasterRenderer* r = new QgsPalettedRasterRenderer( provider, bandNumber, colors, nColors ); + QgsRasterRenderer* r = new QgsPalettedRasterRenderer( input, bandNumber, colors, nColors ); r->readXML( elem ); return r; } @@ -81,109 +81,103 @@ QColor* QgsPalettedRasterRenderer::colors() const return colorArray; } -void QgsPalettedRasterRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) +//void QgsPalettedRasterRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) +void * QgsPalettedRasterRenderer::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { - if ( !p || !mProvider || !viewPort || !theQgsMapToPixel ) + if ( !mInput ) { - return; - } - - double oversamplingX, oversamplingY; - QgsRasterDataProvider::DataType transparencyType = QgsRasterDataProvider::UnknownDataType; - if ( mAlphaBand > 0 ) - { - transparencyType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mAlphaBand ); - } - startRasterRead( mBandNumber, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); - - //Read alpha band if necessary - if ( mAlphaBand > 0 && mAlphaBand != mBandNumber ) - { - startRasterRead( mAlphaBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); + return 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; - int currentRasterPos = 0; - QgsRasterDataProvider::DataType rasterType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mBandNumber ); - void* rasterData; + //double oversamplingX, oversamplingY; + //QgsRasterFace::DataType transparencyType = QgsRasterFace::UnknownDataType; + //if ( mAlphaBand > 0 ) + //{ + //transparencyType = ( QgsRasterFace::DataType )mInput->dataType( mAlphaBand ); + //} + //startRasterRead( mBandNumber, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); + + ////Read alpha band if necessary + //if ( mAlphaBand > 0 && mAlphaBand != mBandNumber ) + //{ + //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; + //int currentRasterPos = 0; + QgsRasterFace::DataType rasterType = ( QgsRasterFace::DataType )mInput->dataType( mBandNumber ); + void* rasterData = mInput->readBlock( bandNo, extent, width, height ); double currentOpacity = mOpacity; //rendering is faster without considering user-defined transparency - bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS ); + // TODO + bool hasTransparency = false; + //bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS ); void* transparencyData = 0; - while ( readNextRasterPart( mBandNumber, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, - &rasterData, topLeftCol, topLeftRow ) ) - { - if ( mAlphaBand > 0 && mAlphaBand != mBandNumber ) - { - readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, - &transparencyData, topLeftCol, topLeftRow ); - } - else if ( mAlphaBand == mBandNumber ) - { - transparencyData = rasterData; - } - - //create image - QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied ); - QRgb* imageScanLine = 0; - int val = 0; - currentRasterPos = 0; + //if ( mAlphaBand > 0 && mAlphaBand != mBandNumber ) + //{ + //readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, + //&transparencyData, topLeftCol, topLeftRow ); + //} + //else if ( mAlphaBand == mBandNumber ) + //{ + //transparencyData = rasterData; + //} + + //create image + QImage img( width, height, QImage::Format_ARGB32_Premultiplied ); + QRgb* imageScanLine = 0; + int val = 0; + int currentRasterPos = 0; - for ( int i = 0; i < nRasterRows; ++i ) + for ( int i = 0; i < height; ++i ) + { + imageScanLine = ( QRgb* )( img.scanLine( i ) ); + for ( int j = 0; j < width; ++j ) { - imageScanLine = ( QRgb* )( img.scanLine( i ) ); - for ( int j = 0; j < nRasterCols; ++j ) + val = readValue( rasterData, rasterType, currentRasterPos ); + if ( !hasTransparency ) + { + imageScanLine[j] = mColors[ val ].rgba(); + } + else { - val = readValue( rasterData, rasterType, currentRasterPos ); - if ( !hasTransparency ) + currentOpacity = mOpacity; + if ( mRasterTransparency ) { - imageScanLine[j] = mColors[ val ].rgba(); + currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0; + } + //if ( mAlphaBand > 0 ) + //{ + //currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 ); + //} + QColor& currentColor = mColors[val]; + + if ( mInvertColor ) + { + imageScanLine[j] = qRgba( currentOpacity * currentColor.blue(), currentOpacity * currentColor.green(), currentOpacity * currentColor.red(), currentOpacity * 255 ); } else { - currentOpacity = mOpacity; - if ( mRasterTransparency ) - { - currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0; - } - if ( mAlphaBand > 0 ) - { - currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 ); - } - QColor& currentColor = mColors[val]; - - if ( mInvertColor ) - { - imageScanLine[j] = qRgba( currentOpacity * currentColor.blue(), currentOpacity * currentColor.green(), currentOpacity * currentColor.red(), currentOpacity * 255 ); - } - else - { - imageScanLine[j] = qRgba( currentOpacity * currentColor.red(), currentOpacity * currentColor.green(), currentOpacity * currentColor.blue(), currentOpacity * 255 ); - } + imageScanLine[j] = qRgba( currentOpacity * currentColor.red(), currentOpacity * currentColor.green(), currentOpacity * currentColor.blue(), currentOpacity * 255 ); } - ++currentRasterPos; } + ++currentRasterPos; } - - drawImage( p, viewPort, img, topLeftCol, topLeftRow, nCols, nRows, oversamplingX, oversamplingY ); } - //stop raster reading - stopRasterRead( mBandNumber ); - if ( mAlphaBand > 0 && mAlphaBand != mBandNumber ) - { - stopRasterRead( mAlphaBand ); - } + VSIFree( rasterData ); + void * data = VSIMalloc( img.byteCount() ); + return memcpy( data, img.bits(), img.byteCount() ); } void QgsPalettedRasterRenderer::writeXML( QDomDocument& doc, QDomElement& parentElem ) const diff --git a/src/core/raster/qgspalettedrasterrenderer.h b/src/core/raster/qgspalettedrasterrenderer.h index 1357d5b8cf5f..ada7fd394130 100644 --- a/src/core/raster/qgspalettedrasterrenderer.h +++ b/src/core/raster/qgspalettedrasterrenderer.h @@ -27,12 +27,14 @@ class CORE_EXPORT QgsPalettedRasterRenderer: public QgsRasterRenderer { public: /**Renderer owns color array*/ - QgsPalettedRasterRenderer( QgsRasterDataProvider* provider, int bandNumber, QColor* colorArray, int nColors ); + QgsPalettedRasterRenderer( QgsRasterFace* input, int bandNumber, QColor* colorArray, int nColors ); ~QgsPalettedRasterRenderer(); - static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterDataProvider* provider ); + static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterFace* input ); void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ); + void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height ); + /**Returns number of colors*/ int nColors() const { return mNColors; } /**Returns copy of color array (caller takes ownership)*/ diff --git a/src/core/raster/qgsrasterdrawer.cpp b/src/core/raster/qgsrasterdrawer.cpp new file mode 100644 index 000000000000..9d58f709f30a --- /dev/null +++ b/src/core/raster/qgsrasterdrawer.cpp @@ -0,0 +1,220 @@ +/*************************************************************************** + qgsrasterdrawer.cpp + --------------------- + begin : June 2012 + copyright : (C) 2012 by Radim Blazek + email : radim dot blazek at gmail.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgslogger.h" +#include "qgsrasterdrawer.h" +//#include "qgsrasterresampler.h" +#include "qgsrasterprojector.h" +#include "qgsrastertransparency.h" +#include "qgsrasterviewport.h" +#include "qgsmaptopixel.h" + +//resamplers +//#include "qgsbilinearrasterresampler.h" +//#include "qgscubicrasterresampler.h" + +#include +#include +#include +#include + +QgsRasterDrawer::QgsRasterDrawer( QgsRasterFace* input ): mInput( input ) +{ +} + +QgsRasterDrawer::~QgsRasterDrawer() +{ + //remove remaining memory in partinfos + /* + QMap::iterator partIt = mRasterPartInfos.begin(); + for ( ; partIt != mRasterPartInfos.end(); ++partIt ) + { + CPLFree( partIt.value().data ); + } + */ +} + +void QgsRasterDrawer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) +{ + QgsDebugMsg( "Entered" ); + if ( !p || !mInput || !viewPort || !theQgsMapToPixel ) + { + return; + } + + // last pipe filter has only 1 band + int bandNumber = 0; + startRasterRead( bandNumber, viewPort, theQgsMapToPixel ); + + //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; + + // We know that the output data type of last pipe filter is QImage data + //QgsRasterDataProvider::DataType rasterType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mGrayBand ); + + void* rasterData; + + // readNextRasterPart calcs and resets nCols, nRows, topLeftCol, topLeftRow + while ( readNextRasterPart( bandNumber, viewPort, nCols, nRows, + &rasterData, topLeftCol, topLeftRow ) ) + { + //create image + //QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied ); + + // TODO: the exact format should be read from input + QImage img(( uchar * ) rasterData, nCols, nRows, QImage::Format_ARGB32_Premultiplied ); + drawImage( p, viewPort, img, topLeftCol, topLeftRow ); + + // QImage does not delete data block passed to constructor + free( rasterData ); + } +} + +void QgsRasterDrawer::startRasterRead( int bandNumber, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel ) +{ + if ( !viewPort || !mapToPixel || !mInput ) + { + return; + } + + //remove any previous part on that band + removePartInfo( bandNumber ); + + //split raster into small portions if necessary + RasterPartInfo pInfo; + pInfo.nCols = viewPort->drawableAreaXDim; + pInfo.nRows = viewPort->drawableAreaYDim; + + //effective oversampling factors are different to global one because of rounding + //oversamplingX = (( double )pInfo.nCols * oversampling ) / viewPort->drawableAreaXDim; + //oversamplingY = (( double )pInfo.nRows * oversampling ) / viewPort->drawableAreaYDim; + + // TODO : we dont know oversampling (grid size) here - how to get totalMemoryUsage ? + //int totalMemoryUsage = pInfo.nCols * oversamplingX * pInfo.nRows * oversamplingY * mInput->dataTypeSize( bandNumber ); + int totalMemoryUsage = pInfo.nCols * pInfo.nRows * mInput->dataTypeSize( bandNumber ); + int parts = totalMemoryUsage / 100000000 + 1; + int nPartsPerDimension = sqrt( parts ); + pInfo.nColsPerPart = pInfo.nCols / nPartsPerDimension; + pInfo.nRowsPerPart = pInfo.nRows / nPartsPerDimension; + pInfo.currentCol = 0; + pInfo.currentRow = 0; + pInfo.data = 0; + pInfo.prj = 0; + mRasterPartInfos.insert( bandNumber, pInfo ); +} + +bool QgsRasterDrawer::readNextRasterPart( int bandNumber, QgsRasterViewPort* viewPort, + int& nCols, int& nRows, void** rasterData, int& topLeftCol, int& topLeftRow ) +{ + if ( !viewPort ) + { + return false; + } + + //get partinfo + QMap::iterator partIt = mRasterPartInfos.find( bandNumber ); + if ( partIt == mRasterPartInfos.end() ) + { + return false; + } + + RasterPartInfo& pInfo = partIt.value(); + + //remove last data block + // TODO: data are released somewhere else (check) + //free( pInfo.data ); + pInfo.data = 0; + delete pInfo.prj; + pInfo.prj = 0; + + //already at end + if ( pInfo.currentCol == pInfo.nCols && pInfo.currentRow == pInfo.nRows ) + { + return false; + } + + //read data block + nCols = qMin( pInfo.nColsPerPart, pInfo.nCols - pInfo.currentCol ); + nRows = qMin( pInfo.nRowsPerPart, pInfo.nRows - pInfo.currentRow ); + int typeSize = mInput->dataTypeSize( bandNumber ) / 8; + + //get subrectangle + QgsRectangle viewPortExtent = viewPort->mDrawnExtent; + double xmin = viewPortExtent.xMinimum() + pInfo.currentCol / ( double )pInfo.nCols * viewPortExtent.width(); + double xmax = viewPortExtent.xMinimum() + ( pInfo.currentCol + nCols ) / ( double )pInfo.nCols * viewPortExtent.width(); + double ymin = viewPortExtent.yMaximum() - ( pInfo.currentRow + nRows ) / ( double )pInfo.nRows * viewPortExtent.height(); + double ymax = viewPortExtent.yMaximum() - pInfo.currentRow / ( double )pInfo.nRows * viewPortExtent.height(); + QgsRectangle blockRect( xmin, ymin, xmax, ymax ); + + pInfo.data = mInput->readBlock( bandNumber, blockRect, nCols, nRows ); + + *rasterData = pInfo.data; + topLeftCol = pInfo.currentCol; + topLeftRow = pInfo.currentRow; + + pInfo.currentCol += nCols; + if ( pInfo.currentCol == pInfo.nCols && pInfo.currentRow + nRows == pInfo.nRows ) //end of raster + { + pInfo.currentRow = pInfo.nRows; + } + else if ( pInfo.currentCol == pInfo.nCols ) //start new row + { + pInfo.currentCol = 0; + pInfo.currentRow += pInfo.nRowsPerPart; + } + + return true; +} + +void QgsRasterDrawer::stopRasterRead( int bandNumber ) +{ + removePartInfo( bandNumber ); +} + +void QgsRasterDrawer::removePartInfo( int bandNumber ) +{ + QMap::iterator partIt = mRasterPartInfos.find( bandNumber ); + if ( partIt != mRasterPartInfos.end() ) + { + RasterPartInfo& pInfo = partIt.value(); + //CPLFree( pInfo.data ); + free( pInfo.data ); + delete pInfo.prj; + mRasterPartInfos.remove( bandNumber ); + } +} + +void QgsRasterDrawer::drawImage( QPainter* p, QgsRasterViewPort* viewPort, const QImage& img, int topLeftCol, int topLeftRow ) const +{ + if ( !p || !viewPort ) + { + return; + } + + //top left position in device coords + QPoint tlPoint = QPoint( viewPort->topLeftPoint.x() + topLeftCol, viewPort->topLeftPoint.y() + topLeftRow ); + + p->drawImage( tlPoint, img ); +} + diff --git a/src/core/raster/qgsrasterdrawer.h b/src/core/raster/qgsrasterdrawer.h new file mode 100644 index 000000000000..fad439410e06 --- /dev/null +++ b/src/core/raster/qgsrasterdrawer.h @@ -0,0 +1,136 @@ +/*************************************************************************** + qgsrasterdrawer.h + ------------------- + begin : June 2012 + copyright : (C) 2012 by Radim Blazek + email : radim dot blazek at gmail.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSRASTERDRAWER_H +#define QGSRASTERDRAWER_H + +//#include "qgsrasterdataprovider.h" +#include "qgsrasterface.h" + +#include + +class QPainter; +class QImage; +class QgsMapToPixel; +class QgsRasterResampler; +class QgsRasterProjector; +class QgsRasterTransparency; +class QgsRasterViewPort; + +class QDomElement; + +class QgsRasterDrawer +{ + public: + //Stores information about reading of a raster band. Columns and rows are in unsampled coordinates + struct RasterPartInfo + { + int currentCol; + int currentRow; + int nCols; + int nRows; + int nColsPerPart; + int nRowsPerPart; + void* data; //data (can be in oversampled/undersampled resolution) + QgsRasterProjector* prj; //raster projector (or 0 if no reprojection is done) + }; + + QgsRasterDrawer( QgsRasterFace* input ); + ~QgsRasterDrawer(); + + void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ); + + protected: + //inline double readValue( void *data, QgsRasterFace::DataType type, int index ); + + /**Start reading of raster band. Raster data can then be retrieved by calling readNextRasterPart until it returns false. + @param bandNumer number of raster band to read + @param viewPort describes raster position on screen + */ + void startRasterRead( int bandNumber, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel ); + /**Fetches next part of raster data + @param nCols number of columns on output device + @param nRows number of rows on output device + @param nColsRaster number of raster columns (different to nCols if oversamplingX != 1.0) + @param nRowsRaster number of raster rows (different to nRows if oversamplingY != 0)*/ + //bool readNextRasterPart( int bandNumber, QgsRasterViewPort* viewPort, + // int& nCols, int& nRows, + // int& nColsRaster, int& nRowsRaster, + // void** rasterData, int& topLeftCol, int& topLeftRow ); + bool readNextRasterPart( int bandNumber, QgsRasterViewPort* viewPort, + int& nCols, int& nRows, + void** rasterData, + int& topLeftCol, int& topLeftRow ); + /**Draws raster part + @param topLeftCol Left position relative to left border of viewport + @param topLeftRow Top position relative to top border of viewport*/ + void drawImage( QPainter* p, QgsRasterViewPort* viewPort, const QImage& img, int topLeftCol, int topLeftRow ) const; + void stopRasterRead( int bandNumber ); + + QgsRasterFace* mInput; + QMap mRasterPartInfos; + + private: + /**Remove part into and release memory*/ + void removePartInfo( int bandNumer ); +}; +/* +inline double QgsRasterDrawer::readValue( void *data, QgsRasterFace::DataType type, int index ) +{ + if ( !mProvider ) + { + return 0; + } + + if ( !data ) + { + return mProvider->noDataValue(); + } + + switch ( type ) + { + case QgsRasterFace::Byte: + return ( double )(( GByte * )data )[index]; + break; + case QgsRasterFace::UInt16: + return ( double )(( GUInt16 * )data )[index]; + break; + case QgsRasterFace::Int16: + return ( double )(( GInt16 * )data )[index]; + break; + case QgsRasterFace::UInt32: + return ( double )(( GUInt32 * )data )[index]; + break; + case QgsRasterFace::Int32: + return ( double )(( GInt32 * )data )[index]; + break; + case QgsRasterFace::Float32: + return ( double )(( float * )data )[index]; + break; + case QgsRasterFace::Float64: + return ( double )(( double * )data )[index]; + break; + default: + //QgsMessageLog::logMessage( tr( "GDAL data type %1 is not supported" ).arg( type ), tr( "Raster" ) ); + break; + } + + return mProvider->noDataValue(); +} +*/ + +#endif // QGSRASTERDRAWER_H diff --git a/src/core/raster/qgsrasterface.cpp b/src/core/raster/qgsrasterface.cpp new file mode 100644 index 000000000000..5b1618e409af --- /dev/null +++ b/src/core/raster/qgsrasterface.cpp @@ -0,0 +1,29 @@ +/*************************************************************************** + qgsrasterface.cpp - Internal raster processing modules interface + -------------------------------------- + Date : Jun 21, 2012 + Copyright : (C) 2012 by Radim Blazek + email : radim dot blazek at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsrasterface.h" +#include "qgslogger.h" + +#include + +QgsRasterFace::QgsRasterFace( QgsRasterFace * input ): mInput( input ) +{ +} + +QgsRasterFace::~QgsRasterFace() +{ +} diff --git a/src/core/raster/qgsrasterface.h b/src/core/raster/qgsrasterface.h new file mode 100644 index 000000000000..d40497e0cc29 --- /dev/null +++ b/src/core/raster/qgsrasterface.h @@ -0,0 +1,130 @@ +/*************************************************************************** + qgsrasterface.h - Internal raster processing modules interface + -------------------------------------- + Date : Jun 21, 2012 + Copyright : (C) 2012 by Radim Blazek + email : radim dot blazek at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSRASTERFACE_H +#define QGSRASTERFACE_H + +#include + +#include "qgsrectangle.h" + +/** \ingroup core + * Base class for processing modules. + */ +// TODO: inherit from QObject? QgsRasterDataProvider inherits already from QObject +class CORE_EXPORT QgsRasterFace //: public QObject +{ + + //Q_OBJECT + + public: + + // TODO: This is copy of QgsRasterDataProvider::DataType, the QgsRasterDataProvider + // should use this DataType + // This is modified copy of GDALDataType + enum DataType + { + /*! Unknown or unspecified type */ UnknownDataType = 0, + /*! Eight bit unsigned integer */ Byte = 1, + /*! Sixteen bit unsigned integer */ UInt16 = 2, + /*! Sixteen bit signed integer */ Int16 = 3, + /*! Thirty two bit unsigned integer */ UInt32 = 4, + /*! Thirty two bit signed integer */ Int32 = 5, + /*! Thirty two bit floating point */ Float32 = 6, + /*! Sixty four bit floating point */ Float64 = 7, + /*! Complex Int16 */ CInt16 = 8, + /*! Complex Int32 */ CInt32 = 9, + /*! Complex Float32 */ CFloat32 = 10, + /*! Complex Float64 */ CFloat64 = 11, + /*! Color, alpha, red, green, blue, 4 bytes */ ARGBDataType = 12, + TypeCount = 13 /* maximum type # + 1 */ + }; + + int typeSize( int dataType ) const + { + // modified copy from GDAL + switch ( dataType ) + { + case Byte: + return 8; + + case UInt16: + case Int16: + return 16; + + case UInt32: + case Int32: + case Float32: + case CInt16: + return 32; + + case Float64: + case CInt32: + case CFloat32: + return 64; + + case CFloat64: + return 128; + + case ARGBDataType: + return 32; + + default: + return 0; + } + } + int dataTypeSize( int bandNo ) const + { + return typeSize( dataType( bandNo ) ); + } + + + QgsRasterFace( QgsRasterFace * input = 0 ); + + virtual ~QgsRasterFace(); + + /** Returns data type for the band specified by number */ + virtual int dataType( int bandNo ) const + { + return UnknownDataType; + } + + // TODO + virtual double noDataValue() const { return 0; } + + /** Read block of data using given extent and size. + * Returns pointer to data. + * Caller is responsible to free the memory returned. + */ + virtual void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) + { + Q_UNUSED( bandNo ); Q_UNUSED( extent ); Q_UNUSED( width ); Q_UNUSED( height ); + return 0; + } + + void setInput( QgsRasterFace* input ) { mInput = input; } + + //protected: + // QgsRasterFace from used as input, data are read from it + QgsRasterFace* mInput; + + +}; + +#endif + + diff --git a/src/core/raster/qgsrasterlayer.cpp b/src/core/raster/qgsrasterlayer.cpp index e25a4dd0b987..73e7a3237c95 100644 --- a/src/core/raster/qgsrasterlayer.cpp +++ b/src/core/raster/qgsrasterlayer.cpp @@ -40,10 +40,10 @@ email : tim at linfiniti.com #include "qgscolorrampshader.h" //renderers -#include "qgspalettedrasterrenderer.h" -#include "qgsmultibandcolorrenderer.h" -#include "qgssinglebandcolordatarenderer.h" -#include "qgssinglebandpseudocolorrenderer.h" +//#include "qgspalettedrasterrenderer.h" +//#include "qgsmultibandcolorrenderer.h" +//#include "qgssinglebandcolordatarenderer.h" +//#include "qgssinglebandpseudocolorrenderer.h" #include "qgssinglebandgrayrenderer.h" #include @@ -823,7 +823,9 @@ void QgsRasterLayer::draw( QPainter * theQPainter, if ( mRenderer ) { - mRenderer->draw( theQPainter, theRasterViewPort, theQgsMapToPixel ); + //mRenderer->draw( theQPainter, theRasterViewPort, theQgsMapToPixel ); + QgsRasterDrawer drawer( mRenderer ); + drawer.draw( theQPainter, theRasterViewPort, theQgsMapToPixel ); } QgsDebugMsg( QString( "raster draw time (ms): %1" ).arg( time.elapsed() ) ); diff --git a/src/core/raster/qgsrasterlayer.h b/src/core/raster/qgsrasterlayer.h index ddf50ad45b1c..0543c6a8562b 100644 --- a/src/core/raster/qgsrasterlayer.h +++ b/src/core/raster/qgsrasterlayer.h @@ -41,6 +41,8 @@ #include "qgsrastershader.h" #include "qgscolorrampshader.h" #include "qgsrastershaderfunction.h" +#include "qgsrasterface.h" +#include "qgsrasterdrawer.h" #include "qgsrasterdataprovider.h" // diff --git a/src/core/raster/qgsrasterrenderer.cpp b/src/core/raster/qgsrasterrenderer.cpp index d58e3162f1c9..bc0a648d114b 100644 --- a/src/core/raster/qgsrasterrenderer.cpp +++ b/src/core/raster/qgsrasterrenderer.cpp @@ -31,7 +31,8 @@ #include #include -QgsRasterRenderer::QgsRasterRenderer( QgsRasterDataProvider* provider, const QString& type ): mProvider( provider ), +//QgsRasterRenderer::QgsRasterRenderer( QgsRasterFace* input, const QString& type ): mInput( input ), +QgsRasterRenderer::QgsRasterRenderer( QgsRasterFace* input, const QString& type ): QgsRasterFace( input ), mType( type ), mZoomedInResampler( 0 ), mZoomedOutResampler( 0 ), mOpacity( 1.0 ), mRasterTransparency( 0 ), mAlphaBand( -1 ), mInvertColor( false ), mMaxOversampling( 2.0 ) { @@ -40,11 +41,11 @@ QgsRasterRenderer::QgsRasterRenderer( QgsRasterDataProvider* provider, const QSt QgsRasterRenderer::~QgsRasterRenderer() { //remove remaining memory in partinfos - QMap::iterator partIt = mRasterPartInfos.begin(); - for ( ; partIt != mRasterPartInfos.end(); ++partIt ) - { - CPLFree( partIt.value().data ); - } + //QMap::iterator partIt = mRasterPartInfos.begin(); + //for ( ; partIt != mRasterPartInfos.end(); ++partIt ) + //{ + //CPLFree( partIt.value().data ); + //} delete mZoomedInResampler; delete mZoomedOutResampler; @@ -63,9 +64,10 @@ void QgsRasterRenderer::setZoomedOutResampler( QgsRasterResampler* r ) mZoomedOutResampler = r; } +/* void QgsRasterRenderer::startRasterRead( int bandNumber, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel, double& oversamplingX, double& oversamplingY ) { - if ( !viewPort || !mapToPixel || !mProvider ) + if ( !viewPort || !mapToPixel || !mInput ) { return; } @@ -78,13 +80,13 @@ void QgsRasterRenderer::startRasterRead( int bandNumber, QgsRasterViewPort* view if ( mZoomedInResampler || mZoomedOutResampler ) { - QgsRectangle providerExtent = mProvider->extent(); + QgsRectangle providerExtent = mInput->extent(); if ( viewPort->mSrcCRS.isValid() && viewPort->mDestCRS.isValid() && viewPort->mSrcCRS != viewPort->mDestCRS ) { QgsCoordinateTransform t( viewPort->mSrcCRS, viewPort->mDestCRS ); providerExtent = t.transformBoundingBox( providerExtent ); } - double pixelRatio = mapToPixel->mapUnitsPerPixel() / ( providerExtent.width() / mProvider->xSize() ); + double pixelRatio = mapToPixel->mapUnitsPerPixel() / ( providerExtent.width() / mInput->xSize() ); oversampling = ( pixelRatio > mMaxOversampling ) ? mMaxOversampling : pixelRatio; } @@ -103,7 +105,7 @@ void QgsRasterRenderer::startRasterRead( int bandNumber, QgsRasterViewPort* view oversamplingX = (( double )pInfo.nCols * oversampling ) / viewPort->drawableAreaXDim; oversamplingY = (( double )pInfo.nRows * oversampling ) / viewPort->drawableAreaYDim; - int totalMemoryUsage = pInfo.nCols * oversamplingX * pInfo.nRows * oversamplingY * mProvider->dataTypeSize( bandNumber ); + int totalMemoryUsage = pInfo.nCols * oversamplingX * pInfo.nRows * oversamplingY * mInput->dataTypeSize( bandNumber ); int parts = totalMemoryUsage / 100000000 + 1; int nPartsPerDimension = sqrt(( double ) parts ); pInfo.nColsPerPart = pInfo.nCols / nPartsPerDimension; @@ -147,7 +149,7 @@ bool QgsRasterRenderer::readNextRasterPart( int bandNumber, double oversamplingX //read data block nCols = qMin( pInfo.nColsPerPart, pInfo.nCols - pInfo.currentCol ); nRows = qMin( pInfo.nRowsPerPart, pInfo.nRows - pInfo.currentRow ); - int typeSize = mProvider->dataTypeSize( bandNumber ) / 8; + int typeSize = mInput->dataTypeSize( bandNumber ) / 8; //get subrectangle QgsRectangle viewPortExtent = viewPort->mDrawnExtent; @@ -160,7 +162,7 @@ bool QgsRasterRenderer::readNextRasterPart( int bandNumber, double oversamplingX if ( viewPort->mSrcCRS.isValid() && viewPort->mDestCRS.isValid() && viewPort->mSrcCRS != viewPort->mDestCRS ) { pInfo.prj = new QgsRasterProjector( viewPort->mSrcCRS, - viewPort->mDestCRS, blockRect, nRows, nCols, 0, 0, mProvider->extent() ); + viewPort->mDestCRS, blockRect, nRows, nCols, 0, 0, mInput->extent() ); // If we zoom out too much, projector srcRows / srcCols maybe 0, which can cause problems in providers if ( pInfo.prj->srcRows() <= 0 || pInfo.prj->srcCols() <= 0 ) @@ -183,8 +185,10 @@ bool QgsRasterRenderer::readNextRasterPart( int bandNumber, double oversamplingX nColsRaster = nCols * oversamplingX; nRowsRaster = nRows * oversamplingY; } - pInfo.data = VSIMalloc( typeSize * nColsRaster * nRowsRaster ); - mProvider->readBlock( bandNumber, blockRect, nColsRaster, nRowsRaster, pInfo.data ); + //pInfo.data = VSIMalloc( typeSize * nColsRaster * nRowsRaster ); + //mInput->readBlock( bandNumber, blockRect, nColsRaster, nRowsRaster, pInfo.data ); + pInfo.data = mInput->readBlock( bandNumber, blockRect, nColsRaster, nRowsRaster ); + *rasterData = pInfo.data; topLeftCol = pInfo.currentCol; topLeftRow = pInfo.currentRow; @@ -219,16 +223,17 @@ void QgsRasterRenderer::removePartInfo( int bandNumber ) mRasterPartInfos.remove( bandNumber ); } } +*/ bool QgsRasterRenderer::usesTransparency( QgsCoordinateReferenceSystem& srcSRS, QgsCoordinateReferenceSystem& dstSRS ) const { //transparency is always used if on-the-fly reprojection is enabled bool reprojectionEnabled = ( srcSRS.isValid() && dstSRS.isValid() && srcSRS != dstSRS ); - if ( !mProvider || reprojectionEnabled ) + if ( !mInput || reprojectionEnabled ) { return true; } - return ( mAlphaBand > 0 || ( mRasterTransparency && !mRasterTransparency->isEmpty( mProvider->noDataValue() ) ) || !doubleNear( mOpacity, 1.0 ) ); + return ( mAlphaBand > 0 || ( mRasterTransparency && !mRasterTransparency->isEmpty( mInput->noDataValue() ) ) || !doubleNear( mOpacity, 1.0 ) ); } void QgsRasterRenderer::setRasterTransparency( QgsRasterTransparency* t ) @@ -237,6 +242,7 @@ void QgsRasterRenderer::setRasterTransparency( QgsRasterTransparency* t ) mRasterTransparency = t; } +/* void QgsRasterRenderer::drawImage( QPainter* p, QgsRasterViewPort* viewPort, const QImage& img, int topLeftCol, int topLeftRow, int nCols, int nRows, double oversamplingX, double oversamplingY ) const { @@ -317,6 +323,7 @@ void QgsRasterRenderer::projectImage( const QImage& srcImg, QImage& dstImage, Qg } } } +*/ void QgsRasterRenderer::_writeXML( QDomDocument& doc, QDomElement& rasterRendererElem ) const { diff --git a/src/core/raster/qgsrasterrenderer.h b/src/core/raster/qgsrasterrenderer.h index 672bf7462cf0..64618e10b4c3 100644 --- a/src/core/raster/qgsrasterrenderer.h +++ b/src/core/raster/qgsrasterrenderer.h @@ -18,6 +18,7 @@ #ifndef QGSRASTERRENDERER_H #define QGSRASTERRENDERER_H +#include "qgsrasterface.h" #include "qgsrasterdataprovider.h" #include @@ -30,27 +31,20 @@ struct QgsRasterViewPort; class QDomElement; -class CORE_EXPORT QgsRasterRenderer +class CORE_EXPORT QgsRasterRenderer : public QgsRasterFace { public: - //Stores information about reading of a raster band. Columns and rows are in unsampled coordinates - struct RasterPartInfo - { - int currentCol; - int currentRow; - int nCols; - int nRows; - int nColsPerPart; - int nRowsPerPart; - void* data; //data (can be in oversampled/undersampled resolution) - QgsRasterProjector* prj; //raster projector (or 0 if no reprojection is done) - }; - - QgsRasterRenderer( QgsRasterDataProvider* provider, const QString& type ); + QgsRasterRenderer( QgsRasterFace* input, const QString& type ); virtual ~QgsRasterRenderer(); virtual QString type() const { return mType; } - virtual void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) = 0; + //virtual void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) = 0; + + virtual void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) + { + Q_UNUSED( bandNo ); Q_UNUSED( extent ); Q_UNUSED( width ); Q_UNUSED( height ); + return 0; + } bool usesTransparency( QgsCoordinateReferenceSystem& srcSRS, QgsCoordinateReferenceSystem& dstSRS ) const; @@ -86,55 +80,19 @@ class CORE_EXPORT QgsRasterRenderer void readXML( const QDomElement& rendererElem ); protected: - inline double readValue( void *data, QgsRasterDataProvider::DataType type, int index ); - - /**Start reading of raster band. Raster data can then be retrieved by calling readNextRasterPart until it returns false. - @param bandNumber number of raster band to read - @param viewPort describes raster position on screen - @param mapToPixel transform map to pixel - @param oversamplingX out: oversampling rate in x-direction - @param oversamplingY out: oversampling rate in y-direction*/ - void startRasterRead( int bandNumber, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel, double& oversamplingX, double& oversamplingY ); - /**Fetches next part of raster data - @param bandNumber number of raster band to read - @param oversamplingX oversampling rate in x-direction - @param oversamplingY oversampling rate in y-direction - @param viewPort view port - @param nCols number of columns on output device - @param nRows number of rows on output device - @param nColsRaster number of raster columns (different to nCols if oversamplingX != 1.0) - @param nRowsRaster number of raster rows (different to nRows if oversamplingY != 0) - @param rasterData raster data - @param topLeftCol Left position relative to left border of viewport - @param topLeftRow Top position relative to top border of viewport*/ - bool readNextRasterPart( int bandNumber, double oversamplingX, double oversamplingY, QgsRasterViewPort* viewPort, int& nCols, int& nRows, - int& nColsRaster, int& nRowsRaster, void** rasterData, int& topLeftCol, int& topLeftRow ); - /**Draws raster part - @param p the painter - @param viewPort view port - @param img image - @param topLeftCol Left position relative to left border of viewport - @param topLeftRow Top position relative to top border of viewport - @param nCols number of columns - @param nRows number of rows - @param oversamplingX oversampling rate in x-direction - @param oversamplingY oversampling rate in y-direction - */ - void drawImage( QPainter* p, QgsRasterViewPort* viewPort, const QImage& img, int topLeftCol, int topLeftRow, - int nCols, int nRows, double oversamplingX, double oversamplingY ) const; - void stopRasterRead( int bandNumber ); + inline double readValue( void *data, QgsRasterFace::DataType type, int index ); /**Write upper class info into rasterrenderer element (called by writeXML method of subclasses)*/ void _writeXML( QDomDocument& doc, QDomElement& rasterRendererElem ) const; - QgsRasterDataProvider* mProvider; + QgsRasterFace* mProvider; QString mType; /**Resampler used if screen resolution is higher than raster resolution (zoomed in). 0 means no resampling (nearest neighbour)*/ QgsRasterResampler* mZoomedInResampler; /**Resampler used if raster resolution is higher than raster resolution (zoomed out). 0 mean no resampling (nearest neighbour)*/ QgsRasterResampler* mZoomedOutResampler; - QMap mRasterPartInfos; + //QMap mRasterPartInfos; /**Global alpha value (0-1)*/ double mOpacity; @@ -155,39 +113,41 @@ class CORE_EXPORT QgsRasterRenderer void projectImage( const QImage& srcImg, QImage& dstImage, QgsRasterProjector* prj ) const; }; -inline double QgsRasterRenderer::readValue( void *data, QgsRasterDataProvider::DataType type, int index ) +inline double QgsRasterRenderer::readValue( void *data, QgsRasterFace::DataType type, int index ) { - if ( !mProvider ) + if ( !mInput ) { return 0; } if ( !data ) { - return mProvider->noDataValue(); + // TODO + //return mInput->noDataValue(); + return 0; } switch ( type ) { - case QgsRasterDataProvider::Byte: + case QgsRasterFace::Byte: return ( double )(( GByte * )data )[index]; break; - case QgsRasterDataProvider::UInt16: + case QgsRasterFace::UInt16: return ( double )(( GUInt16 * )data )[index]; break; - case QgsRasterDataProvider::Int16: + case QgsRasterFace::Int16: return ( double )(( GInt16 * )data )[index]; break; - case QgsRasterDataProvider::UInt32: + case QgsRasterFace::UInt32: return ( double )(( GUInt32 * )data )[index]; break; - case QgsRasterDataProvider::Int32: + case QgsRasterFace::Int32: return ( double )(( GInt32 * )data )[index]; break; - case QgsRasterDataProvider::Float32: + case QgsRasterFace::Float32: return ( double )(( float * )data )[index]; break; - case QgsRasterDataProvider::Float64: + case QgsRasterFace::Float64: return ( double )(( double * )data )[index]; break; default: @@ -195,7 +155,7 @@ inline double QgsRasterRenderer::readValue( void *data, QgsRasterDataProvider::D break; } - return mProvider->noDataValue(); + return mInput->noDataValue(); } #endif // QGSRASTERRENDERER_H diff --git a/src/core/raster/qgsrasterrendererregistry.h b/src/core/raster/qgsrasterrendererregistry.h index 86d22f65fbaf..d5cc0b0b3f84 100644 --- a/src/core/raster/qgsrasterrendererregistry.h +++ b/src/core/raster/qgsrasterrendererregistry.h @@ -23,12 +23,13 @@ #include class QDomElement; -class QgsRasterDataProvider; +//class QgsRasterDataProvider; +class QgsRasterFace; class QgsRasterLayer; class QgsRasterRenderer; class QgsRasterRendererWidget; -typedef QgsRasterRenderer*( *QgsRasterRendererCreateFunc )( const QDomElement&, QgsRasterDataProvider* provider ); +typedef QgsRasterRenderer*( *QgsRasterRendererCreateFunc )( const QDomElement&, QgsRasterFace* input ); typedef QgsRasterRendererWidget*( *QgsRasterRendererWidgetCreateFunc )( QgsRasterLayer* ); struct CORE_EXPORT QgsRasterRendererRegistryEntry diff --git a/src/core/raster/qgssinglebandcolordatarenderer.cpp b/src/core/raster/qgssinglebandcolordatarenderer.cpp index 28ae943c5e64..5bdb91554314 100644 --- a/src/core/raster/qgssinglebandcolordatarenderer.cpp +++ b/src/core/raster/qgssinglebandcolordatarenderer.cpp @@ -21,8 +21,8 @@ #include #include -QgsSingleBandColorDataRenderer::QgsSingleBandColorDataRenderer( QgsRasterDataProvider* provider, int band ): - QgsRasterRenderer( provider, "singlebandcolordata" ), mBand( band ) +QgsSingleBandColorDataRenderer::QgsSingleBandColorDataRenderer( QgsRasterFace* input, int band ): + QgsRasterRenderer( input, "singlebandcolordata" ), mBand( band ) { } @@ -31,7 +31,7 @@ QgsSingleBandColorDataRenderer::~QgsSingleBandColorDataRenderer() { } -QgsRasterRenderer* QgsSingleBandColorDataRenderer::create( const QDomElement& elem, QgsRasterDataProvider* provider ) +QgsRasterRenderer* QgsSingleBandColorDataRenderer::create( const QDomElement& elem, QgsRasterFace* input ) { if ( elem.isNull() ) { @@ -39,20 +39,20 @@ QgsRasterRenderer* QgsSingleBandColorDataRenderer::create( const QDomElement& el } int band = elem.attribute( "band", "-1" ).toInt(); - QgsRasterRenderer* r = new QgsSingleBandColorDataRenderer( provider, band ); + QgsRasterRenderer* r = new QgsSingleBandColorDataRenderer( input, band ); r->readXML( elem ); return r; } -void QgsSingleBandColorDataRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) +void * QgsSingleBandColorDataRenderer::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { - if ( !p || !mProvider || !viewPort || !theQgsMapToPixel ) + if ( !mInput ) { - return; + return 0; } double oversamplingX, oversamplingY; - startRasterRead( mBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); + //startRasterRead( mBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); //number of cols/rows in output pixels int nCols = 0; @@ -64,24 +64,29 @@ void QgsSingleBandColorDataRenderer::draw( QPainter* p, QgsRasterViewPort* viewP int topLeftCol = 0; int topLeftRow = 0; int currentRasterPos; - void* rasterData; - bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS ); + //bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS ); + bool hasTransparency = false; + + QgsRasterFace::DataType rasterType = ( QgsRasterFace::DataType )mInput->dataType( mBand ); + + + void* rasterData = mInput->readBlock( bandNo, extent, width, height ); - while ( readNextRasterPart( mBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, &rasterData, topLeftCol, topLeftRow ) ) + currentRasterPos = 0; + QImage img( width, height, QImage::Format_ARGB32 ); + uchar* scanLine = 0; + for ( int i = 0; i < height; ++i ) { - currentRasterPos = 0; - QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32 ); - uchar* scanLine = 0; - for ( int i = 0; i < nRasterRows; ++i ) + scanLine = img.scanLine( i ); + if ( !hasTransparency ) { - scanLine = img.scanLine( i ); - if ( !hasTransparency ) - { - memcpy( scanLine, &((( uint* )rasterData )[currentRasterPos] ), nCols * 4 ); - currentRasterPos += nRasterCols; - } - else + memcpy( scanLine, &((( uint* )rasterData )[currentRasterPos] ), nCols * 4 ); + currentRasterPos += nRasterCols; + } + else + { + for ( int j = 0; j < width; ++j ) { QRgb pixelColor; double alpha = 255.0; @@ -95,11 +100,11 @@ void QgsSingleBandColorDataRenderer::draw( QPainter* p, QgsRasterViewPort* viewP } } } - - drawImage( p, viewPort, img, topLeftCol, topLeftRow, nCols, nRows, oversamplingX, oversamplingY ); } + VSIFree( rasterData ); - stopRasterRead( mBand ); + void * data = VSIMalloc( img.byteCount() ); + return memcpy( data, img.bits(), img.byteCount() ); } void QgsSingleBandColorDataRenderer::writeXML( QDomDocument& doc, QDomElement& parentElem ) const diff --git a/src/core/raster/qgssinglebandcolordatarenderer.h b/src/core/raster/qgssinglebandcolordatarenderer.h index ce21e8e3de10..aae77ea7536d 100644 --- a/src/core/raster/qgssinglebandcolordatarenderer.h +++ b/src/core/raster/qgssinglebandcolordatarenderer.h @@ -25,12 +25,14 @@ class QDomElement; class CORE_EXPORT QgsSingleBandColorDataRenderer: public QgsRasterRenderer { public: - QgsSingleBandColorDataRenderer( QgsRasterDataProvider* provider, int band ); + QgsSingleBandColorDataRenderer( QgsRasterFace* input, int band ); ~QgsSingleBandColorDataRenderer(); - static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterDataProvider* provider ); + static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterFace* input ); - virtual void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ); + //virtual void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ); + + void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height ); void writeXML( QDomDocument& doc, QDomElement& parentElem ) const; diff --git a/src/core/raster/qgssinglebandgrayrenderer.cpp b/src/core/raster/qgssinglebandgrayrenderer.cpp index bf0c01126646..7d3e4f960117 100644 --- a/src/core/raster/qgssinglebandgrayrenderer.cpp +++ b/src/core/raster/qgssinglebandgrayrenderer.cpp @@ -22,8 +22,8 @@ #include #include -QgsSingleBandGrayRenderer::QgsSingleBandGrayRenderer( QgsRasterDataProvider* provider, int grayBand ): - QgsRasterRenderer( provider, "singlebandgray" ), mGrayBand( grayBand ), mContrastEnhancement( 0 ) +QgsSingleBandGrayRenderer::QgsSingleBandGrayRenderer( QgsRasterFace* input, int grayBand ): + QgsRasterRenderer( input, "singlebandgray" ), mGrayBand( grayBand ), mContrastEnhancement( 0 ) { } @@ -32,7 +32,7 @@ QgsSingleBandGrayRenderer::~QgsSingleBandGrayRenderer() delete mContrastEnhancement; } -QgsRasterRenderer* QgsSingleBandGrayRenderer::create( const QDomElement& elem, QgsRasterDataProvider* provider ) +QgsRasterRenderer* QgsSingleBandGrayRenderer::create( const QDomElement& elem, QgsRasterFace* input ) { if ( elem.isNull() ) { @@ -40,14 +40,14 @@ QgsRasterRenderer* QgsSingleBandGrayRenderer::create( const QDomElement& elem, Q } int grayBand = elem.attribute( "grayBand", "-1" ).toInt(); - QgsSingleBandGrayRenderer* r = new QgsSingleBandGrayRenderer( provider, grayBand ); + QgsSingleBandGrayRenderer* r = new QgsSingleBandGrayRenderer( input, grayBand ); r->readXML( elem ); QDomElement contrastEnhancementElem = elem.firstChildElement( "contrastEnhancement" ); if ( !contrastEnhancementElem.isNull() ) { QgsContrastEnhancement* ce = new QgsContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )( - provider->dataType( grayBand ) ) ) ; + input->dataType( grayBand ) ) ) ; ce->readXML( contrastEnhancementElem ); r->setContrastEnhancement( ce ); } @@ -60,115 +60,113 @@ void QgsSingleBandGrayRenderer::setContrastEnhancement( QgsContrastEnhancement* mContrastEnhancement = ce; } -void QgsSingleBandGrayRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) +//void QgsSingleBandGrayRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) +void * QgsSingleBandGrayRenderer::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { - if ( !p || !mProvider || !viewPort || !theQgsMapToPixel ) + //if ( !mInput || !viewPort || !theQgsMapToPixel ) + if ( !mInput ) { - return; + return 0; } - double oversamplingX, oversamplingY; - startRasterRead( mGrayBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); - if ( mAlphaBand > 0 && mGrayBand != mAlphaBand ) - { - startRasterRead( mAlphaBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); - } + //double oversamplingX, oversamplingY; + //startRasterRead( mGrayBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); + //if ( mAlphaBand > 0 && mGrayBand != mAlphaBand ) + //{ + //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; - QgsRasterDataProvider::DataType rasterType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mGrayBand ); - QgsRasterDataProvider::DataType alphaType = QgsRasterDataProvider::UnknownDataType; - if ( mAlphaBand > 0 ) - { - alphaType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mAlphaBand ); - } - void* rasterData; - void* alphaData = 0; + //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; + + QgsRasterFace::DataType rasterType = ( QgsRasterFace::DataType )mInput->dataType( mGrayBand ); + //QgsRasterFace::DataType alphaType = QgsRasterFace::UnknownDataType; + //if ( mAlphaBand > 0 ) + //{ + //alphaType = ( QgsRasterFace::DataType )mInput->dataType( mAlphaBand ); + //} + + void* rasterData = mInput->readBlock( mGrayBand, extent, width, height ); + //void* alphaData; double currentAlpha = mOpacity; int grayVal; QRgb myDefaultColor = qRgba( 0, 0, 0, 0 ); - - while ( readNextRasterPart( mGrayBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, - &rasterData, topLeftCol, topLeftRow ) ) + //if ( mAlphaBand > 0 && mGrayBand != mAlphaBand ) + //{ + //readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, + //&alphaData, topLeftCol, topLeftRow ); + //} + //else if ( mAlphaBand > 0 ) + //{ + //alphaData = rasterData; + //} + + //create image + QImage img( width, height, QImage::Format_ARGB32_Premultiplied ); + QRgb* imageScanLine = 0; + int currentRasterPos = 0; + + for ( int i = 0; i < height; ++i ) { - if ( mAlphaBand > 0 && mGrayBand != mAlphaBand ) + imageScanLine = ( QRgb* )( img.scanLine( i ) ); + for ( int j = 0; j < width; ++j ) { - readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, - &alphaData, topLeftCol, topLeftRow ); - } - else if ( mAlphaBand > 0 ) - { - alphaData = rasterData; - } + grayVal = readValue( rasterData, rasterType, currentRasterPos ); - - //create image - QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied ); - QRgb* imageScanLine = 0; - int currentRasterPos = 0; - - for ( int i = 0; i < nRasterRows; ++i ) - { - imageScanLine = ( QRgb* )( img.scanLine( i ) ); - for ( int j = 0; j < nRasterCols; ++j ) + //alpha + currentAlpha = mOpacity; + if ( mRasterTransparency ) { - grayVal = readValue( rasterData, rasterType, currentRasterPos ); - - //alpha - currentAlpha = mOpacity; - if ( mRasterTransparency ) - { - currentAlpha = mRasterTransparency->alphaValue( grayVal, mOpacity * 255 ) / 255.0; - } - if ( mAlphaBand > 0 ) - { - currentAlpha *= ( readValue( alphaData, alphaType, currentRasterPos ) / 255.0 ); - } + currentAlpha = mRasterTransparency->alphaValue( grayVal, mOpacity * 255 ) / 255.0; + } + if ( mAlphaBand > 0 ) + { + currentAlpha *= ( readValue( alphaData, alphaType, currentRasterPos ) / 255.0 ); + } - if ( mContrastEnhancement ) + if ( mContrastEnhancement ) + { + if ( !mContrastEnhancement->isValueInDisplayableRange( grayVal ) ) { - if ( !mContrastEnhancement->isValueInDisplayableRange( grayVal ) ) - { - imageScanLine[ j ] = myDefaultColor; - ++currentRasterPos; - continue; - } - grayVal = mContrastEnhancement->enhanceContrast( grayVal ); + imageScanLine[ j ] = myDefaultColor; + ++currentRasterPos; + continue; } + grayVal = mContrastEnhancement->enhanceContrast( grayVal ); + } - if ( mInvertColor ) - { - grayVal = 255 - grayVal; - } + if ( mInvertColor ) + { + grayVal = 255 - grayVal; + } - if ( doubleNear( currentAlpha, 1.0 ) ) - { - imageScanLine[j] = qRgba( grayVal, grayVal, grayVal, 255 ); - } - else - { - imageScanLine[j] = qRgba( currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * 255 ); - } - ++currentRasterPos; + if ( doubleNear( currentAlpha, 1.0 ) ) + { + imageScanLine[j] = qRgba( grayVal, grayVal, grayVal, 255 ); } + else + { + imageScanLine[j] = qRgba( currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * 255 ); + } + ++currentRasterPos; } - - drawImage( p, viewPort, img, topLeftCol, topLeftRow, nCols, nRows, oversamplingX, oversamplingY ); } - stopRasterRead( mGrayBand ); - if ( mAlphaBand > 0 && mGrayBand != mAlphaBand ) - { - stopRasterRead( mAlphaBand ); - } + VSIFree( rasterData ); + + // TODO: howto get image data without memcpy? + // TODO: byteCount() added in 4.6, QGIS requirement is Qt >= 4.4.0 + void * data = VSIMalloc( img.byteCount() ); + + return memcpy( data, img.bits(), img.byteCount() ); } void QgsSingleBandGrayRenderer::writeXML( QDomDocument& doc, QDomElement& parentElem ) const diff --git a/src/core/raster/qgssinglebandgrayrenderer.h b/src/core/raster/qgssinglebandgrayrenderer.h index f86cdb7409d9..97c34fbc4e4d 100644 --- a/src/core/raster/qgssinglebandgrayrenderer.h +++ b/src/core/raster/qgssinglebandgrayrenderer.h @@ -26,12 +26,15 @@ class QDomElement; class CORE_EXPORT QgsSingleBandGrayRenderer: public QgsRasterRenderer { public: - QgsSingleBandGrayRenderer( QgsRasterDataProvider* provider, int grayBand ); + QgsSingleBandGrayRenderer( QgsRasterFace* input, int grayBand ); ~QgsSingleBandGrayRenderer(); - static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterDataProvider* provider ); + //static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterDataProvider* provider ); + static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterFace* input ); - virtual void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ); + //virtual void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ); + + void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height ); int grayBand() const { return mGrayBand; } void setGrayBand( int band ) { mGrayBand = band; } diff --git a/src/core/raster/qgssinglebandpseudocolorrenderer.cpp b/src/core/raster/qgssinglebandpseudocolorrenderer.cpp index b394a50612c2..2190afa13b9a 100644 --- a/src/core/raster/qgssinglebandpseudocolorrenderer.cpp +++ b/src/core/raster/qgssinglebandpseudocolorrenderer.cpp @@ -23,8 +23,8 @@ #include #include -QgsSingleBandPseudoColorRenderer::QgsSingleBandPseudoColorRenderer( QgsRasterDataProvider* provider, int band, QgsRasterShader* shader ): - QgsRasterRenderer( provider, "singlebandpseudocolor" ), mShader( shader ), mBand( band ) +QgsSingleBandPseudoColorRenderer::QgsSingleBandPseudoColorRenderer( QgsRasterFace* input, int band, QgsRasterShader* shader ): + QgsRasterRenderer( input, "singlebandpseudocolor" ), mShader( shader ), mBand( band ) { } @@ -39,7 +39,7 @@ void QgsSingleBandPseudoColorRenderer::setShader( QgsRasterShader* shader ) mShader = shader; } -QgsRasterRenderer* QgsSingleBandPseudoColorRenderer::create( const QDomElement& elem, QgsRasterDataProvider* provider ) +QgsRasterRenderer* QgsSingleBandPseudoColorRenderer::create( const QDomElement& elem, QgsRasterFace* input ) { if ( elem.isNull() ) { @@ -54,30 +54,30 @@ QgsRasterRenderer* QgsSingleBandPseudoColorRenderer::create( const QDomElement& shader = new QgsRasterShader(); shader->readXML( rasterShaderElem ); } - QgsRasterRenderer* r = new QgsSingleBandPseudoColorRenderer( provider, band, shader ); + QgsRasterRenderer* r = new QgsSingleBandPseudoColorRenderer( input, band, shader ); r->readXML( elem ); return r; } -void QgsSingleBandPseudoColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) +void * QgsSingleBandPseudoColorRenderer::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { - if ( !p || !mProvider || !viewPort || !theQgsMapToPixel || !mShader ) + if ( !mInput || !mShader ) { - return; + return 0; } - 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 ); - } + //double oversamplingX, oversamplingY; + //QgsRasterFace::DataType transparencyType = QgsRasterFace::UnknownDataType; + //if ( mAlphaBand > 0 ) + //{ + //transparencyType = ( QgsRasterFace::DataType )mInput->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; @@ -88,79 +88,75 @@ void QgsSingleBandPseudoColorRenderer::draw( QPainter* p, QgsRasterViewPort* vie //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 ); + QgsRasterFace::DataType rasterType = ( QgsRasterFace::DataType )mInput->dataType( mBand ); + + void* rasterData = mInput->readBlock( 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( viewPort->mSrcCRS, viewPort->mDestCRS ); - - while ( readNextRasterPart( mBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, - &rasterData, topLeftCol, topLeftRow ) ) + //bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS ); + bool hasTransparency = false; + + //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( width, height, QImage::Format_ARGB32_Premultiplied ); + QRgb* imageScanLine = 0; + double val = 0; + + int currentRasterPos = 0; + for ( int i = 0; i < height; ++i ) { - if ( mAlphaBand > 0 && mAlphaBand != mBand ) - { - readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, - &transparencyData, topLeftCol, topLeftRow ); - } - else if ( mAlphaBand == mBand ) + imageScanLine = ( QRgb* )( img.scanLine( i ) ); + for ( int j = 0; j < width; ++j ) { - transparencyData = rasterData; - } - - //create image - QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied ); - QRgb* imageScanLine = 0; - double val = 0; + val = readValue( rasterData, rasterType, currentRasterPos ); + if ( !mShader->shade( val, &red, &green, &blue ) ) + { + imageScanLine[j] = myDefaultColor; + ++currentRasterPos; + continue; + } - int currentRasterPos = 0; - for ( int i = 0; i < nRasterRows; ++i ) - { - imageScanLine = ( QRgb* )( img.scanLine( i ) ); - for ( int j = 0; j < nRasterCols; ++j ) + if ( !hasTransparency ) { - val = readValue( rasterData, rasterType, currentRasterPos ); - if ( !mShader->shade( val, &red, &green, &blue ) ) + imageScanLine[j] = qRgba( red, green, blue, 255 ); + } + else + { + //opacity + currentOpacity = mOpacity; + if ( mRasterTransparency ) { - imageScanLine[j] = myDefaultColor; - ++currentRasterPos; - continue; + currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0; } + //if ( mAlphaBand > 0 ) + //{ + //currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 ); + //} - 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; + 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 ); - } + VSIFree( rasterData ); + + void * data = VSIMalloc( img.byteCount() ); + return memcpy( data, img.bits(), img.byteCount() ); } void QgsSingleBandPseudoColorRenderer::writeXML( QDomDocument& doc, QDomElement& parentElem ) const diff --git a/src/core/raster/qgssinglebandpseudocolorrenderer.h b/src/core/raster/qgssinglebandpseudocolorrenderer.h index cb7f0c7f94bc..e21268315062 100644 --- a/src/core/raster/qgssinglebandpseudocolorrenderer.h +++ b/src/core/raster/qgssinglebandpseudocolorrenderer.h @@ -27,12 +27,14 @@ class CORE_EXPORT QgsSingleBandPseudoColorRenderer: public QgsRasterRenderer { public: /**Note: takes ownership of QgsRasterShader*/ - QgsSingleBandPseudoColorRenderer( QgsRasterDataProvider* provider, int band, QgsRasterShader* shader ); + QgsSingleBandPseudoColorRenderer( QgsRasterFace* input, int band, QgsRasterShader* shader ); ~QgsSingleBandPseudoColorRenderer(); - static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterDataProvider* provider ); + static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterFace* input ); - virtual void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ); + //virtual void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ); + + void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height ); /**Takes ownership of the shader*/ void setShader( QgsRasterShader* shader ); diff --git a/src/providers/gdal/qgsgdalprovider.cpp b/src/providers/gdal/qgsgdalprovider.cpp index e4b803ba3d66..66fb6dee978c 100644 --- a/src/providers/gdal/qgsgdalprovider.cpp +++ b/src/providers/gdal/qgsgdalprovider.cpp @@ -805,6 +805,11 @@ void QgsGdalProvider::readBlock( int theBandNo, QgsRectangle const & theExtent, return; } +//void * QgsGdalProvider::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) +//{ +// return 0; +//} + // this is old version which was using GDALWarpOperation, unfortunately // it may be very slow on large datasets #if 0 diff --git a/src/providers/gdal/qgsgdalprovider.h b/src/providers/gdal/qgsgdalprovider.h index 71e857837072..8c4adaa1b2cb 100644 --- a/src/providers/gdal/qgsgdalprovider.h +++ b/src/providers/gdal/qgsgdalprovider.h @@ -203,6 +203,8 @@ class QgsGdalProvider : public QgsRasterDataProvider void readBlock( int bandNo, int xBlock, int yBlock, void *data ); void readBlock( int bandNo, QgsRectangle const & viewExtent, int width, int height, void *data ); + //void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height ); + double noDataValue() const; void computeMinMax( int bandNo ); double minimumValue( int bandNo ) const;