Merge pull request #3559 from nyalldawson/fix_render_flashing

Fix layers with layer wide opacity "flashing" while rendering
This commit is contained in:
Nyall Dawson 2016-10-04 15:40:30 +10:00 committed by GitHub
commit b4a70c771e
7 changed files with 23 additions and 28 deletions

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
@ -35,12 +35,12 @@ import sys
import argparse import argparse
from PyQt5.QtGui import QImage, QColor, qRed, qBlue, qGreen, qAlpha, qRgb from PyQt5.QtGui import QImage, QColor, qRed, qBlue, qGreen, qAlpha, qRgb
import struct import struct
import urllib2 import urllib.request, urllib.error, urllib.parse
import glob import glob
def error(msg): def error(msg):
print msg print(msg)
sys.exit(1) sys.exit(1)
@ -53,9 +53,9 @@ def colorDiff(c1, c2):
def imageFromPath(path): def imageFromPath(path):
if (path[:7] == 'http://' or path[:7] == 'file://'): if (path[:7] == 'http://' or path[:7] == 'file://' or path[:8] == 'https://'):
#fetch remote image #fetch remote image
data = urllib2.urlopen(path).read() data = urllib.request.urlopen(path).read()
image = QImage() image = QImage()
image.loadFromData(data) image.loadFromData(data)
else: else:
@ -88,7 +88,7 @@ def getControlImagePath(path):
error('No matching control images found for {}'.format(path)) error('No matching control images found for {}'.format(path))
found_image = filtered_images[0] found_image = filtered_images[0]
print 'Found matching control image: {}'.format(found_image) print('Found matching control image: {}'.format(found_image))
return found_image return found_image
@ -101,10 +101,10 @@ def updateMask(control_image_path, rendered_image_path, mask_image_path):
if not rendered_image: if not rendered_image:
error('Could not read rendered image {}'.format(rendered_image_path)) error('Could not read rendered image {}'.format(rendered_image_path))
if not rendered_image.width() == control_image.width() or not rendered_image.height() == control_image.height(): if not rendered_image.width() == control_image.width() or not rendered_image.height() == control_image.height():
print ('Size mismatch - control image is {}x{}, rendered image is {}x{}'.format(control_image.width(), print(('Size mismatch - control image is {}x{}, rendered image is {}x{}'.format(control_image.width(),
control_image.height(), control_image.height(),
rendered_image.width(), rendered_image.width(),
rendered_image.height())) rendered_image.height())))
max_width = min(rendered_image.width(), control_image.width()) max_width = min(rendered_image.width(), control_image.width())
max_height = min(rendered_image.height(), control_image.height()) max_height = min(rendered_image.height(), control_image.height())
@ -112,19 +112,19 @@ def updateMask(control_image_path, rendered_image_path, mask_image_path):
#read current mask, if it exist #read current mask, if it exist
mask_image = imageFromPath(mask_image_path) mask_image = imageFromPath(mask_image_path)
if mask_image.isNull(): if mask_image.isNull():
print 'Mask image does not exist, creating {}'.format(mask_image_path) print('Mask image does not exist, creating {}'.format(mask_image_path))
mask_image = QImage(control_image.width(), control_image.height(), QImage.Format_ARGB32) mask_image = QImage(control_image.width(), control_image.height(), QImage.Format_ARGB32)
mask_image.fill(QColor(0, 0, 0)) mask_image.fill(QColor(0, 0, 0))
#loop through pixels in rendered image and compare #loop through pixels in rendered image and compare
mismatch_count = 0 mismatch_count = 0
linebytes = max_width * 4 linebytes = max_width * 4
for y in xrange(max_height): for y in range(max_height):
control_scanline = control_image.constScanLine(y).asstring(linebytes) control_scanline = control_image.constScanLine(y).asstring(linebytes)
rendered_scanline = rendered_image.constScanLine(y).asstring(linebytes) rendered_scanline = rendered_image.constScanLine(y).asstring(linebytes)
mask_scanline = mask_image.scanLine(y).asstring(linebytes) mask_scanline = mask_image.scanLine(y).asstring(linebytes)
for x in xrange(max_width): for x in range(max_width):
currentTolerance = qRed(struct.unpack('I', mask_scanline[x * 4:x * 4 + 4])[0]) currentTolerance = qRed(struct.unpack('I', mask_scanline[x * 4:x * 4 + 4])[0])
if currentTolerance == 255: if currentTolerance == 255:
@ -143,9 +143,9 @@ def updateMask(control_image_path, rendered_image_path, mask_image_path):
if mismatch_count: if mismatch_count:
#update mask #update mask
mask_image.save(mask_image_path, "png") mask_image.save(mask_image_path, "png")
print 'Updated {} pixels in {}'.format(mismatch_count, mask_image_path) print('Updated {} pixels in {}'.format(mismatch_count, mask_image_path))
else: else:
print 'No mismatches in {}'.format(mask_image_path) print('No mismatches in {}'.format(mask_image_path))
parser = argparse.ArgumentParser() # OptionParser("usage: %prog control_image rendered_image mask_image") parser = argparse.ArgumentParser() # OptionParser("usage: %prog control_image rendered_image mask_image")
parser.add_argument('control_image') parser.add_argument('control_image')

