diff --git a/scripts/generate_test_mask_image.py b/scripts/generate_test_mask_image.py index 18914ce1ed3..fcd62935876 100755 --- a/scripts/generate_test_mask_image.py +++ b/scripts/generate_test_mask_image.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ @@ -35,12 +35,12 @@ import sys 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) @@ -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: @@ -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 @@ -101,10 +101,10 @@ 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()) @@ -112,19 +112,19 @@ def updateMask(control_image_path, rendered_image_path, mask_image_path): #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: @@ -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') diff --git a/src/core/qgsmaprenderercustompainterjob.cpp b/src/core/qgsmaprenderercustompainterjob.cpp index c572e49a84d..67e07bac74d 100644 --- a/src/core/qgsmaprenderercustompainterjob.cpp +++ b/src/core/qgsmaprenderercustompainterjob.cpp @@ -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 ); } } diff --git a/src/core/qgsmaprendererjob.cpp b/src/core/qgsmaprendererjob.cpp index 01c012447da..5ea92d336fa 100644 --- a/src/core/qgsmaprendererjob.cpp +++ b/src/core/qgsmaprendererjob.cpp @@ -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( ml ) ) + { + job.opacity = 1.0 - vl->layerTransparency() / 100.0; + } job.layerId = ml->id(); job.renderingTime = -1; @@ -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 ); } diff --git a/src/core/qgsmaprendererjob.h b/src/core/qgsmaprendererjob.h index b37815663dc..ff57843cd96 100644 --- a/src/core/qgsmaprendererjob.h +++ b/src/core/qgsmaprendererjob.h @@ -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) diff --git a/src/core/qgsvectorlayerrenderer.cpp b/src/core/qgsvectorlayerrenderer.cpp index d9630eaf057..f07ed9fc773 100644 --- a/src/core/qgsvectorlayerrenderer.cpp +++ b/src/core/qgsvectorlayerrenderer.cpp @@ -55,7 +55,6 @@ QgsVectorLayerRenderer::QgsVectorLayerRenderer( QgsVectorLayer* layer, QgsRender , mDiagrams( false ) , mLabelProvider( nullptr ) , mDiagramProvider( nullptr ) - , mLayerTransparency( 0 ) { mSource = new QgsVectorLayerFeatureSource( layer ); @@ -66,7 +65,6 @@ QgsVectorLayerRenderer::QgsVectorLayerRenderer( QgsVectorLayer* layer, QgsRender mGeometryType = layer->geometryType(); - mLayerTransparency = layer->layerTransparency(); mFeatureBlendMode = layer->featureBlendMode(); mSimplifyMethod = layer->simplifyMethod(); @@ -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; } diff --git a/src/core/qgsvectorlayerrenderer.h b/src/core/qgsvectorlayerrenderer.h index 70774e2090c..3a4ba17bf7c 100644 --- a/src/core/qgsvectorlayerrenderer.h +++ b/src/core/qgsvectorlayerrenderer.h @@ -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; diff --git a/tests/testdata/control_images/expected_vector_layertransparency/default/expected_vector_layertransparency_mask.png b/tests/testdata/control_images/expected_vector_layertransparency/default/expected_vector_layertransparency_mask.png index 97a4ae9bce6..16070fb00e1 100644 Binary files a/tests/testdata/control_images/expected_vector_layertransparency/default/expected_vector_layertransparency_mask.png and b/tests/testdata/control_images/expected_vector_layertransparency/default/expected_vector_layertransparency_mask.png differ