Skip to content

Commit

Permalink
Keep raster renderer parts aligned to pixel boundaries of unsampled r…
Browse files Browse the repository at this point in the history
…asters (to avoid overlaps or white stripes in large prints
  • Loading branch information
mhugent committed Jan 21, 2012
1 parent 15fe4da commit f940c5f
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 41 deletions.
19 changes: 14 additions & 5 deletions src/core/raster/qgsmultibandcolorrenderer.cpp
Expand Up @@ -66,15 +66,24 @@ void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
void* greenData = 0;
void* blueData = 0;
void* alphaData = 0;
int nCols, nRows, topLeftCol, topLeftRow;
//number of cols/rows in output pixels
int nCols = 0;
int nRows = 0;
//number of raster cols/rows with oversampling
int nRasterCols = 0;
int nRasterRows = 0;
//shift to top left point for the raster part
int topLeftCol = 0;
int topLeftRow = 0;

bool readSuccess = true;
while ( true )
{
QSet<int>::const_iterator bandIt = bands.constBegin();
for ( ; bandIt != bands.constEnd(); ++bandIt )
{
readSuccess = readSuccess && readNextRasterPart( *bandIt, viewPort, nCols, nRows, &bandData[*bandIt], topLeftCol, topLeftRow );
readSuccess = readSuccess && readNextRasterPart( *bandIt, oversamplingX, oversamplingY, viewPort, nCols, nRows,
nRasterCols, nRasterRows, &bandData[*bandIt], topLeftCol, topLeftRow );
}

if ( !readSuccess )
Expand All @@ -90,16 +99,16 @@ void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
alphaData = bandData[mAlphaBand];
}

QImage img( nCols, nRows, QImage::Format_ARGB32_Premultiplied );
QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );
QRgb* imageScanLine = 0;
int currentRasterPos = 0;
int redVal, greenVal, blueVal;
double currentOpacity = mOpacity; //opacity (between 0 and 1)

for ( int i = 0; i < nRows; ++i )
for ( int i = 0; i < nRasterRows; ++i )
{
imageScanLine = ( QRgb* )( img.scanLine( i ) );
for ( int j = 0; j < nCols; ++j )
for ( int j = 0; j < nRasterCols; ++j )
{
redVal = readValue( redData, redType, currentRasterPos );
greenVal = readValue( greenData, greenType, currentRasterPos );
Expand Down
17 changes: 12 additions & 5 deletions src/core/raster/qgspalettedrasterrenderer.cpp
Expand Up @@ -53,8 +53,13 @@ void QgsPalettedRasterRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
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;
Expand All @@ -66,27 +71,29 @@ void QgsPalettedRasterRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS );
void* transparencyData;

while ( readNextRasterPart( mBandNumber, viewPort, nCols, nRows, &rasterData, topLeftCol, topLeftRow ) )
while ( readNextRasterPart( mBandNumber, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
&rasterData, topLeftCol, topLeftRow ) )
{
if ( mAlphaBand > 0 && mAlphaBand != mBandNumber )
{
readNextRasterPart( mAlphaBand, viewPort, nCols, nRows, &transparencyData, topLeftCol, topLeftRow );
readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
&transparencyData, topLeftCol, topLeftRow );
}
else if ( mAlphaBand == mBandNumber )
{
transparencyData = rasterData;
}

//create image
QImage img( nCols, nRows, QImage::Format_ARGB32_Premultiplied );
QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );
QRgb* imageScanLine = 0;
int val = 0;
currentRasterPos = 0;