View File

@ -260,7 +260,9 @@ void QgsMapRendererCustomPainterJob::doRender()
if ( job.img ) if ( job.img )
{ {
// If we flattened this layer for alternate blend modes, composite it now // If we flattened this layer for alternate blend modes, composite it now
mPainter->setOpacity( job.opacity );
mPainter->drawImage( 0, 0, *job.img ); mPainter->drawImage( 0, 0, *job.img );
mPainter->setOpacity( 1.0 );
} }
} }

View File

@ -245,6 +245,11 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsLabelingEn
job.cached = false; job.cached = false;
job.img = nullptr; job.img = nullptr;
job.blendMode = ml->blendMode(); job.blendMode = ml->blendMode();
job.opacity = 1.0;
if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml ) )
{
job.opacity = 1.0 - vl->layerTransparency() / 100.0;
}
job.layerId = ml->id(); job.layerId = ml->id();
job.renderingTime = -1; job.renderingTime = -1;
@ -360,8 +365,10 @@ QImage QgsMapRendererJob::composeImage( const QgsMapSettings& settings, const La
const LayerRenderJob& job = *it; const LayerRenderJob& job = *it;
painter.setCompositionMode( job.blendMode ); painter.setCompositionMode( job.blendMode );
painter.setOpacity( job.opacity );
Q_ASSERT( job.img ); Q_ASSERT( job.img );
painter.drawImage( 0, 0, *job.img ); painter.drawImage( 0, 0, *job.img );
} }

View File

@ -46,6 +46,7 @@ struct LayerRenderJob
QImage* img; // may be null if it is not necessary to draw to separate image (e.g. sequential rendering) QImage* img; // may be null if it is not necessary to draw to separate image (e.g. sequential rendering)
QgsMapLayerRenderer* renderer; // must be deleted QgsMapLayerRenderer* renderer; // must be deleted
QPainter::CompositionMode blendMode; QPainter::CompositionMode blendMode;
double opacity;
bool cached; // if true, img already contains cached image from previous rendering bool cached; // if true, img already contains cached image from previous rendering
QString layerId; QString layerId;
int renderingTime; //!< time it took to render the layer in ms (it is -1 if not rendered or still rendering) int renderingTime; //!< time it took to render the layer in ms (it is -1 if not rendered or still rendering)

View File

@ -55,7 +55,6 @@ QgsVectorLayerRenderer::QgsVectorLayerRenderer( QgsVectorLayer* layer, QgsRender
, mDiagrams( false ) , mDiagrams( false )
, mLabelProvider( nullptr ) , mLabelProvider( nullptr )
, mDiagramProvider( nullptr ) , mDiagramProvider( nullptr )
, mLayerTransparency( 0 )
{ {
mSource = new QgsVectorLayerFeatureSource( layer ); mSource = new QgsVectorLayerFeatureSource( layer );
@ -66,7 +65,6 @@ QgsVectorLayerRenderer::QgsVectorLayerRenderer( QgsVectorLayer* layer, QgsRender
mGeometryType = layer->geometryType(); mGeometryType = layer->geometryType();
mLayerTransparency = layer->layerTransparency();
mFeatureBlendMode = layer->featureBlendMode(); mFeatureBlendMode = layer->featureBlendMode();
mSimplifyMethod = layer->simplifyMethod(); mSimplifyMethod = layer->simplifyMethod();
@ -264,18 +262,6 @@ bool QgsVectorLayerRenderer::render()
mRenderer->paintEffect()->end( mContext ); mRenderer->paintEffect()->end( mContext );
} }
//apply layer transparency for vector layers
if ( mContext.useAdvancedEffects() && mLayerTransparency != 0 )
{
// a layer transparency has been set, so update the alpha for the flattened layer
// by combining it with the layer transparency
QColor transparentFillColor = QColor( 0, 0, 0, 255 - ( 255 * mLayerTransparency / 100 ) );
// use destination in composition mode to merge source's alpha with destination
mContext.painter()->setCompositionMode( QPainter::CompositionMode_DestinationIn );
mContext.painter()->fillRect( 0, 0, mContext.painter()->device()->width(),
mContext.painter()->device()->height(), transparentFillColor );
}
return true; return true;
} }

View File

@ -136,7 +136,6 @@ class QgsVectorLayerRenderer : public QgsMapLayerRenderer
//! may be null. no need to delete: if exists it is owned by labeling engine //! may be null. no need to delete: if exists it is owned by labeling engine
QgsVectorLayerDiagramProvider* mDiagramProvider; QgsVectorLayerDiagramProvider* mDiagramProvider;
int mLayerTransparency;
QPainter::CompositionMode mFeatureBlendMode; QPainter::CompositionMode mFeatureBlendMode;
QgsVectorSimplifyMethod mSimplifyMethod; QgsVectorSimplifyMethod mSimplifyMethod;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB