Skip to content

Commit

Permalink
Merge pull request #3559 from nyalldawson/fix_render_flashing
Browse files Browse the repository at this point in the history
Fix layers with layer wide opacity "flashing" while rendering
  • Loading branch information
nyalldawson committed Oct 4, 2016
2 parents d3f8763 + 377de52 commit b4a70c7
Show file tree
Hide file tree
Showing 7 changed files with 23 additions and 28 deletions.
26 changes: 13 additions & 13 deletions scripts/generate_test_mask_image.py
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Expand Down Expand Up @@ -35,12 +35,12 @@
import argparse
from PyQt5.QtGui import QImage, QColor, qRed, qBlue, qGreen, qAlpha, qRgb
import struct
import urllib2
import urllib.request, urllib.error, urllib.parse
import glob


def error(msg):
print msg
print(msg)
sys.exit(1)


Expand All @@ -53,9 +53,9 @@ def colorDiff(c1, c2):


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
data = urllib2.urlopen(path).read()
data = urllib.request.urlopen(path).read()
image = QImage()
image.loadFromData(data)
else:
Expand Down Expand Up @@ -88,7 +88,7 @@ def getControlImagePath(path):
error('No matching control images found for {}'.format(path))

found_image = filtered_images[0]
print 'Found matching control image: {}'.format(found_image)
print('Found matching control image: {}'.format(found_image))
return found_image


Expand All @@ -101,30 +101,30 @@ def updateMask(control_image_path, rendered_image_path, mask_image_path):
if not rendered_image:
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():
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(),
rendered_image.width(),
rendered_image.height()))
rendered_image.height())))

max_width = min(rendered_image.width(), control_image.width())
max_height = min(rendered_image.height(), control_image.height())

#read current mask, if it exist
mask_image = imageFromPath(mask_image_path)
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.fill(QColor(0, 0, 0))

#loop through pixels in rendered image and compare
mismatch_count = 0
linebytes = max_width * 4
for y in xrange(max_height):
for y in range(max_height):
control_scanline = control_image.constScanLine(y).asstring(linebytes)
rendered_scanline = rendered_image.constScanLine(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])

if currentTolerance == 255:
Expand All @@ -143,9 +143,9 @@ def updateMask(control_image_path, rendered_image_path, mask_image_path):
if mismatch_count:
#update mask
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:
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.add_argument('control_image')
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsmaprenderercustompainterjob.cpp
Expand Up @@ -260,7 +260,9 @@ void QgsMapRendererCustomPainterJob::doRender()
if ( job.img )
{
// If we flattened this layer for alternate blend modes, composite it now
mPainter->setOpacity( job.opacity );
mPainter->drawImage( 0, 0, *job.img );
mPainter->setOpacity( 1.0 );
}

}
Expand Down
7 changes: 7 additions & 0 deletions src/core/qgsmaprendererjob.cpp
Expand Up @@ -245,6 +245,11 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsLabelingEn
job.cached = false;
job.img = nullptr;
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.renderingTime = -1;

Expand Down Expand Up @@ -360,8 +365,10 @@ QImage QgsMapRendererJob::composeImage( const QgsMapSettings& settings, const La
const LayerRenderJob& job = *it;

painter.setCompositionMode( job.blendMode );
painter.setOpacity( job.opacity );

Q_ASSERT( job.img );

painter.drawImage( 0, 0, *job.img );
}

Expand Down
1 change: 1 addition & 0 deletions src/core/qgsmaprendererjob.h
Expand Up @@ -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)
QgsMapLayerRenderer* renderer; // must be deleted
QPainter::CompositionMode blendMode;
double opacity;
bool cached; // if true, img already contains cached image from previous rendering
QString layerId;
int renderingTime; //!< time it took to render the layer in ms (it is -1 if not rendered or still rendering)
Expand Down
14 changes: 0 additions & 14 deletions src/core/qgsvectorlayerrenderer.cpp
Expand Up @@ -55,7 +55,6 @@ QgsVectorLayerRenderer::QgsVectorLayerRenderer( QgsVectorLayer* layer, QgsRender
, mDiagrams( false )
, mLabelProvider( nullptr )
, mDiagramProvider( nullptr )
, mLayerTransparency( 0 )
{
mSource = new QgsVectorLayerFeatureSource( layer );

Expand All @@ -66,7 +65,6 @@ QgsVectorLayerRenderer::QgsVectorLayerRenderer( QgsVectorLayer* layer, QgsRender

mGeometryType = layer->geometryType();

mLayerTransparency = layer->layerTransparency();
mFeatureBlendMode = layer->featureBlendMode();

mSimplifyMethod = layer->simplifyMethod();
Expand Down Expand Up @@ -264,18 +262,6 @@ bool QgsVectorLayerRenderer::render()
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;
}

Expand Down
1 change: 0 additions & 1 deletion src/core/qgsvectorlayerrenderer.h
Expand Up @@ -136,7 +136,6 @@ class QgsVectorLayerRenderer : public QgsMapLayerRenderer
//! may be null. no need to delete: if exists it is owned by labeling engine
QgsVectorLayerDiagramProvider* mDiagramProvider;

int mLayerTransparency;
QPainter::CompositionMode mFeatureBlendMode;

QgsVectorSimplifyMethod mSimplifyMethod;
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b4a70c7

Please sign in to comment.