Skip to content

Commit 2ddf77a

Browse files
author
mhugent
committedJan 21, 2010
Draw GDAL rasters and WMS layers in several parts if they contain many pixels (e.g. when printing in high resolution to large paper sizes)
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@12809 c8812cc2-4d05-0410-92ff-de0c093fc19c

File tree

2 files changed

+534
-272
lines changed

2 files changed

+534
-272
lines changed
 

‎src/core/raster/qgsrasterlayer.cpp

Lines changed: 479 additions & 272 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ QgsRasterLayer::~QgsRasterLayer()
248248
GDALClose( mGdalDataset );
249249
}
250250
}
251+
delete mRasterShader;
251252
}
252253

253254

@@ -1536,7 +1537,7 @@ bool QgsRasterLayer::draw( QgsRenderContext& rendererContext )
15361537
//the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is becasue
15371538
//theQgsMapToPixel.mapUnitsPerPixel() is less then 1,
15381539
//so we will just get the pixel data and then render these special cases differently in paintImageToCanvas()
1539-
if( 2 >= myRasterViewPort->clippedWidth && 2 >= myRasterViewPort->clippedHeight )
1540+
if ( 2 >= myRasterViewPort->clippedWidth && 2 >= myRasterViewPort->clippedHeight )
15401541
{
15411542
myRasterViewPort->drawableAreaXDim = myRasterViewPort->clippedWidth;
15421543
myRasterViewPort->drawableAreaYDim = myRasterViewPort->clippedHeight;
@@ -1591,90 +1592,88 @@ bool QgsRasterLayer::draw( QgsRenderContext& rendererContext )
15911592

15921593
mDataProvider->setDpi( rendererContext.rasterScaleFactor() * 25.4 * rendererContext.scaleFactor() );
15931594

1594-
QImage* image =
1595-
mDataProvider->draw(
1596-
myRasterExtent,
1597-
// Below should calculate to the actual pixel size of the
1598-
// part of the layer that's visible.
1599-
static_cast<int>( fabs(( myRasterViewPort->clippedXMax - myRasterViewPort->clippedXMin )
1600-
/ theQgsMapToPixel.mapUnitsPerPixel() * mGeoTransform[1] ) + 1 ),
1601-
static_cast<int>( fabs(( myRasterViewPort->clippedYMax - myRasterViewPort->clippedYMin )
1602-
/ theQgsMapToPixel.mapUnitsPerPixel() * mGeoTransform[5] ) + 1 )
1603-
// myRasterViewPort->drawableAreaXDim,
1604-
// myRasterViewPort->drawableAreaYDim
1605-
);
1606-
1607-
if ( !image )
1595+
//fetch image in several parts if it is too memory consuming
1596+
//also some WMS servers have a pixel limit, so it's better to make several requests
1597+
int totalPixelWidth = fabs(( myRasterViewPort->clippedXMax - myRasterViewPort->clippedXMin )
1598+
/ theQgsMapToPixel.mapUnitsPerPixel() * mGeoTransform[1] ) + 1;
1599+
int totalPixelHeight = fabs(( myRasterViewPort->clippedYMax - myRasterViewPort->clippedYMin )
1600+
/ theQgsMapToPixel.mapUnitsPerPixel() * mGeoTransform[5] ) + 1;
1601+
int numParts = totalPixelWidth * totalPixelHeight / 5000000 + 1.0;
1602+
int numRowsPerPart = totalPixelHeight / numParts + 1.0;
1603+
1604+
1605+
int currentPixelOffsetY = 0; //top y-coordinate of current raster part
1606+
//the width of a WMS image part
1607+
int pixelWidth = ( myRasterExtent.xMaximum() - myRasterExtent.xMinimum() ) / theQgsMapToPixel.mapUnitsPerPixel();
1608+
for ( int i = 0; i < numParts; ++i )
16081609
{
1609-
// An error occurred.
1610-
mErrorCaption = mDataProvider->lastErrorTitle();
1611-
mError = mDataProvider->lastError();
1610+
//fetch a small overlap of 2 pixels between two adjacent tiles to avoid white stripes
1611+
QgsRectangle rasterPartRect( myRasterExtent.xMinimum(), myRasterExtent.yMaximum() - ( currentPixelOffsetY + numRowsPerPart + 2 ) * theQgsMapToPixel.mapUnitsPerPixel(), \
1612+
myRasterExtent.xMaximum(), myRasterExtent.yMaximum() - currentPixelOffsetY * theQgsMapToPixel.mapUnitsPerPixel() );
16121613

1613-
delete myRasterViewPort;
1614-
return FALSE;
1615-
}
1614+
int pixelHeight = rasterPartRect.height() / theQgsMapToPixel.mapUnitsPerPixel();
1615+
QImage* image = mDataProvider->draw( rasterPartRect, pixelWidth, pixelHeight );
1616+
1617+
if ( !image )
1618+
{
1619+
// An error occurred.
1620+
mErrorCaption = mDataProvider->lastErrorTitle();
1621+
mError = mDataProvider->lastError();
1622+
1623+
delete myRasterViewPort;
1624+
return FALSE;
1625+
}
16161626

1617-
QgsDebugMsg( "Done mDataProvider->draw." );
1618-
QgsDebugMsg( "image stats: " );
1627+
QgsDebugMsg( "Done mDataProvider->draw." );
1628+
QgsDebugMsg( "image stats: " );
16191629

1620-
QgsDebugMsg( QString( "depth=%1" ).arg( image->depth() ) );
1621-
QgsDebugMsg( QString( "bytes=%1" ).arg( image->numBytes() ) );
1622-
QgsDebugMsg( QString( "width=%1" ).arg( image->width() ) );
1623-
QgsDebugMsg( QString( "height=%1" ).arg( image->height() ) );
1630+
QgsDebugMsg( QString( "depth=%1" ).arg( image->depth() ) );
1631+
QgsDebugMsg( QString( "bytes=%1" ).arg( image->numBytes() ) );
1632+
QgsDebugMsg( QString( "width=%1" ).arg( image->width() ) );
1633+
QgsDebugMsg( QString( "height=%1" ).arg( image->height() ) );
16241634

1625-
QgsDebugMsg( "Want to theQPainter->drawImage with" );
1635+
QgsDebugMsg( "Want to theQPainter->drawImage with" );
16261636

1627-
QgsDebugMsg( QString( "origin x: %1" ).arg( myRasterViewPort->topLeftPoint.x() ) );
1628-
QgsDebugMsg( QString( "(int)origin x: %1" ).arg( static_cast<int>( myRasterViewPort->topLeftPoint.x() ) ) );
1629-
QgsDebugMsg( QString( "origin y: %1" ).arg( myRasterViewPort->topLeftPoint.y() ) );
1630-
QgsDebugMsg( QString( "(int)origin y: %1" ).arg( static_cast<int>( myRasterViewPort->topLeftPoint.y() ) ) );
1637+
QgsDebugMsg( QString( "origin x: %1" ).arg( myRasterViewPort->topLeftPoint.x() ) );
1638+
QgsDebugMsg( QString( "(int)origin x: %1" ).arg( static_cast<int>( myRasterViewPort->topLeftPoint.x() ) ) );
1639+
QgsDebugMsg( QString( "origin y: %1" ).arg( myRasterViewPort->topLeftPoint.y() ) );
1640+
QgsDebugMsg( QString( "(int)origin y: %1" ).arg( static_cast<int>( myRasterViewPort->topLeftPoint.y() ) ) );
16311641

1632-
//Set the transparency for the whole layer
1633-
//QImage::setAlphaChannel does not work quite as expected so set each pixel individually
1634-
//Currently this is only done for WMS images, which should be small enough not to impact performance
1642+
//Set the transparency for the whole layer
1643+
//QImage::setAlphaChannel does not work quite as expected so set each pixel individually
1644+
//Currently this is only done for WMS images, which should be small enough not to impact performance
16351645

1636-
if ( mTransparencyLevel != 255 ) //improve performance if layer transparency not altered
1637-
{
1638-
QImage* transparentImageCopy = new QImage( *image ); //copy image if there is user transparency
1639-
image = transparentImageCopy;
1640-
int myWidth = image->width();
1641-
int myHeight = image->height();
1642-
QRgb myRgb;
1643-
int newTransparency;
1644-
for ( int myHeightRunner = 0; myHeightRunner < myHeight; myHeightRunner++ )
1646+
if ( mTransparencyLevel != 255 ) //improve performance if layer transparency not altered
16451647
{
1646-
QRgb* myLineBuffer = ( QRgb* ) transparentImageCopy->scanLine( myHeightRunner );
1647-
for ( int myWidthRunner = 0; myWidthRunner < myWidth; myWidthRunner++ )
1648+
QImage* transparentImageCopy = new QImage( *image ); //copy image if there is user transparency
1649+
image = transparentImageCopy;
1650+
int myWidth = image->width();
1651+
int myHeight = image->height();
1652+
QRgb myRgb;
1653+
int newTransparency;
1654+
for ( int myHeightRunner = 0; myHeightRunner < myHeight; myHeightRunner++ )
16481655
{
1649-
myRgb = image->pixel( myWidthRunner, myHeightRunner );
1650-
//combine transparency from WMS and layer transparency
1651-
newTransparency = ( double ) mTransparencyLevel / 255.0 * ( double )( qAlpha( myRgb ) );
1652-
myLineBuffer[ myWidthRunner ] = qRgba( qRed( myRgb ), qGreen( myRgb ), qBlue( myRgb ), newTransparency );
1656+
QRgb* myLineBuffer = ( QRgb* ) transparentImageCopy->scanLine( myHeightRunner );
1657+
for ( int myWidthRunner = 0; myWidthRunner < myWidth; myWidthRunner++ )
1658+
{
1659+
myRgb = image->pixel( myWidthRunner, myHeightRunner );
1660+
//combine transparency from WMS and layer transparency
1661+
newTransparency = ( double ) mTransparencyLevel / 255.0 * ( double )( qAlpha( myRgb ) );
1662+
myLineBuffer[ myWidthRunner ] = qRgba( qRed( myRgb ), qGreen( myRgb ), qBlue( myRgb ), newTransparency );
1663+
}
16531664
}
16541665
}
1655-
}
16561666

1657-
// Since GDAL's RasterIO can't handle floating point, we have to round to
1658-
// the nearest pixel. Add 0.5 to get rounding instead of truncation
1659-
// out of static_cast<int>.
1660-
theQPainter->drawImage( static_cast<int>(
1661-
myRasterViewPort->topLeftPoint.x()
1662-
+ 0.5 // try simulating rounding instead of truncation, to avoid off-by-one errors
1663-
// TODO: Check for rigorous correctness
1664-
),
1665-
static_cast<int>(
1666-
myRasterViewPort->topLeftPoint.y()
1667-
+ 0.5 // try simulating rounding instead of truncation, to avoid off-by-one errors
1668-
// TODO: Check for rigorous correctness
1669-
),
1670-
*image );
1671-
1672-
if ( mTransparencyLevel != 255 )
1673-
{
1674-
delete image;
1675-
}
1667+
theQPainter->drawImage( myRasterViewPort->topLeftPoint.x(), myRasterViewPort->topLeftPoint.y() + currentPixelOffsetY, *image );
1668+
currentPixelOffsetY += numRowsPerPart;
1669+
1670+
if ( mTransparencyLevel != 255 )
1671+
{
1672+
delete image;
1673+
}
16761674

1677-
emit statusChanged( tr( "%1 retrieved using %2" ).arg( name() ).arg( mProviderKey ) );
1675+
emit statusChanged( tr( "%1 retrieved using %2" ).arg( name() ).arg( mProviderKey ) );
1676+
}
16781677
}
16791678
else
16801679
{
@@ -4329,6 +4328,7 @@ void QgsRasterLayer::drawMultiBandColor( QPainter * theQPainter, QgsRasterViewPo
43294328
{
43304329
return;
43314330
}
4331+
43324332
GDALRasterBandH myGdalRedBand = GDALGetRasterBand( mGdalDataset, myRedBandNo );
43334333
GDALRasterBandH myGdalGreenBand = GDALGetRasterBand( mGdalDataset, myGreenBandNo );
43344334
GDALRasterBandH myGdalBlueBand = GDALGetRasterBand( mGdalDataset, myBlueBandNo );
@@ -4337,26 +4337,19 @@ void QgsRasterLayer::drawMultiBandColor( QPainter * theQPainter, QgsRasterViewPo
43374337
GDALDataType myGreenType = GDALGetRasterDataType( myGdalGreenBand );
43384338
GDALDataType myBlueType = GDALGetRasterDataType( myGdalBlueBand );
43394339

4340-
void *myGdalRedData = readData( myGdalRedBand, theRasterViewPort );
4341-
void *myGdalGreenData = readData( myGdalGreenBand, theRasterViewPort );
4342-
void *myGdalBlueData = readData( myGdalBlueBand, theRasterViewPort );
4343-
4344-
/* Check for out of memory error */
4345-
if ( myGdalRedData == NULL || myGdalGreenData == NULL || myGdalBlueData == NULL )
4346-
{
4347-
// Safe to free NULL-pointer */
4348-
VSIFree( myGdalRedData );
4349-
VSIFree( myGdalGreenData );
4350-
VSIFree( myGdalBlueData );
4351-
return;
4352-
}
4340+
QRgb* redImageScanLine = 0;
4341+
void* redRasterScanLine = 0;
4342+
QRgb* greenImageScanLine = 0;
4343+
void* greenRasterScanLine = 0;
4344+
QRgb* blueImageScanLine = 0;
4345+
void* blueRasterScanLine = 0;
43534346

4354-
QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
43554347
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
43564348

43574349
QgsRasterBandStats myRedBandStats;
43584350
QgsRasterBandStats myGreenBandStats;
43594351
QgsRasterBandStats myBlueBandStats;
4352+
43604353
/*
43614354
* If a stetch is requested and there are no user defined Min Max values
43624355
* we need to get these values from the bands themselves.
@@ -4408,35 +4401,40 @@ void QgsRasterLayer::drawMultiBandColor( QPainter * theQPainter, QgsRasterViewPo
44084401
QgsContrastEnhancement* myGreenContrastEnhancement = contrastEnhancement( myGreenBandNo );
44094402
QgsContrastEnhancement* myBlueContrastEnhancement = contrastEnhancement( myBlueBandNo );
44104403

4411-
QgsDebugMsg( "Starting main render loop" );
4412-
for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
4404+
QgsRasterImageBuffer redImageBuffer( myGdalRedBand, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4405+
redImageBuffer.reset();
4406+
QgsRasterImageBuffer greenImageBuffer( myGdalGreenBand, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4407+
greenImageBuffer.setWritingEnabled( false ); //only draw to redImageBuffer
4408+
greenImageBuffer.reset();
4409+
QgsRasterImageBuffer blueImageBuffer( myGdalGreenBand, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4410+
blueImageBuffer.setWritingEnabled( false ); //only draw to redImageBuffer
4411+
blueImageBuffer.reset();
4412+
4413+
while ( redImageBuffer.nextScanLine( &redImageScanLine, &redRasterScanLine ) && greenImageBuffer.nextScanLine( &greenImageScanLine, &greenRasterScanLine ) \
4414+
&& blueImageBuffer.nextScanLine( &blueImageScanLine, &blueRasterScanLine ) )
44134415
{
4414-
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
4415-
for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
4416+
for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
44164417
{
4417-
myRedValue = readValue( myGdalRedData, ( GDALDataType )myRedType,
4418-
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
4419-
myGreenValue = readValue( myGdalGreenData, ( GDALDataType )myGreenType,
4420-
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
4421-
myBlueValue = readValue( myGdalBlueData, ( GDALDataType )myBlueType,
4422-
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
4418+
myRedValue = readValue( redImageScanLine, ( GDALDataType )myRedType, i );
4419+
myGreenValue = readValue( greenImageScanLine, ( GDALDataType )myGreenType, i );
4420+
myBlueValue = readValue( blueImageScanLine, ( GDALDataType )myBlueType, i );
44234421

44244422
if ( mValidNoDataValue && (( fabs( myRedValue - mNoDataValue ) <= TINY_VALUE || myRedValue != myRedValue ) || ( fabs( myGreenValue - mNoDataValue ) <= TINY_VALUE || myGreenValue != myGreenValue ) || ( fabs( myBlueValue - mNoDataValue ) <= TINY_VALUE || myBlueValue != myBlueValue ) ) )
44254423
{
4426-
myLineBuffer[ myColumn ] = myDefaultColor;
4424+
redImageScanLine[ i ] = myDefaultColor;
44274425
continue;
44284426
}
44294427

44304428
if ( !myRedContrastEnhancement->isValueInDisplayableRange( myRedValue ) || !myGreenContrastEnhancement->isValueInDisplayableRange( myGreenValue ) || !myBlueContrastEnhancement->isValueInDisplayableRange( myBlueValue ) )
44314429
{
4432-
myLineBuffer[ myColumn ] = myDefaultColor;
4430+
redImageScanLine[ i ] = myDefaultColor;
44334431
continue;
44344432
}
44354433

44364434
myAlphaValue = mRasterTransparency.alphaValue( myRedValue, myGreenValue, myBlueValue, mTransparencyLevel );
44374435
if ( 0 == myAlphaValue )
44384436
{
4439-
myLineBuffer[ myColumn ] = myDefaultColor;
4437+
redImageScanLine[ i ] = myDefaultColor;
44404438
continue;
44414439
}
44424440

@@ -4451,34 +4449,9 @@ void QgsRasterLayer::drawMultiBandColor( QPainter * theQPainter, QgsRasterViewPo
44514449
myStretchedBlueValue = 255 - myStretchedBlueValue;
44524450
}
44534451

4454-
myLineBuffer[ myColumn ] = qRgba( myStretchedRedValue, myStretchedGreenValue, myStretchedBlueValue, myAlphaValue );
4452+
redImageScanLine[ i ] = qRgba( myStretchedRedValue, myStretchedGreenValue, myStretchedBlueValue, myAlphaValue );
44554453
}
44564454
}
4457-
//free the scanline memory
4458-
CPLFree( myGdalRedData );
4459-
CPLFree( myGdalGreenData );
4460-
CPLFree( myGdalBlueData );
4461-
4462-
#ifdef QGISDEBUG
4463-
QPixmap *pm = dynamic_cast<QPixmap *>( theQPainter->device() );
4464-
if ( pm )
4465-
{
4466-
QgsDebugMsg( "theQPainter stats: " );
4467-
QgsDebugMsg( "width = " + QString::number( pm->width() ) );
4468-
QgsDebugMsg( "height = " + QString::number( pm->height() ) );
4469-
pm->save( "/tmp/qgis-rasterlayer-drawmultibandcolor-test-a.png", "PNG" );
4470-
}
4471-
#endif
4472-
4473-
paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
4474-
4475-
#ifdef QGISDEBUG
4476-
QgsDebugMsg( "theQPainter->drawImage." );
4477-
if ( pm )
4478-
{
4479-
pm->save( "/tmp/qgis-rasterlayer-drawmultibandcolor-test-b.png", "PNG" );
4480-
}
4481-
#endif
44824455
}
44834456

44844457
void QgsRasterLayer::drawMultiBandSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
@@ -4518,69 +4491,58 @@ void QgsRasterLayer::drawPalettedSingleBandColor( QPainter * theQPainter, QgsRas
45184491

45194492
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
45204493
GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
4521-
void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
45224494

4523-
/* Check for out of memory error */
4524-
if ( myGdalScanData == NULL )
4525-
{
4526-
return;
4527-
}
4495+
QgsRasterImageBuffer imageBuffer( myGdalBand, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4496+
imageBuffer.reset();
45284497

4529-
QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
4530-
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4498+
QRgb* imageScanLine = 0;
4499+
void* rasterScanLine = 0;
45314500

4501+
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
45324502
double myPixelValue = 0.0;
45334503
int myRedValue = 0;
45344504
int myGreenValue = 0;
45354505
int myBlueValue = 0;
45364506
int myAlphaValue = 0;
45374507

4538-
QgsDebugMsg( "Starting main render loop" );
4539-
for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
4508+
while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) )
45404509
{
4541-
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
4542-
for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
4510+
for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
45434511
{
4544-
myRedValue = 0;
4545-
myGreenValue = 0;
4546-
myBlueValue = 0;
4547-
myPixelValue = readValue( myGdalScanData, ( GDALDataType )myDataType,
4548-
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
4512+
myRedValue = 0; myGreenValue = 0; myBlueValue = 0;
4513+
myPixelValue = readValue( rasterScanLine, ( GDALDataType )myDataType, i );
45494514

45504515
if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
45514516
{
4552-
myLineBuffer[ myColumn ] = myDefaultColor;
4517+
imageScanLine[ i ] = myDefaultColor;
45534518
continue;
45544519
}
45554520

45564521
myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
45574522
if ( 0 == myAlphaValue )
45584523
{
4559-
myLineBuffer[ myColumn ] = myDefaultColor;
4524+
imageScanLine[ i ] = myDefaultColor;
45604525
continue;
45614526
}
45624527

45634528
if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
45644529
{
4565-
myLineBuffer[ myColumn ] = myDefaultColor;
4530+
imageScanLine[ i ] = myDefaultColor;
45664531
continue;
45674532
}
45684533

45694534
if ( mInvertColor )
45704535
{
45714536
//Invert flag, flip blue and read
4572-
myLineBuffer[ myColumn ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
4537+
imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
45734538
}
45744539
else
45754540
{
45764541
//Normal
4577-
myLineBuffer[ myColumn ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
4542+
imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
45784543
}
45794544
}
45804545
}
4581-
CPLFree( myGdalScanData );
4582-
4583-
paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
45844546
}
45854547

45864548
/**
@@ -4606,71 +4568,62 @@ void QgsRasterLayer::drawPalettedSingleBandGray( QPainter * theQPainter, QgsRast
46064568

46074569
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
46084570
GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
4609-
void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
46104571

4611-
/* Check for out of memory error */
4612-
if ( myGdalScanData == NULL )
4613-
{
4614-
return;
4615-
}
4572+
QgsRasterImageBuffer imageBuffer( myGdalBand, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4573+
imageBuffer.reset();
46164574

4617-
QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
4618-
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4575+
QRgb* imageScanLine = 0;
4576+
void* rasterScanLine = 0;
46194577

4578+
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
46204579
double myPixelValue = 0.0;
46214580
int myRedValue = 0;
46224581
int myGreenValue = 0;
46234582
int myBlueValue = 0;
46244583
int myAlphaValue = 0;
46254584

4626-
QgsDebugMsg( "Starting main render loop" );
4627-
for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
4585+
while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) )
46284586
{
4629-
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
4630-
for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
4587+
for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
46314588
{
46324589
myRedValue = 0;
46334590
myGreenValue = 0;
46344591
myBlueValue = 0;
4635-
myPixelValue = readValue( myGdalScanData, ( GDALDataType )myDataType,
4636-
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
4592+
myPixelValue = readValue( rasterScanLine, ( GDALDataType )myDataType, i );
46374593

46384594
if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
46394595
{
4640-
myLineBuffer[ myColumn ] = myDefaultColor;
4596+
imageScanLine[ i ] = myDefaultColor;
46414597
continue;
46424598
}
46434599

46444600
myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
46454601
if ( 0 == myAlphaValue )
46464602
{
4647-
myLineBuffer[ myColumn ] = myDefaultColor;
4603+
imageScanLine[ i ] = myDefaultColor;
46484604
continue;
46494605
}
46504606

46514607
if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
46524608
{
4653-
myLineBuffer[ myColumn ] = myDefaultColor;
4609+
imageScanLine[ i ] = myDefaultColor;
46544610
continue;
46554611
}
46564612

46574613
if ( mInvertColor )
46584614
{
46594615
//Invert flag, flip blue and read
46604616
double myGrayValue = ( 0.3 * ( double )myRedValue ) + ( 0.59 * ( double )myGreenValue ) + ( 0.11 * ( double )myBlueValue );
4661-
myLineBuffer[ myColumn ] = qRgba(( int )myGrayValue, ( int )myGrayValue, ( int )myGrayValue, myAlphaValue );
4617+
imageScanLine[ i ] = qRgba(( int )myGrayValue, ( int )myGrayValue, ( int )myGrayValue, myAlphaValue );
46624618
}
46634619
else
46644620
{
46654621
//Normal
46664622
double myGrayValue = ( 0.3 * ( double )myBlueValue ) + ( 0.59 * ( double )myGreenValue ) + ( 0.11 * ( double )myRedValue );
4667-
myLineBuffer[ myColumn ] = qRgba(( int )myGrayValue, ( int )myGrayValue, ( int )myGrayValue, myAlphaValue );
4623+
imageScanLine[ i ] = qRgba(( int )myGrayValue, ( int )myGrayValue, ( int )myGrayValue, myAlphaValue );
46684624
}
46694625
}
46704626
}
4671-
CPLFree( myGdalScanData );
4672-
4673-
paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
46744627
}
46754628

46764629
/**
@@ -4694,22 +4647,14 @@ void QgsRasterLayer::drawPalettedSingleBandPseudoColor( QPainter * theQPainter,
46944647
QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo );
46954648
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
46964649
GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
4697-
void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
4698-
4699-
/* Check for out of memory error */
4700-
if ( myGdalScanData == NULL )
4701-
{
4702-
return;
4703-
}
47044650

4705-
QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
4706-
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4651+
QgsRasterImageBuffer imageBuffer( myGdalBand, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4652+
imageBuffer.reset();
47074653

4708-
if ( NULL == mRasterShader )
4709-
{
4710-
return;
4711-
}
4654+
QRgb* imageScanLine = 0;
4655+
void* rasterScanLine = 0;
47124656

4657+
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
47134658
double myMinimumValue = 0.0;
47144659
double myMaximumValue = 0.0;
47154660
//Use standard deviations if set, otherwise, use min max of band
@@ -4733,52 +4678,46 @@ void QgsRasterLayer::drawPalettedSingleBandPseudoColor( QPainter * theQPainter,
47334678
int myBlueValue = 0;
47344679
int myAlphaValue = 0;
47354680

4736-
QgsDebugMsg( "Starting main render loop" );
4737-
for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
4681+
while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) )
47384682
{
4739-
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
4740-
for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
4683+
for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
47414684
{
47424685
myRedValue = 0;
47434686
myGreenValue = 0;
47444687
myBlueValue = 0;
4745-
myPixelValue = readValue( myGdalScanData, ( GDALDataType )myDataType,
4746-
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
4688+
myPixelValue = readValue( rasterScanLine, ( GDALDataType )myDataType, i );
47474689

47484690
if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
47494691
{
4750-
myLineBuffer[ myColumn ] = myDefaultColor;
4692+
imageScanLine[ i ] = myDefaultColor;
47514693
continue;
47524694
}
47534695

47544696
myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
47554697
if ( 0 == myAlphaValue )
47564698
{
4757-
myLineBuffer[ myColumn ] = myDefaultColor;
4699+
imageScanLine[ i ] = myDefaultColor;
47584700
continue;
47594701
}
47604702

47614703
if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
47624704
{
4763-
myLineBuffer[ myColumn ] = myDefaultColor;
4705+
imageScanLine[ i ] = myDefaultColor;
47644706
continue;
47654707
}
47664708

47674709
if ( mInvertColor )
47684710
{
47694711
//Invert flag, flip blue and read
4770-
myLineBuffer[ myColumn ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
4712+
imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
47714713
}
47724714
else
47734715
{
47744716
//Normal
4775-
myLineBuffer[ myColumn ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
4717+
imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
47764718
}
47774719
}
47784720
}
4779-
CPLFree( myGdalScanData );
4780-
4781-
paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
47824721
}
47834722

47844723
/**
@@ -4804,19 +4743,19 @@ void QgsRasterLayer::drawSingleBandGray( QPainter * theQPainter, QgsRasterViewPo
48044743

48054744
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
48064745
GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
4807-
void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
4746+
QgsRasterImageBuffer imageBuffer( myGdalBand, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4747+
imageBuffer.reset();
48084748

4809-
/* Check for out of memory error */
4810-
if ( myGdalScanData == NULL )
4811-
{
4812-
return;
4813-
}
4749+
QRgb* imageScanLine = 0;
4750+
void* rasterScanLine = 0;
48144751

4815-
QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
48164752
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4753+
double myGrayValue = 0.0;
4754+
int myGrayVal = 0;
4755+
int myAlphaValue = 0;
4756+
QgsContrastEnhancement* myContrastEnhancement = contrastEnhancement( theBandNo );
48174757

48184758
QgsRasterBandStats myGrayBandStats;
4819-
48204759
if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedGrayMinimumMaximum && mStandardDeviations > 0 )
48214760
{
48224761
mGrayMinimumMaximumEstimated = false;
@@ -4836,41 +4775,28 @@ void QgsRasterLayer::drawSingleBandGray( QPainter * theQPainter, QgsRasterViewPo
48364775

48374776
}
48384777

4839-
QgsDebugMsg( "Starting main render loop" );
4840-
// print each point in myGdalScanData with equal parts R, G, B or make it show as gray
4841-
double myGrayValue = 0.0;
4842-
int myGrayVal = 0;
4843-
int myAlphaValue = 0;
4844-
QgsContrastEnhancement* myContrastEnhancement = contrastEnhancement( theBandNo );
4845-
for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
4778+
while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) )
48464779
{
4847-
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
4848-
for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
4780+
for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
48494781
{
4850-
myGrayValue = readValue( myGdalScanData, myDataType,
4851-
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
4852-
4853-
// If mNoDataValue is 'nan', the comparison
4854-
// against myGrayVal will always fail ( nan==nan always
4855-
// returns false, by design), hence the slightly odd comparison
4856-
// of myGrayVal against itself.
4782+
myGrayValue = readValue( rasterScanLine, ( GDALDataType )myDataType, i );
48574783

48584784
if ( mValidNoDataValue && ( fabs( myGrayValue - mNoDataValue ) <= TINY_VALUE || myGrayValue != myGrayValue ) )
48594785
{
4860-
myLineBuffer[ myColumn ] = myDefaultColor;
4786+
imageScanLine[ i ] = myDefaultColor;
48614787
continue;
48624788
}
48634789

48644790
if ( !myContrastEnhancement->isValueInDisplayableRange( myGrayValue ) )
48654791
{
4866-
myLineBuffer[ myColumn ] = myDefaultColor;
4792+
imageScanLine[ i ] = myDefaultColor;
48674793
continue;
48684794
}
48694795

48704796
myAlphaValue = mRasterTransparency.alphaValue( myGrayValue, mTransparencyLevel );
48714797
if ( 0 == myAlphaValue )
48724798
{
4873-
myLineBuffer[ myColumn ] = myDefaultColor;
4799+
imageScanLine[ i ] = myDefaultColor;
48744800
continue;
48754801
}
48764802

@@ -4882,16 +4808,9 @@ void QgsRasterLayer::drawSingleBandGray( QPainter * theQPainter, QgsRasterViewPo
48824808
myGrayVal = 255 - myGrayVal;
48834809
}
48844810

4885-
myLineBuffer[ myColumn ] = qRgba( myGrayVal, myGrayVal, myGrayVal, myAlphaValue );
4811+
imageScanLine[ i ] = qRgba( myGrayVal, myGrayVal, myGrayVal, myAlphaValue );
48864812
}
48874813
}
4888-
4889-
CPLFree( myGdalScanData );
4890-
4891-
QgsDebugMsg( "Render done, preparing to copy to canvas" );
4892-
4893-
paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
4894-
48954814
} // QgsRasterLayer::drawSingleBandGray
48964815

48974816
void QgsRasterLayer::drawSingleBandPseudoColor( QPainter * theQPainter,
@@ -4909,17 +4828,14 @@ void QgsRasterLayer::drawSingleBandPseudoColor( QPainter * theQPainter,
49094828
QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo );
49104829
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
49114830
GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
4912-
void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
49134831

4914-
/* Check for out of memory error */
4915-
if ( myGdalScanData == NULL )
4916-
{
4917-
return;
4918-
}
4832+
QgsRasterImageBuffer imageBuffer( myGdalBand, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4833+
imageBuffer.reset();
49194834

4920-
QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
4921-
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4835+
QRgb* imageScanLine = 0;
4836+
void* rasterScanLine = 0;
49224837

4838+
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
49234839
if ( NULL == mRasterShader )
49244840
{
49254841
return;
@@ -4942,57 +4858,50 @@ void QgsRasterLayer::drawSingleBandPseudoColor( QPainter * theQPainter,
49424858
mRasterShader->setMinimumValue( myMinimumValue );
49434859
mRasterShader->setMaximumValue( myMaximumValue );
49444860

4945-
49464861
int myRedValue = 255;
49474862
int myGreenValue = 255;
49484863
int myBlueValue = 255;
49494864

49504865
double myPixelValue = 0.0;
49514866
int myAlphaValue = 0;
4952-
QgsDebugMsg( "Starting main render loop" );
4953-
for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
4867+
4868+
while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) )
49544869
{
4955-
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
4956-
for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
4870+
for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
49574871
{
4958-
myPixelValue = readValue( myGdalScanData, myDataType,
4959-
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
4872+
myPixelValue = readValue( rasterScanLine, myDataType, i );
49604873

49614874
if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
49624875
{
4963-
myLineBuffer[ myColumn ] = myDefaultColor;
4876+
imageScanLine[ i ] = myDefaultColor;
49644877
continue;
49654878
}
49664879

49674880
myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
49684881
if ( 0 == myAlphaValue )
49694882
{
4970-
myLineBuffer[ myColumn ] = myDefaultColor;
4883+
imageScanLine[ i ] = myDefaultColor;
49714884
continue;
49724885
}
49734886

49744887
if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
49754888
{
4976-
myLineBuffer[ myColumn ] = myDefaultColor;
4889+
imageScanLine[ i ] = myDefaultColor;
49774890
continue;
49784891
}
49794892

49804893
if ( mInvertColor )
49814894
{
49824895
//Invert flag, flip blue and read
4983-
myLineBuffer[ myColumn ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
4896+
imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
49844897
}
49854898
else
49864899
{
49874900
//Normal
4988-
myLineBuffer[ myColumn ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
4901+
imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
49894902
}
4990-
} //end of columnwise loop
4991-
} //end of rowwise loop
4992-
4993-
CPLFree( myGdalScanData );
4994-
4995-
paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
4903+
}
4904+
}
49964905
}
49974906

49984907

@@ -5085,7 +4994,7 @@ void QgsRasterLayer::paintImageToCanvas( QPainter* theQPainter, QgsRasterViewPor
50854994

50864995
//Catch special rendering cases
50874996
//INSTANCE: 1x1
5088-
if( 1 == theRasterViewPort->clippedWidth && 1 == theRasterViewPort->clippedHeight )
4997+
if ( 1 == theRasterViewPort->clippedWidth && 1 == theRasterViewPort->clippedHeight )
50894998
{
50904999
QColor myColor( theImage->pixel( 0, 0 ) );
50915000
myColor.setAlpha( qAlpha( theImage->pixel( 0, 0 ) ) );
@@ -5096,38 +5005,41 @@ void QgsRasterLayer::paintImageToCanvas( QPainter* theQPainter, QgsRasterViewPor
50965005
QBrush( myColor ) );
50975006
}
50985007
//1x2, 2x1 or 2x2
5099-
else if( 2 >= theRasterViewPort->clippedWidth && 2 >= theRasterViewPort->clippedHeight )
5008+
else if ( 2 >= theRasterViewPort->clippedWidth && 2 >= theRasterViewPort->clippedHeight )
51005009
{
51015010
int myPixelBoundaryX = 0;
51025011
int myPixelBoundaryY = 0;
5103-
if( theQgsMapToPixel ) {
5104-
myPixelBoundaryX = static_cast<int>( theRasterViewPort->topLeftPoint.x() + 0.5 ) + static_cast<int>( fabs ( mGeoTransform[1] / theQgsMapToPixel->mapUnitsPerPixel() ) ) - paintXoffset;
5105-
myPixelBoundaryY = static_cast<int>( theRasterViewPort->topLeftPoint.y() + 0.5 ) + static_cast<int>( fabs(mGeoTransform[5] / theQgsMapToPixel->mapUnitsPerPixel() )) - paintYoffset;
5012+
if ( theQgsMapToPixel )
5013+
{
5014+
myPixelBoundaryX = static_cast<int>( theRasterViewPort->topLeftPoint.x() + 0.5 ) + static_cast<int>( fabs( mGeoTransform[1] / theQgsMapToPixel->mapUnitsPerPixel() ) ) - paintXoffset;
5015+
myPixelBoundaryY = static_cast<int>( theRasterViewPort->topLeftPoint.y() + 0.5 ) + static_cast<int>( fabs( mGeoTransform[5] / theQgsMapToPixel->mapUnitsPerPixel() ) ) - paintYoffset;
51065016
}
51075017

51085018
//INSTANCE: 1x2
5109-
if( 1 == theRasterViewPort->clippedWidth ) {
5019+
if ( 1 == theRasterViewPort->clippedWidth )
5020+
{
51105021
QColor myColor( theImage->pixel( 0, 0 ) );
51115022
myColor.setAlpha( qAlpha( theImage->pixel( 0, 0 ) ) );
51125023
theQPainter->fillRect( static_cast<int>( theRasterViewPort->topLeftPoint.x() + 0.5 ),
51135024
static_cast<int>( theRasterViewPort->topLeftPoint.y() + 0.5 ),
51145025
static_cast<int>( theRasterViewPort->bottomRightPoint.x() ),
51155026
static_cast<int>( myPixelBoundaryY ),
51165027
QBrush( myColor ) );
5117-
myColor = QColor( theImage->pixel( 0, 1) );
5028+
myColor = QColor( theImage->pixel( 0, 1 ) );
51185029
myColor.setAlpha( qAlpha( theImage->pixel( 0, 1 ) ) );
51195030
theQPainter->fillRect( static_cast<int>( theRasterViewPort->topLeftPoint.x() + 0.5 ),
51205031
static_cast<int>( myPixelBoundaryY ),
51215032
static_cast<int>( theRasterViewPort->bottomRightPoint.x() ),
51225033
static_cast<int>( theRasterViewPort->bottomRightPoint.y() ),
51235034
QBrush( myColor ) );
51245035
}
5125-
else {
5036+
else
5037+
{
51265038
//INSTANCE: 2x1
5127-
if( 1 == theRasterViewPort->clippedHeight )
5039+
if ( 1 == theRasterViewPort->clippedHeight )
51285040
{
51295041
QColor myColor( theImage->pixel( 0, 0 ) );
5130-
myColor.setAlpha( qAlpha( theImage->pixel( 0,0 ) ) );
5042+
myColor.setAlpha( qAlpha( theImage->pixel( 0, 0 ) ) );
51315043
theQPainter->fillRect( static_cast<int>( theRasterViewPort->topLeftPoint.x() + 0.5 ),
51325044
static_cast<int>( theRasterViewPort->topLeftPoint.y() + 0.5 ),
51335045
static_cast<int>( myPixelBoundaryX ),
@@ -5148,10 +5060,10 @@ void QgsRasterLayer::paintImageToCanvas( QPainter* theQPainter, QgsRasterViewPor
51485060
myColor.setAlpha( qAlpha( theImage->pixel( 0, 0 ) ) );
51495061
theQPainter->fillRect( static_cast<int>( theRasterViewPort->topLeftPoint.x() + 0.5 ),
51505062
static_cast<int>( theRasterViewPort->topLeftPoint.y() + 0.5 ),
5151-
static_cast<int>(myPixelBoundaryX ),
5063+
static_cast<int>( myPixelBoundaryX ),
51525064
static_cast<int>( myPixelBoundaryY ),
51535065
QBrush( myColor ) );
5154-
myColor = QColor( theImage->pixel( 1, 0 ) );
5066+
myColor = QColor( theImage->pixel( 1, 0 ) );
51555067
myColor.setAlpha( qAlpha( theImage->pixel( 1, 0 ) ) );
51565068
theQPainter->fillRect( static_cast<int>( myPixelBoundaryX ),
51575069
static_cast<int>( theRasterViewPort->topLeftPoint.y() + 0.5 ),
@@ -5177,7 +5089,8 @@ void QgsRasterLayer::paintImageToCanvas( QPainter* theQPainter, QgsRasterViewPor
51775089

51785090
}
51795091
// INSTANCE: > 2x2, so just use the image filled by GDAL
5180-
else {
5092+
else
5093+
{
51815094
theQPainter->drawImage( static_cast<int>( theRasterViewPort->topLeftPoint.x() + 0.5 ),
51825095
static_cast<int>( theRasterViewPort->topLeftPoint.y() + 0.5 ),
51835096
*theImage,
@@ -5617,3 +5530,297 @@ QString QgsRasterLayer::validateBandName( QString const & theBandName )
56175530
QgsDebugMsg( "All checks failed, returning '" + QSTRING_NOT_SET + "'" );
56185531
return TRSTRING_NOT_SET;
56195532
}
5533+
5534+
QgsRasterImageBuffer::QgsRasterImageBuffer( GDALRasterBandH rasterBand, QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel, double* geoTransform ): \
5535+
mRasterBand( rasterBand ), mPainter( p ), mViewPort( viewPort ), mMapToPixel( mapToPixel ), mValid( false ), mWritingEnabled( true ), mDrawPixelRect( false ), mCurrentImage( 0 ), mCurrentGDALData( 0 ), mGeoTransform( geoTransform )
5536+
{
5537+
5538+
}
5539+
5540+
QgsRasterImageBuffer::~QgsRasterImageBuffer()
5541+
{
5542+
delete mCurrentImage;
5543+
CPLFree( mCurrentGDALData );
5544+
}
5545+
5546+
void QgsRasterImageBuffer::reset( int maxPixelsInVirtualMemory )
5547+
{
5548+
if ( mRasterBand && mPainter && mViewPort && mMapToPixel )
5549+
{
5550+
mValid = true;
5551+
}
5552+
else
5553+
{
5554+
mValid = false;
5555+
return;
5556+
}
5557+
5558+
//decide on the partition of the image
5559+
5560+
int pixels = mViewPort->drawableAreaXDim * mViewPort->drawableAreaYDim;
5561+
int mNumPartImages = pixels / maxPixelsInVirtualMemory + 1.0;
5562+
mNumRasterRowsPerPart = ( double )mViewPort->clippedHeight / ( double )mNumPartImages + 0.5;
5563+
5564+
mCurrentPartRasterMin = -1;
5565+
mCurrentPartRasterMax = -1;
5566+
mCurrentPartImageRow = 0;
5567+
mNumCurrentImageRows = 0;
5568+
5569+
createNextPartImage();
5570+
5571+
if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight )
5572+
{
5573+
//use Peter's fix for zoomed in rasters
5574+
mDrawPixelRect = true;
5575+
}
5576+
}
5577+
5578+
bool QgsRasterImageBuffer::nextScanLine( QRgb** imageScanLine, void** rasterScanLine )
5579+
{
5580+
if ( !mValid )
5581+
{
5582+
return false;
5583+
}
5584+
5585+
if ( !mCurrentGDALData || ! mCurrentImage )
5586+
{
5587+
return false;
5588+
}
5589+
5590+
if ( mCurrentPartImageRow >= ( mNumCurrentImageRows ) )
5591+
{
5592+
if ( !createNextPartImage() )
5593+
{
5594+
return false;
5595+
}
5596+
}
5597+
5598+
if ( mWritingEnabled )
5599+
{
5600+
*imageScanLine = ( QRgb* )( mCurrentImage->scanLine( mCurrentPartImageRow ) );
5601+
}
5602+
else
5603+
{
5604+
*imageScanLine = 0;
5605+
}
5606+
GDALDataType type = GDALGetRasterDataType( mRasterBand );
5607+
int size = GDALGetDataTypeSize( type ) / 8;
5608+
*rasterScanLine = mCurrentGDALData + mCurrentPartImageRow * mViewPort->drawableAreaXDim * size;
5609+
5610+
++mCurrentPartImageRow;
5611+
++mCurrentRow;
5612+
return true;
5613+
}
5614+
5615+
bool QgsRasterImageBuffer::createNextPartImage()
5616+
{
5617+
//draw the last image if mCurrentImage if it exists
5618+
if ( mCurrentImage )
5619+
{
5620+
if ( mWritingEnabled )
5621+
{
5622+
if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight )
5623+
{
5624+
drawPixelRectangle();
5625+
}
5626+
else
5627+
{
5628+
double xLeft = mViewPort->topLeftPoint.x();
5629+
double yTop = mViewPort->topLeftPoint.y() + fabs( mGeoTransform[5] ) * mCurrentPartRasterMin / mMapToPixel->mapUnitsPerPixel();
5630+
mPainter->drawImage( QPointF( xLeft, yTop + 0.5 ), *mCurrentImage );
5631+
}
5632+
}
5633+
}
5634+
5635+
delete mCurrentImage; mCurrentImage = 0;
5636+
CPLFree( mCurrentGDALData ); mCurrentGDALData = 0;
5637+
5638+
if ( mCurrentPartRasterMax >= mViewPort->clippedHeight )
5639+
{
5640+
return false; //already at the end...
5641+
}
5642+
5643+
mCurrentPartRasterMin = mCurrentPartRasterMax + 1;
5644+
mCurrentPartRasterMax = mCurrentPartRasterMin + mNumRasterRowsPerPart;
5645+
if ( mCurrentPartRasterMax > mViewPort->clippedHeight )
5646+
{
5647+
mCurrentPartRasterMax = mViewPort->clippedHeight;
5648+
}
5649+
mCurrentRow = mCurrentPartRasterMin;
5650+
mCurrentPartImageRow = 0;
5651+
5652+
//read GDAL image data
5653+
GDALDataType type = GDALGetRasterDataType( mRasterBand );
5654+
int size = GDALGetDataTypeSize( type ) / 8;
5655+
int xSize = mViewPort->drawableAreaXDim;
5656+
5657+
//make the raster tiles overlap at least 2 pixels to avoid white stripes
5658+
int overlapRows = 0;
5659+
overlapRows = mMapToPixel->mapUnitsPerPixel() / fabs( mGeoTransform[5] ) + 2;
5660+
if ( mCurrentPartRasterMax + overlapRows >= mViewPort->clippedHeight )
5661+
{
5662+
overlapRows = 0;
5663+
}
5664+
int rasterYSize = mCurrentPartRasterMax - mCurrentPartRasterMin + overlapRows;
5665+
5666+
int ySize = 0;
5667+
if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight ) //for zoomed in rasters
5668+
{
5669+
rasterYSize = mViewPort->clippedHeight;
5670+
ySize = mViewPort->drawableAreaYDim;
5671+
}
5672+
else //normal mode
5673+
{
5674+
ySize = fabs((( rasterYSize ) / mMapToPixel->mapUnitsPerPixel() * mGeoTransform[5] ) ) + 0.5;
5675+
}
5676+
if ( ySize == 0 )
5677+
{
5678+
return false;
5679+
}
5680+
mNumCurrentImageRows = ySize;
5681+
mCurrentGDALData = VSIMalloc( size * xSize * ySize );
5682+
CPLErr myErr = GDALRasterIO( mRasterBand, GF_Read, mViewPort->rectXOffset, \
5683+
mViewPort->rectYOffset + mCurrentRow, mViewPort->clippedWidth, rasterYSize, \
5684+
mCurrentGDALData, xSize, ySize, type, 0, 0 );
5685+
5686+
if ( myErr != CPLE_None )
5687+
{
5688+
CPLFree( mCurrentGDALData );
5689+
mCurrentGDALData = 0;
5690+
return false;
5691+
}
5692+
5693+
//create the QImage
5694+
if ( mWritingEnabled )
5695+
{
5696+
mCurrentImage = new QImage( xSize, ySize, QImage::Format_ARGB32 );
5697+
mCurrentImage->fill( qRgba( 255, 255, 255, 0 ) );
5698+
}
5699+
else
5700+
{
5701+
mCurrentImage = 0;
5702+
}
5703+
return true;
5704+
}
5705+
5706+
void QgsRasterImageBuffer::drawPixelRectangle()
5707+
{
5708+
// Set up the initial offset into the myQImage we want to copy to the map canvas
5709+
// This is useful when the source image pixels are larger than the screen image.
5710+
int paintXoffset = 0;
5711+
int paintYoffset = 0;
5712+
5713+
if ( mMapToPixel )
5714+
{
5715+
paintXoffset = static_cast<int>(
5716+
( mViewPort->rectXOffsetFloat -
5717+
mViewPort->rectXOffset )
5718+
/ mMapToPixel->mapUnitsPerPixel()
5719+
* fabs( mGeoTransform[1] )
5720+
);
5721+
5722+
paintYoffset = static_cast<int>(
5723+
( mViewPort->rectYOffsetFloat -
5724+
mViewPort->rectYOffset )
5725+
/ mMapToPixel->mapUnitsPerPixel()
5726+
* fabs( mGeoTransform[5] )
5727+
);
5728+
}
5729+
5730+
//fix for zoomed in rasters
5731+
//Catch special rendering cases
5732+
//INSTANCE: 1x1
5733+
if ( 1 == mViewPort->clippedWidth && 1 == mViewPort->clippedHeight )
5734+
{
5735+
QColor myColor( mCurrentImage->pixel( 0, 0 ) );
5736+
myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) );
5737+
mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ),
5738+
static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ),
5739+
static_cast<int>( mViewPort->bottomRightPoint.x() ),
5740+
static_cast<int>( mViewPort->bottomRightPoint.y() ),
5741+
QBrush( myColor ) );
5742+
}
5743+
//1x2, 2x1 or 2x2
5744+
else if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight )
5745+
{
5746+
int myPixelBoundaryX = 0;
5747+
int myPixelBoundaryY = 0;
5748+
if ( mMapToPixel )
5749+
{
5750+
myPixelBoundaryX = static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ) + static_cast<int>( fabs( mGeoTransform[1] / mMapToPixel->mapUnitsPerPixel() ) ) - paintXoffset;
5751+
myPixelBoundaryY = static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ) + static_cast<int>( fabs( mGeoTransform[5] / mMapToPixel->mapUnitsPerPixel() ) ) - paintYoffset;
5752+
}
5753+
5754+
//INSTANCE: 1x2
5755+
if ( 1 == mViewPort->clippedWidth )
5756+
{
5757+
QColor myColor( mCurrentImage->pixel( 0, 0 ) );
5758+
myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) );
5759+
mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ),
5760+
static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ),
5761+
static_cast<int>( mViewPort->bottomRightPoint.x() ),
5762+
static_cast<int>( myPixelBoundaryY ),
5763+
QBrush( myColor ) );
5764+
myColor = QColor( mCurrentImage->pixel( 0, 1 ) );
5765+
myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 1 ) ) );
5766+
mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ),
5767+
static_cast<int>( myPixelBoundaryY ),
5768+
static_cast<int>( mViewPort->bottomRightPoint.x() ),
5769+
static_cast<int>( mViewPort->bottomRightPoint.y() ),
5770+
QBrush( myColor ) );
5771+
}
5772+
else
5773+
{
5774+
//INSTANCE: 2x1
5775+
if ( 1 == mViewPort->clippedHeight )
5776+
{
5777+
QColor myColor( mCurrentImage->pixel( 0, 0 ) );
5778+
myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) );
5779+
mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ),
5780+
static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ),
5781+
static_cast<int>( myPixelBoundaryX ),
5782+
static_cast<int>( mViewPort->bottomRightPoint.y() ),
5783+
QBrush( myColor ) );
5784+
myColor = QColor( mCurrentImage->pixel( 1, 0 ) );
5785+
myColor.setAlpha( qAlpha( mCurrentImage->pixel( 1, 0 ) ) );
5786+
mPainter->fillRect( static_cast<int>( myPixelBoundaryX ),
5787+
static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ),
5788+
static_cast<int>( mViewPort->bottomRightPoint.x() ),
5789+
static_cast<int>( mViewPort->bottomRightPoint.y() ),
5790+
QBrush( myColor ) );
5791+
}
5792+
//INSTANCE: 2x2
5793+
else
5794+
{
5795+
QColor myColor( mCurrentImage->pixel( 0, 0 ) );
5796+
myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) );
5797+
mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ),
5798+
static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ),
5799+
static_cast<int>( myPixelBoundaryX ),
5800+
static_cast<int>( myPixelBoundaryY ),
5801+
QBrush( myColor ) );
5802+
myColor = QColor( mCurrentImage->pixel( 1, 0 ) );
5803+
myColor.setAlpha( qAlpha( mCurrentImage->pixel( 1, 0 ) ) );
5804+
mPainter->fillRect( static_cast<int>( myPixelBoundaryX ),
5805+
static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ),
5806+
static_cast<int>( mViewPort->bottomRightPoint.x() ),
5807+
static_cast<int>( myPixelBoundaryY ),
5808+
QBrush( myColor ) );
5809+
myColor = QColor( mCurrentImage->pixel( 0, 1 ) );
5810+
myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 1 ) ) );
5811+
mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ),
5812+
static_cast<int>( myPixelBoundaryY ),
5813+
static_cast<int>( myPixelBoundaryX ),
5814+
static_cast<int>( mViewPort->bottomRightPoint.y() ),
5815+
QBrush( myColor ) );
5816+
myColor = QColor( mCurrentImage->pixel( 1, 1 ) );
5817+
myColor.setAlpha( qAlpha( mCurrentImage->pixel( 1, 1 ) ) );
5818+
mPainter->fillRect( static_cast<int>( myPixelBoundaryX ),
5819+
static_cast<int>( myPixelBoundaryY ),
5820+
static_cast<int>( mViewPort->bottomRightPoint.x() ),
5821+
static_cast<int>( mViewPort->bottomRightPoint.y() ),
5822+
QBrush( myColor ) );
5823+
}
5824+
}
5825+
}
5826+
}