for ( int i = 0; i < nRows; ++i )
for ( int i = 0; i < nRasterRows; ++i )
{
imageScanLine = ( QRgb* )( img.scanLine( i ) );
for ( int j = 0; j < nCols; ++j )
for ( int j = 0; j < nRasterCols; ++j )
{
val = readValue( rasterData, rasterType, currentRasterPos );
if ( !hasTransparency )
Expand Down
24 changes: 13 additions & 11 deletions src/core/raster/qgsrasterrenderer.cpp
Expand Up @@ -86,14 +86,14 @@ void QgsRasterRenderer::startRasterRead( int bandNumber, QgsRasterViewPort* view

//split raster into small portions if necessary
RasterPartInfo pInfo;
pInfo.nCols = viewPort->drawableAreaXDim * oversampling;
pInfo.nRows = viewPort->drawableAreaYDim * oversampling;
pInfo.nCols = viewPort->drawableAreaXDim;
pInfo.nRows = viewPort->drawableAreaYDim;

//effective oversampling factors are different to global one because of rounding
oversamplingX = ( double )pInfo.nCols / viewPort->drawableAreaXDim;
oversamplingY = ( double )pInfo.nRows / viewPort->drawableAreaYDim;
oversamplingX = (( double )pInfo.nCols * oversampling ) / viewPort->drawableAreaXDim;
oversamplingY = (( double )pInfo.nRows * oversampling ) / viewPort->drawableAreaYDim;

int totalMemoryUsage = pInfo.nCols * pInfo.nRows * mProvider->dataTypeSize( bandNumber );
int totalMemoryUsage = pInfo.nCols * oversamplingX * pInfo.nRows * oversamplingY * mProvider->dataTypeSize( bandNumber );
int parts = totalMemoryUsage / 100000000 + 1;
int nPartsPerDimension = sqrt( parts );
pInfo.nColsPerPart = pInfo.nCols / nPartsPerDimension;
Expand All @@ -104,7 +104,8 @@ void QgsRasterRenderer::startRasterRead( int bandNumber, QgsRasterViewPort* view
mRasterPartInfos.insert( bandNumber, pInfo );
}

bool QgsRasterRenderer::readNextRasterPart( int bandNumber, QgsRasterViewPort* viewPort, int& nCols, int& nRows, void** rasterData, int& topLeftCol, int& topLeftRow )
bool QgsRasterRenderer::readNextRasterPart( int bandNumber, double oversamplingX, double oversamplingY, QgsRasterViewPort* viewPort,
int& nCols, int& nRows, int& nColsRaster, int& nRowsRaster, void** rasterData, int& topLeftCol, int& topLeftRow )
{
if ( !viewPort )
{
Expand Down Expand Up @@ -134,7 +135,6 @@ bool QgsRasterRenderer::readNextRasterPart( int bandNumber, QgsRasterViewPort* v
nCols = qMin( pInfo.nColsPerPart, pInfo.nCols - pInfo.currentCol );
nRows = qMin( pInfo.nRowsPerPart, pInfo.nRows - pInfo.currentRow );
int typeSize = mProvider->dataTypeSize( bandNumber ) / 8;
pInfo.data = VSIMalloc( typeSize * nCols * nRows );

//get subrectangle
QgsRectangle viewPortExtent = viewPort->mDrawnExtent;
Expand All @@ -144,7 +144,10 @@ bool QgsRasterRenderer::readNextRasterPart( int bandNumber, QgsRasterViewPort* v
double ymax = viewPortExtent.yMaximum() - pInfo.currentRow / ( double )pInfo.nRows * viewPortExtent.height();
QgsRectangle blockRect( xmin, ymin, xmax, ymax );

mProvider->readBlock( bandNumber, blockRect, nCols, nRows, viewPort->mSrcCRS, viewPort->mDestCRS, pInfo.data );
nColsRaster = nCols * oversamplingX;
nRowsRaster = nRows * oversamplingY;
pInfo.data = VSIMalloc( typeSize * nColsRaster * nRowsRaster );
mProvider->readBlock( bandNumber, blockRect, nColsRaster, nRowsRaster, viewPort->mSrcCRS, viewPort->mDestCRS, pInfo.data );
*rasterData = pInfo.data;
topLeftCol = pInfo.currentCol;
topLeftRow = pInfo.currentRow;
Expand Down Expand Up @@ -199,12 +202,12 @@ void QgsRasterRenderer::drawImage( QPainter* p, QgsRasterViewPort* viewPort, con
}

//top left position in device coords
QPointF tlPoint = QPointF( viewPort->topLeftPoint.x(), viewPort->topLeftPoint.y() );
QPoint tlPoint = QPoint( viewPort->topLeftPoint.x() + topLeftCol, viewPort->topLeftPoint.y() + topLeftRow );

//resample and draw image
if (( mZoomedInResampler || mZoomedOutResampler ) && !doubleNear( oversamplingX, 1.0 ) && !doubleNear( oversamplingY, 1.0 ) )
{
QImage dstImg( nCols / oversamplingX + 1.0, nRows / oversamplingY + 1.0, QImage::Format_ARGB32_Premultiplied );
QImage dstImg( nCols, nRows, QImage::Format_ARGB32_Premultiplied );
if ( mZoomedInResampler && oversamplingX < 1.0 )
{
mZoomedInResampler->resample( img, dstImg );
Expand All @@ -214,7 +217,6 @@ void QgsRasterRenderer::drawImage( QPainter* p, QgsRasterViewPort* viewPort, con
mZoomedOutResampler->resample( img, dstImg );
}

tlPoint += QPointF( topLeftCol / oversamplingX, topLeftRow / oversamplingY );
p->drawImage( tlPoint, dstImg );
}
else //use original image
Expand Down
20 changes: 17 additions & 3 deletions src/core/raster/qgsrasterrenderer.h
Expand Up @@ -29,7 +29,7 @@ class QgsRasterViewPort;
class QgsRasterRenderer
{
public:

//Stores information about reading of a raster band. Columns and rows are in unsampled coordinates
struct RasterPartInfo
{
int currentCol;
Expand All @@ -38,7 +38,7 @@ class QgsRasterRenderer
int nRows;
int nColsPerPart;
int nRowsPerPart;
void* data;
void* data; //data (can be in oversampled/undersampled resolution)
};

QgsRasterRenderer( QgsRasterDataProvider* provider );
Expand Down Expand Up @@ -70,8 +70,22 @@ class QgsRasterRenderer
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 bandNumer number of raster band to read
@param viewPort describes raster position on screen
@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 );
bool readNextRasterPart( int bandNumber, QgsRasterViewPort* viewPort, int& nCols, int& nRows, void** rasterData, int& topLeftCol, int& topLeftRow );
/**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, double oversamplingX, double oversamplingY, QgsRasterViewPort* viewPort, int& nCols, int& nRows,
int& nColsRaster, int& nRowsRaster, 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,
int nCols, int nRows, double oversamplingX, double oversamplingY ) const;
void stopRasterRead( int bandNumber );
Expand Down
21 changes: 15 additions & 6 deletions src/core/raster/qgssinglebandcolordatarenderer.cpp
Expand Up @@ -39,27 +39,36 @@ void QgsSingleBandColorDataRenderer::draw( QPainter* p, QgsRasterViewPort* viewP
double oversamplingX, oversamplingY;
startRasterRead( mBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY );

int topLeftCol, topLeftRow, nCols, nRows, currentRasterPos;
//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;
void* rasterData;

bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS );

while ( readNextRasterPart( mBand, viewPort, nCols, nRows, &rasterData, topLeftCol, topLeftRow ) )
while ( readNextRasterPart( mBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, &rasterData, topLeftCol, topLeftRow ) )
{
currentRasterPos = 0;
QImage img( nCols, nRows, QImage::Format_ARGB32 );
QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32 );
uchar* scanLine = 0;
for ( int i = 0; i < nRows; ++i )
for ( int i = 0; i < nRasterRows; ++i )
{
scanLine = img.scanLine( i );
if ( !hasTransparency )
{
memcpy( scanLine, &((( uint* )rasterData )[currentRasterPos] ), nCols * 4 );
currentRasterPos += nCols;
currentRasterPos += nRasterCols;
}
else
{
for ( int j = 0; j < nCols; ++j )
for ( int j = 0; j < nRasterCols; ++j )
{
QRgb c((( uint* )( rasterData ) )[currentRasterPos] );
scanLine[i] = qRgba( qRed( c ), qGreen( c ), qBlue( c ), 255 );
Expand Down
18 changes: 12 additions & 6 deletions src/core/raster/qgssinglebandgrayrenderer.cpp
Expand Up @@ -43,8 +43,13 @@ void QgsSingleBandGrayRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
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 );
Expand All @@ -60,11 +65,13 @@ void QgsSingleBandGrayRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
QRgb myDefaultColor = qRgba( 0, 0, 0, 0 );


while ( readNextRasterPart( mGrayBand, viewPort, nCols, nRows, &rasterData, topLeftCol, topLeftRow ) )
while ( readNextRasterPart( mGrayBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
&rasterData, topLeftCol, topLeftRow ) )
{
if ( mAlphaBand > 0 && mGrayBand != mAlphaBand )
{
readNextRasterPart( mAlphaBand, viewPort, nCols, nRows, &alphaData, topLeftCol, topLeftRow );
readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
&alphaData, topLeftCol, topLeftRow );
}
else if ( mAlphaBand > 0 )
{
Expand All @@ -73,14 +80,14 @@ void QgsSingleBandGrayRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,


//create image
QImage img( nCols, nRows, QImage::Format_ARGB32_Premultiplied );
QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );
QRgb* imageScanLine = 0;
int currentRasterPos = 0;

for ( int i = 0; i < nRows; ++i )
for ( int i = 0; i < nRasterRows; ++i )
{
imageScanLine = ( QRgb* )( img.scanLine( i ) );
for ( int j = 0; j < nCols; ++j )
for ( int j = 0; j < nRasterCols; ++j )
{
grayVal = readValue( rasterData, rasterType, currentRasterPos );

Expand Down Expand Up @@ -131,5 +138,4 @@ void QgsSingleBandGrayRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
{
stopRasterRead( mAlphaBand );
}

}
17 changes: 12 additions & 5 deletions src/core/raster/qgssinglebandpseudocolorrenderer.cpp
Expand Up @@ -50,8 +50,13 @@ void QgsSingleBandPseudoColorRenderer::draw( QPainter* p, QgsRasterViewPort* vie
startRasterRead( mAlphaBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY );
}

//number of cols/rows in output pixels
int nCols = 0;
int nRows = 0;
//number of raster cols/rows with oversampling
int nRasterCols = 0;
int nRasterRows = 0;
//shift to top left point for the raster part
int topLeftCol = 0;
int topLeftRow = 0;
void* rasterData;
Expand All @@ -64,27 +69,29 @@ void QgsSingleBandPseudoColorRenderer::draw( QPainter* p, QgsRasterViewPort* vie
//rendering is faster without considering user-defined transparency
bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS );

while ( readNextRasterPart( mBand, viewPort, nCols, nRows, &rasterData, topLeftCol, topLeftRow ) )
while ( readNextRasterPart( mBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
&rasterData, topLeftCol, topLeftRow ) )
{
if ( mAlphaBand > 0 && mAlphaBand != mBand )
{
readNextRasterPart( mAlphaBand, viewPort, nCols, nRows, &transparencyData, topLeftCol, topLeftRow );
readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
&transparencyData, topLeftCol, topLeftRow );
}
else if ( mAlphaBand == mBand )
{
transparencyData = rasterData;
}

//create image
QImage img( nCols, nRows, QImage::Format_ARGB32_Premultiplied );
QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );
QRgb* imageScanLine = 0;
double val = 0;

int currentRasterPos = 0;
for ( int i = 0; i < nRows; ++i )
for ( int i = 0; i < nRasterRows; ++i )
{
imageScanLine = ( QRgb* )( img.scanLine( i ) );
for ( int j = 0; j < nCols; ++j )
for ( int j = 0; j < nRasterCols; ++j )
{
val = readValue( rasterData, rasterType, currentRasterPos );
if ( !mShader->shade( val, &red, &green, &blue ) )
Expand Down

0 comments on commit f940c5f

Please sign in to comment.