mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-08 00:05:09 -04:00
Merge pull request #3559 from nyalldawson/fix_render_flashing
Fix layers with layer wide opacity "flashing" while rendering
This commit is contained in:
commit
b4a70c771e
@ -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')
|
||||||
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 |
Loading…
x
Reference in New Issue
Block a user