‎src/core/raster/qgsrasterlayer.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,4 +881,59 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
881881
bool mValidNoDataValue;
882882
};
883883

884+
/*#include <QColor>
885+
886+
typedef void* GDALRasterBandH;
887+
class QgsMapToPixel;
888+
struct QgsRasterViewPort;
889+
class QImage;
890+
class QPainter;*/
891+
892+
/**A class encapsulates reading from a raster band and drawing the pixels to a painter.
893+
The class allows sequential reading of the scan lines and setting the image scan line pixels. It automatically decides
894+
on how much of the band / image should stay in virtual memory at a time*/
895+
class CORE_EXPORT QgsRasterImageBuffer
896+
{
897+
public:
898+
QgsRasterImageBuffer( GDALRasterBandH rasterBand, QPainter* p, \
899+
QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel, double* mGeoTransform );
900+
~QgsRasterImageBuffer();
901+
void reset( int maxPixelsInVirtualMemory = 5000000 );
902+
/**Returns a pointer to the next scan line (or 0 if end)*/
903+
bool nextScanLine( QRgb** imageScanLine, void** rasterScanLine );
904+
905+
void setWritingEnabled( bool enabled ) { mWritingEnabled = enabled; }
906+
907+
private:
908+
QgsRasterImageBuffer(); //forbidden
909+
/**Creates next part image. Returns false if at end*/
910+
bool createNextPartImage();
911+
912+
/**Peter's fix for zoomed in rasters*/
913+
void drawPixelRectangle();
914+
915+
GDALRasterBandH mRasterBand; //raster band
916+
QPainter* mPainter;
917+
QgsRasterViewPort* mViewPort;
918+
const QgsMapToPixel* mMapToPixel;
919+
double* mGeoTransform;
920+
921+
bool mValid;
922+
/**True (default), if values are written to an image. If false, the class only reads the values, but does not create an image*/
923+
bool mWritingEnabled;
924+
/**Draws the raster pixels as rectangles. This is only used if the map units per pixel is very, very small*/
925+
bool mDrawPixelRect;
926+
int mCurrentRow;
927+
int mNumPartImages; //number of part images
928+
int mNumRasterRowsPerPart; //number of (raster source) rows per part
929+
int mCurrentPartRasterMin; //minimum (raster source) row of current image
930+
int mCurrentPartRasterMax; //maximum (raster source) row of current image
931+
int mCurrentPartImageRow; //current image row
932+
int mNumCurrentImageRows; //number of image rows for the current part
933+
934+
//current memory image and gdal scan data
935+
QImage* mCurrentImage;
936+
void* mCurrentGDALData;
937+
};
938+
884939
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.