Skip to content

Commit f940c5f

Browse files
committed
Keep raster renderer parts aligned to pixel boundaries of unsampled rasters (to avoid overlaps or white stripes in large prints
1 parent 15fe4da commit f940c5f

7 files changed

+95
-41
lines changed

src/core/raster/qgsmultibandcolorrenderer.cpp

+14-5
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,24 @@ void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
6666
void* greenData = 0;
6767
void* blueData = 0;
6868
void* alphaData = 0;
69-
int nCols, nRows, topLeftCol, topLeftRow;
69+
//number of cols/rows in output pixels
70+
int nCols = 0;
71+
int nRows = 0;
72+
//number of raster cols/rows with oversampling
73+
int nRasterCols = 0;
74+
int nRasterRows = 0;
75+
//shift to top left point for the raster part
76+
int topLeftCol = 0;
77+
int topLeftRow = 0;
7078

7179
bool readSuccess = true;
7280
while ( true )
7381
{
7482
QSet<int>::const_iterator bandIt = bands.constBegin();
7583
for ( ; bandIt != bands.constEnd(); ++bandIt )
7684
{
77-
readSuccess = readSuccess && readNextRasterPart( *bandIt, viewPort, nCols, nRows, &bandData[*bandIt], topLeftCol, topLeftRow );
85+
readSuccess = readSuccess && readNextRasterPart( *bandIt, oversamplingX, oversamplingY, viewPort, nCols, nRows,
86+
nRasterCols, nRasterRows, &bandData[*bandIt], topLeftCol, topLeftRow );
7887
}
7988

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

93-
QImage img( nCols, nRows, QImage::Format_ARGB32_Premultiplied );
102+
QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );
94103
QRgb* imageScanLine = 0;
95104
int currentRasterPos = 0;
96105
int redVal, greenVal, blueVal;
97106
double currentOpacity = mOpacity; //opacity (between 0 and 1)
98107

99-
for ( int i = 0; i < nRows; ++i )
108+
for ( int i = 0; i < nRasterRows; ++i )
100109
{
101110
imageScanLine = ( QRgb* )( img.scanLine( i ) );
102-
for ( int j = 0; j < nCols; ++j )
111+
for ( int j = 0; j < nRasterCols; ++j )
103112
{
104113
redVal = readValue( redData, redType, currentRasterPos );
105114
greenVal = readValue( greenData, greenType, currentRasterPos );

src/core/raster/qgspalettedrasterrenderer.cpp

+12-5
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,13 @@ void QgsPalettedRasterRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
5353
startRasterRead( mAlphaBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY );
5454
}
5555

56+
//number of cols/rows in output pixels
5657
int nCols = 0;
5758
int nRows = 0;
59+
//number of raster cols/rows with oversampling
60+
int nRasterCols = 0;
61+
int nRasterRows = 0;
62+
//shift to top left point for the raster part
5863
int topLeftCol = 0;
5964
int topLeftRow = 0;
6065
int currentRasterPos = 0;
@@ -66,27 +71,29 @@ void QgsPalettedRasterRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
6671
bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS );
6772
void* transparencyData;
6873

69-
while ( readNextRasterPart( mBandNumber, viewPort, nCols, nRows, &rasterData, topLeftCol, topLeftRow ) )
74+
while ( readNextRasterPart( mBandNumber, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
75+
&rasterData, topLeftCol, topLeftRow ) )
7076
{
7177
if ( mAlphaBand > 0 && mAlphaBand != mBandNumber )
7278
{
73-
readNextRasterPart( mAlphaBand, viewPort, nCols, nRows, &transparencyData, topLeftCol, topLeftRow );
79+
readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
80+
&transparencyData, topLeftCol, topLeftRow );
7481
}
7582
else if ( mAlphaBand == mBandNumber )
7683
{
7784
transparencyData = rasterData;
7885
}
7986

8087
//create image
81-
QImage img( nCols, nRows, QImage::Format_ARGB32_Premultiplied );
88+
QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );
8289
QRgb* imageScanLine = 0;
8390
int val = 0;
8491
currentRasterPos = 0;
8592

