Skip to content

Commit

Permalink
[composer] Use last complete map render when previewing map items
Browse files Browse the repository at this point in the history
until a new cached preview is ready

Ensures that map items always show some content while a background
cache update is rendering
  • Loading branch information
nyalldawson committed May 6, 2017
1 parent ba46c87 commit 63a3037
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 16 deletions.
29 changes: 15 additions & 14 deletions src/core/composer/qgscomposermap.cpp
Expand Up @@ -124,7 +124,7 @@ QgsComposerMap::~QgsComposerMap()
}
}

/* This function is called by paint() and cache() to render the map. It does not override any functions
/* This function is called by paint() to render the map. It does not override any functions
from QGraphicsItem. */
void QgsComposerMap::draw( QPainter *painter, const QgsRectangle &extent, QSizeF size, double dpi, double *forceWidthScale )
{
Expand Down Expand Up @@ -218,7 +218,7 @@ void QgsComposerMap::cache()
disconnect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsComposerMap::painterJobFinished );
QgsMapRendererCustomPainterJob *oldJob = mPainterJob.release();
QPainter *oldPainter = mPainter.release();
QImage *oldImage = mCacheImage.release();
QImage *oldImage = mCacheRenderingImage.release();
connect( oldJob, &QgsMapRendererCustomPainterJob::finished, this, [oldPainter, oldJob, oldImage]
{
oldJob->deleteLater();
Expand All @@ -229,12 +229,12 @@ void QgsComposerMap::cache()
}
else
{
mCacheImage.reset( nullptr );
mCacheRenderingImage.reset( nullptr );
}

Q_ASSERT( !mPainterJob );
Q_ASSERT( !mPainter );
Q_ASSERT( !mCacheImage );
Q_ASSERT( !mCacheRenderingImage );

double horizontalVScaleFactor = horizontalViewScaleFactor();
if ( horizontalVScaleFactor < 0 )
Expand Down Expand Up @@ -265,26 +265,26 @@ void QgsComposerMap::cache()
}
}

mCacheImage.reset( new QImage( w, h, QImage::Format_ARGB32 ) );
mCacheRenderingImage.reset( new QImage( w, h, QImage::Format_ARGB32 ) );

// set DPI of the image
mCacheImage->setDotsPerMeterX( 1000 * w / widthMM );
mCacheImage->setDotsPerMeterY( 1000 * h / heightMM );
mCacheRenderingImage->setDotsPerMeterX( 1000 * w / widthMM );
mCacheRenderingImage->setDotsPerMeterY( 1000 * h / heightMM );

if ( hasBackground() )
{
//Initially fill image with specified background color. This ensures that layers with blend modes will
//preview correctly
mCacheImage->fill( backgroundColor().rgba() );
mCacheRenderingImage->fill( backgroundColor().rgba() );
}
else
{
//no background, but start with empty fill to avoid artifacts
mCacheImage->fill( QColor( 255, 255, 255, 0 ).rgba() );
mCacheRenderingImage->fill( QColor( 255, 255, 255, 0 ).rgba() );
}

mPainter.reset( new QPainter( mCacheImage.get() ) );
QgsMapSettings settings( mapSettings( ext, QSizeF( w, h ), mCacheImage->logicalDpiX() ) );
mPainter.reset( new QPainter( mCacheRenderingImage.get() ) );
QgsMapSettings settings( mapSettings( ext, QSizeF( w, h ), mCacheRenderingImage->logicalDpiX() ) );
mPainterJob.reset( new QgsMapRendererCustomPainterJob( settings, mPainter.get() ) );
connect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsComposerMap::painterJobFinished );
mPainterJob->start();
Expand All @@ -296,6 +296,7 @@ void QgsComposerMap::painterJobFinished()
mPainterJob.reset( nullptr );
mPainter.reset( nullptr );
mCacheUpdated = true;
mCacheFinalImage = std::move( mCacheRenderingImage );
updateItem();
}

Expand Down Expand Up @@ -327,22 +328,22 @@ void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *,
}
else if ( mComposition->plotStyle() == QgsComposition::Preview )
{
if ( !mCacheImage || mCacheImage->isNull() )
if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
{
cache();
return;
}

//Background color is already included in cached image, so no need to draw

double imagePixelWidth = mCacheImage->width(); //how many pixels of the image are for the map extent?
double imagePixelWidth = mCacheFinalImage->width(); //how many pixels of the image are for the map extent?
double scale = rect().width() / imagePixelWidth;

painter->save();

painter->translate( mXOffset, mYOffset );
painter->scale( scale, scale );
painter->drawImage( 0, 0, *mCacheImage );
painter->drawImage( 0, 0, *mCacheFinalImage );

//restore rotation
painter->restore();
Expand Down
11 changes: 9 additions & 2 deletions src/core/composer/qgscomposermap.h
Expand Up @@ -516,8 +516,15 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
// to manually tweak each atlas preview page without affecting the actual original map extent.
QgsRectangle mAtlasFeatureExtent;

// Cache used in composer preview
std::unique_ptr< QImage > mCacheImage;
// We have two images used for rendering/storing cached map images.
// the first (mCacheFinalImage) is used ONLY for storing the most recent completed map render. It's always
// used when drawing map item previews. The second (mCacheRenderingImage) is used temporarily while
// rendering a new preview image in the background. If (and only if) the background render completes, then
// mCacheRenderingImage is pushed into mCacheFinalImage, and used from then on when drawing the item preview.
// This ensures that something is always shown in the map item, even while refreshing the preview image in the
// background
std::unique_ptr< QImage > mCacheFinalImage;
std::unique_ptr< QImage > mCacheRenderingImage;

// Is cache up to date
bool mCacheUpdated = false;
Expand Down

0 comments on commit 63a3037

Please sign in to comment.