Skip to content

Commit

Permalink
For xyz/mapserver tiles, disable smooth pixmap transform when
Browse files Browse the repository at this point in the history
we are rendering at native tile resolutions (or just close enough to)

This allows pixel-perfect rendering of tiles at native resolutions
  • Loading branch information
nyalldawson committed Jun 7, 2019
1 parent 493b17c commit 1c9586a
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 9 deletions.
13 changes: 11 additions & 2 deletions src/providers/arcgisrest/qgsamsprovider.cpp
Expand Up @@ -536,7 +536,9 @@ QImage QgsAmsProvider::draw( const QgsRectangle &viewExtent, int pixelWidth, int
QImage localImage;
if ( QgsTileCache::tile( r.url, localImage ) )
{
tileImages << TileImage( r.rect, localImage );
// if image size is "close enough" to destination size, don't smooth it out. Instead try for pixel-perfect placement!
bool disableSmoothing = ( qgsDoubleNear( r.rect.width(), tileWidth, 2 ) && qgsDoubleNear( r.rect.height(), tileHeight, 2 ) );
tileImages << TileImage( r.rect, localImage, !disableSmoothing );
}
else
{
Expand All @@ -556,6 +558,7 @@ QImage QgsAmsProvider::draw( const QgsRectangle &viewExtent, int pixelWidth, int
// from lower or higher resolution available to give the user a bit of context
// while loading the right resolution
p.setCompositionMode( QPainter::CompositionMode_Source );
p.setRenderHint( QPainter::SmoothPixmapTransform, false ); // let's not waste time with bilinear filtering

auto fetchOtherResTiles = [&getRequests]( int otherLevel, QList< TileImage> &otherResTiles, QList< QRectF > &missingRects )
{
Expand All @@ -568,7 +571,7 @@ QImage QgsAmsProvider::draw( const QgsRectangle &viewExtent, int pixelWidth, int
if ( ! QgsTileCache::tile( r.url, localImage ) )
continue;

otherResTiles << TileImage( r.rect, localImage );
otherResTiles << TileImage( r.rect, localImage, false );

// see if there are any missing rects that are completely covered by this tile
for ( const QRectF &missingRect : qgis::as_const( missingRects ) )
Expand Down Expand Up @@ -619,6 +622,8 @@ QImage QgsAmsProvider::draw( const QgsRectangle &viewExtent, int pixelWidth, int
// draw composite in this resolution
for ( const TileImage &ti : qgis::as_const( tileImages ) )
{
if ( ti.smooth )
p.setRenderHint( QPainter::SmoothPixmapTransform, true );
p.drawImage( ti.rect, ti.img );
}

Expand Down Expand Up @@ -1048,6 +1053,10 @@ void QgsAmsTiledImageDownloadHandler::tileReplyFinished()
if ( !myLocalImage.isNull() )
{
QPainter p( mImage );
// if image size is "close enough" to destination size, don't smooth it out. Instead try for pixel-perfect placement!
const bool disableSmoothing = ( qgsDoubleNear( r.width(), myLocalImage.width(), 2 ) && qgsDoubleNear( r.height(), myLocalImage.height(), 2 ) );
if ( !disableSmoothing )
p.setRenderHint( QPainter::SmoothPixmapTransform, true );
p.drawImage( r, myLocalImage );
p.end();

Expand Down
3 changes: 2 additions & 1 deletion src/providers/arcgisrest/qgsamsprovider.h
Expand Up @@ -113,9 +113,10 @@ class QgsAmsProvider : public QgsRasterDataProvider
//! Helper structure to store a cached tile image with its rectangle
typedef struct TileImage
{
TileImage( const QRectF &r, const QImage &i ): rect( r ), img( i ) {}
TileImage( const QRectF &r, const QImage &i, bool smooth ): rect( r ), img( i ), smooth( smooth ) {}
QRectF rect; //!< Destination rectangle for a tile (in screen coordinates)
QImage img; //!< Cached tile to be drawn
bool smooth;
} TileImage;

protected:
Expand Down
13 changes: 8 additions & 5 deletions src/providers/wms/qgswmsprovider.cpp
Expand Up @@ -565,7 +565,7 @@ void QgsWmsProvider::fetchOtherResTiles( QgsTileMode tileMode, const QgsRectangl
( viewExtent.yMaximum() - r.rect.bottom() ) / cr,
r.rect.width() / cr,
r.rect.height() / cr );
otherResTiles << TileImage( dst, localImage );
otherResTiles << TileImage( dst, localImage, false );

// see if there are any missing rects that are completely covered by this tile
const auto constMissingRects = missingRects;
Expand Down Expand Up @@ -782,12 +782,13 @@ QImage *QgsWmsProvider::draw( QgsRectangle const &viewExtent, int pixelWidth, in
if ( QgsTileCache::tile( r.url, localImage ) )
{
double cr = viewExtent.width() / image->width();

QRectF dst( ( r.rect.left() - viewExtent.xMinimum() ) / cr,
( viewExtent.yMaximum() - r.rect.bottom() ) / cr,
r.rect.width() / cr,
r.rect.height() / cr );
tileImages << TileImage( dst, localImage );
// if image size is "close enough" to destination size, don't smooth it out. Instead try for pixel-perfect placement!
bool disableSmoothing = ( qgsDoubleNear( dst.width(), tm->tileWidth, 2 ) && qgsDoubleNear( dst.height(), tm->tileHeight, 2 ) );
tileImages << TileImage( dst, localImage, !disableSmoothing );
}
else
{
Expand Down Expand Up @@ -849,7 +850,7 @@ QImage *QgsWmsProvider::draw( QgsRectangle const &viewExtent, int pixelWidth, in
const auto constTileImages = tileImages;
for ( const TileImage &ti : constTileImages )
{
if ( mSettings.mSmoothPixmapTransform )
if ( ti.smooth && mSettings.mSmoothPixmapTransform )
p.setRenderHint( QPainter::SmoothPixmapTransform, true );
p.drawImage( ti.rect, ti.img );

Expand Down Expand Up @@ -3949,7 +3950,9 @@ void QgsWmsTiledImageDownloadHandler::tileReplyFinished()
if ( !myLocalImage.isNull() )
{
QPainter p( mImage );
if ( mSmoothPixmapTransform )
// if image size is "close enough" to destination size, don't smooth it out. Instead try for pixel-perfect placement!
const bool disableSmoothing = ( qgsDoubleNear( dst.width(), myLocalImage.width(), 2 ) && qgsDoubleNear( dst.height(), myLocalImage.height(), 2 ) );
if ( !disableSmoothing && mSmoothPixmapTransform )
p.setRenderHint( QPainter::SmoothPixmapTransform, true );
p.drawImage( dst, myLocalImage );
p.end();
Expand Down
3 changes: 2 additions & 1 deletion src/providers/wms/qgswmsprovider.h
Expand Up @@ -336,9 +336,10 @@ class QgsWmsProvider : public QgsRasterDataProvider
//! Helper structure to store a cached tile image with its rectangle
typedef struct TileImage
{
TileImage( const QRectF &r, const QImage &i ): rect( r ), img( i ) {}
TileImage( const QRectF &r, const QImage &i, bool smooth ): rect( r ), img( i ), smooth( smooth ) {}
QRectF rect; //!< Destination rectangle for a tile (in screen coordinates)
QImage img; //!< Cached tile to be drawn
bool smooth; //!< Whether to use antialiasing/smooth transforms when rendering tile
} TileImage;
//! Gets tiles from a different resolution to cover the missing areas
void fetchOtherResTiles( QgsTileMode tileMode, const QgsRectangle &viewExtent, int imageWidth, QList<QRectF> &missing, double tres, int resOffset, QList<TileImage> &otherResTiles );
Expand Down

0 comments on commit 1c9586a

Please sign in to comment.