86-
for ( int i = 0; i < nRows; ++i )
93+
for ( int i = 0; i < nRasterRows; ++i )
8794
{
8895
imageScanLine = ( QRgb* )( img.scanLine( i ) );
89-
for ( int j = 0; j < nCols; ++j )
96+
for ( int j = 0; j < nRasterCols; ++j )
9097
{
9198
val = readValue( rasterData, rasterType, currentRasterPos );
9299
if ( !hasTransparency )

src/core/raster/qgsrasterrenderer.cpp

+13-11
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,14 @@ void QgsRasterRenderer::startRasterRead( int bandNumber, QgsRasterViewPort* view
8686

8787
//split raster into small portions if necessary
8888
RasterPartInfo pInfo;
89-
pInfo.nCols = viewPort->drawableAreaXDim * oversampling;
90-
pInfo.nRows = viewPort->drawableAreaYDim * oversampling;
89+
pInfo.nCols = viewPort->drawableAreaXDim;
90+
pInfo.nRows = viewPort->drawableAreaYDim;
9191

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

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

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

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

147-
mProvider->readBlock( bandNumber, blockRect, nCols, nRows, viewPort->mSrcCRS, viewPort->mDestCRS, pInfo.data );
147+
nColsRaster = nCols * oversamplingX;
148+
nRowsRaster = nRows * oversamplingY;
149+
pInfo.data = VSIMalloc( typeSize * nColsRaster * nRowsRaster );
150+
mProvider->readBlock( bandNumber, blockRect, nColsRaster, nRowsRaster, viewPort->mSrcCRS, viewPort->mDestCRS, pInfo.data );
148151
*rasterData = pInfo.data;
149152
topLeftCol = pInfo.currentCol;
150153
topLeftRow = pInfo.currentRow;
@@ -199,12 +202,12 @@ void QgsRasterRenderer::drawImage( QPainter* p, QgsRasterViewPort* viewPort, con
199202
}
200203

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

204207
//resample and draw image
205208
if (( mZoomedInResampler || mZoomedOutResampler ) && !doubleNear( oversamplingX, 1.0 ) && !doubleNear( oversamplingY, 1.0 ) )
206209
{
207-
QImage dstImg( nCols / oversamplingX + 1.0, nRows / oversamplingY + 1.0, QImage::Format_ARGB32_Premultiplied );
210+
QImage dstImg( nCols, nRows, QImage::Format_ARGB32_Premultiplied );
208211
if ( mZoomedInResampler && oversamplingX < 1.0 )
209212
{
210213
mZoomedInResampler->resample( img, dstImg );
@@ -214,7 +217,6 @@ void QgsRasterRenderer::drawImage( QPainter* p, QgsRasterViewPort* viewPort, con
214217
mZoomedOutResampler->resample( img, dstImg );
215218
}
216219

217-
tlPoint += QPointF( topLeftCol / oversamplingX, topLeftRow / oversamplingY );
218220
p->drawImage( tlPoint, dstImg );
219221
}
220222
else //use original image

src/core/raster/qgsrasterrenderer.h

+17-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class QgsRasterViewPort;
2929
class QgsRasterRenderer
3030
{
3131
public:
32-
32+
//Stores information about reading of a raster band. Columns and rows are in unsampled coordinates
3333
struct RasterPartInfo
3434
{
3535
int currentCol;
@@ -38,7 +38,7 @@ class QgsRasterRenderer
3838
int nRows;
3939
int nColsPerPart;
4040
int nRowsPerPart;
41-
void* data;
41+
void* data; //data (can be in oversampled/undersampled resolution)
4242
};
4343

4444
QgsRasterRenderer( QgsRasterDataProvider* provider );
@@ -70,8 +70,22 @@ class QgsRasterRenderer
7070
protected:
7171
inline double readValue( void *data, QgsRasterDataProvider::DataType type, int index );
7272

73+
/**Start reading of raster band. Raster data can then be retrieved by calling readNextRasterPart until it returns false.
74+
@param bandNumer number of raster band to read
75+
@param viewPort describes raster position on screen
76+
@param oversamplingX out: oversampling rate in x-direction
77+
@param oversamplingY out: oversampling rate in y-direction*/
7378
void startRasterRead( int bandNumber, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel, double& oversamplingX, double& oversamplingY );
74-
bool readNextRasterPart( int bandNumber, QgsRasterViewPort* viewPort, int& nCols, int& nRows, void** rasterData, int& topLeftCol, int& topLeftRow );
79+
/**Fetches next part of raster data
80+
@param nCols number of columns on output device
81+
@param nRows number of rows on output device
82+
@param nColsRaster number of raster columns (different to nCols if oversamplingX != 1.0)
83+
@param nRowsRaster number of raster rows (different to nRows if oversamplingY != 0)*/
84+
bool readNextRasterPart( int bandNumber, double oversamplingX, double oversamplingY, QgsRasterViewPort* viewPort, int& nCols, int& nRows,
85+
int& nColsRaster, int& nRowsRaster, void** rasterData, int& topLeftCol, int& topLeftRow );
86+
/**Draws raster part
87+
@param topLeftCol Left position relative to left border of viewport
88+
@param topLeftRow Top position relative to top border of viewport*/
7589
void drawImage( QPainter* p, QgsRasterViewPort* viewPort, const QImage& img, int topLeftCol, int topLeftRow,
7690
int nCols, int nRows, double oversamplingX, double oversamplingY ) const;
7791
void stopRasterRead( int bandNumber );

src/core/raster/qgssinglebandcolordatarenderer.cpp

+15-6
Original file line numberDiff line numberDiff line change
@@ -39,27 +39,36 @@ void QgsSingleBandColorDataRenderer::draw( QPainter* p, QgsRasterViewPort* viewP
3939
double oversamplingX, oversamplingY;
4040
startRasterRead( mBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY );
4141

42-
int topLeftCol, topLeftRow, nCols, nRows, currentRasterPos;
42+
//number of cols/rows in output pixels
43+
int nCols = 0;
44+
int nRows = 0;
45+
//number of raster cols/rows with oversampling
46+
int nRasterCols = 0;
47+
int nRasterRows = 0;
48+
//shift to top left point for the raster part
49+
int topLeftCol = 0;
50+
int topLeftRow = 0;
51+
int currentRasterPos;
4352
void* rasterData;
4453

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

47-
while ( readNextRasterPart( mBand, viewPort, nCols, nRows, &rasterData, topLeftCol, topLeftRow ) )
56+
while ( readNextRasterPart( mBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, &rasterData, topLeftCol, topLeftRow ) )
4857
{
4958
currentRasterPos = 0;
50-
QImage img( nCols, nRows, QImage::Format_ARGB32 );
59+
QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32 );
5160
uchar* scanLine = 0;
52-
for ( int i = 0; i < nRows; ++i )
61+
for ( int i = 0; i < nRasterRows; ++i )
5362
{
5463
scanLine = img.scanLine( i );
5564
if ( !hasTransparency )
5665
{
5766
memcpy( scanLine, &((( uint* )rasterData )[currentRasterPos] ), nCols * 4 );
58-
currentRasterPos += nCols;
67+
currentRasterPos += nRasterCols;
5968
}
6069
else
6170
{
62-
for ( int j = 0; j < nCols; ++j )
71+
for ( int j = 0; j < nRasterCols; ++j )
6372
{
6473
QRgb c((( uint* )( rasterData ) )[currentRasterPos] );
6574
scanLine[i] = qRgba( qRed( c ), qGreen( c ), qBlue( c ), 255 );

src/core/raster/qgssinglebandgrayrenderer.cpp

+12-6
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,13 @@ void QgsSingleBandGrayRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
4343
startRasterRead( mAlphaBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY );
4444
}
4545

46+
//number of cols/rows in output pixels
4647
int nCols = 0;
4748
int nRows = 0;
49+
//number of raster cols/rows with oversampling
50+
int nRasterCols = 0;
51+
int nRasterRows = 0;
52+
//shift to top left point for the raster part
4853
int topLeftCol = 0;
4954
int topLeftRow = 0;
5055
QgsRasterDataProvider::DataType rasterType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mGrayBand );
@@ -60,11 +65,13 @@ void QgsSingleBandGrayRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
6065
QRgb myDefaultColor = qRgba( 0, 0, 0, 0 );
6166

6267

63-
while ( readNextRasterPart( mGrayBand, viewPort, nCols, nRows, &rasterData, topLeftCol, topLeftRow ) )
68+
while ( readNextRasterPart( mGrayBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
69+
&rasterData, topLeftCol, topLeftRow ) )
6470
{
6571
if ( mAlphaBand > 0 && mGrayBand != mAlphaBand )
6672
{
67-
readNextRasterPart( mAlphaBand, viewPort, nCols, nRows, &alphaData, topLeftCol, topLeftRow );
73+
readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
74+
&alphaData, topLeftCol, topLeftRow );
6875
}
6976
else if ( mAlphaBand > 0 )
7077
{
@@ -73,14 +80,14 @@ void QgsSingleBandGrayRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
7380

7481

7582
//create image
76-
QImage img( nCols, nRows, QImage::Format_ARGB32_Premultiplied );
83+
QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );
7784
QRgb* imageScanLine = 0;
7885
int currentRasterPos = 0;
7986

80-
for ( int i = 0; i < nRows; ++i )
87+
for ( int i = 0; i < nRasterRows; ++i )
8188
{
8289
imageScanLine = ( QRgb* )( img.scanLine( i ) );
83-
for ( int j = 0; j < nCols; ++j )
90+
for ( int j = 0; j < nRasterCols; ++j )
8491
{
8592
grayVal = readValue( rasterData, rasterType, currentRasterPos );
8693

@@ -131,5 +138,4 @@ void QgsSingleBandGrayRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
131138
{
132139
stopRasterRead( mAlphaBand );
133140
}
134-
135141
}

src/core/raster/qgssinglebandpseudocolorrenderer.cpp

+12-5
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,13 @@ void QgsSingleBandPseudoColorRenderer::draw( QPainter* p, QgsRasterViewPort* vie
5050
startRasterRead( mAlphaBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY );
5151
}
5252

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

67-
while ( readNextRasterPart( mBand, viewPort, nCols, nRows, &rasterData, topLeftCol, topLeftRow ) )
72+
while ( readNextRasterPart( mBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
73+
&rasterData, topLeftCol, topLeftRow ) )
6874
{
6975
if ( mAlphaBand > 0 && mAlphaBand != mBand )
7076
{
71-
readNextRasterPart( mAlphaBand, viewPort, nCols, nRows, &transparencyData, topLeftCol, topLeftRow );
77+
readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
78+
&transparencyData, topLeftCol, topLeftRow );
7279
}
7380
else if ( mAlphaBand == mBand )
7481
{
7582
transparencyData = rasterData;
7683
}
7784

7885
//create image
79-
QImage img( nCols, nRows, QImage::Format_ARGB32_Premultiplied );
86+
QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );
8087
QRgb* imageScanLine = 0;
8188
double val = 0;
8289

8390
int currentRasterPos = 0;
84-
for ( int i = 0; i < nRows; ++i )
91+
for ( int i = 0; i < nRasterRows; ++i )
8592
{
8693
imageScanLine = ( QRgb* )( img.scanLine( i ) );
87-
for ( int j = 0; j < nCols; ++j )
94+
for ( int j = 0; j < nRasterCols; ++j )
8895
{
8996
val = readValue( rasterData, rasterType, currentRasterPos );
9097
if ( !mShader->shade( val, &red, &green, &blue ) )

0 commit comments

Comments
 (0)