From 19f6b62cd8e99fc73e5f89f3c0f82f586d5214ec Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 3 Oct 2016 15:02:14 +1000 Subject: [PATCH 1/2] Fix layers with layer wide opacity "flashing" by rendering intermediate states without opacity --- src/core/qgsmaprenderercustompainterjob.cpp | 2 ++ src/core/qgsmaprendererjob.cpp | 7 +++++++ src/core/qgsmaprendererjob.h | 1 + src/core/qgsvectorlayerrenderer.cpp | 14 -------------- src/core/qgsvectorlayerrenderer.h | 1 - ...expected_vector_layertransparency_mask.png | Bin 11487 -> 11815 bytes 6 files changed, 10 insertions(+), 15 deletions(-) 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 97a4ae9bce63cedc31ca8b61cadf7ac103a20ca5..16070fb00e1a053a5348cb3b752eff8f7e8f8ab4 100644 GIT binary patch literal 11815 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

3V4LBKWXSr^8mgN5s>>0LqizYue9|9pwfaSa z$uGsZ42Eda2HfpNUYf91xa8yVtXuW7Nv@9?YPGC+C5PL+#_lXa&>LyGP3 z%4*=*q&gzwG(XLs4F;XtJFoa-0!i4|S~LT}je}JCrkagqfFD{Bnfcn&iMUm9YiHR) zvuyc;@Y)*F!(e(zr9Y>v%kxFLnPH0=qZf@zo}?9lOk5)BY?83F#M;H};?YB^y;--l zkFILuZ9?-qmXncka#h)@r_Qg9{@&c!JU*fz1{QSzZS&^JyeE#n@8<2iUv@z*x=KIa zD#tV=a=c2JUwST9zVdDk#NNb3*AFBT-&<-3;+?N~*u2pqOIbL#6Q+?!vAn=Yr62;` z>(WaX&opp@VU@x`uJI?w$fec3kizg+B_~eCE?=S3Vu$jcpRDn4)!5Tp{EUNGv==(7 zmb6u*?Q?$BaqX8xJU0apO#QDHz^8p%XfuXifJ>jin-a{IkaZvspVqr9MBiFcV$sA@ z3uE}K;_PoD-eTeOQCzK|#8S)Z&yC#5w*PsOOu*JT^mtfnIW)sO>1KyMg3*jmq-&Mq zqm%t-AL-1;wwB+`a&ZGE}Tvi4~ zqvR4|Kb?e6_J;ymi42&%^#}JB=fA$Lfd;xVufQ{*{y@iDA8K0RMXKXW%ZWeeo;!nd z8dHOrIO59E@<%5tjRI((7WVH|#cD_$y?h=v9qP~qu$`qzdL#4iD12#kk^y_(qJ{T5 ztxW;K((AOTKYV1%j~=bgOma!GITPuHMVu5c(R5<<$-QRAN2MuD7ls&;GDa&_e=@El z3c6Uf8wau?a%?5FjLMpd`6C+_nOwf9nqB8LZmLkb0TWGK>=n9T<-5SHLa7qC{itU` zt7RnWty!a&jip22?5tMx{rxL6s_-_jh1G0Jt61a@k@XL6pS~Fr?EFq^TB!T;vX_z+ znRG5E*PSBbs+=lC?V>o86O=DReL$SI-k#t`rMLVeE9oKa@aI*$V_+yf$~AS|5aCP;7`2Qq9p7T&@zOVAewQr@(S)UX$U3 zY4O^3tj9X4Z|{YpfDB)N&0xfZ8?@sC!h& zK0!?#=si+#0B9vPu1ysD{_E=aJZ0Frl&?|ndQmpRpt;78Q+?~TX>FU;%3iAW{_3Ig zDDxAg&%%y@)R$^O6>JpIfQJjnO4@f;w@`!8y1ftcs6U>0ev!99Qrj1- zFHvTA2BlT|;ifkWdpk}n*`EI6{h8m}i0Z(NptgO2G}l#``1u_8sYvhh(_u*8l5_k) zhpdFHj)C%Odek?u2-$f3AY(nl@vlSo?_Rmmh`lM7H!1(`fMzrc-c@0|ak5VCI_0LE z>{0jeKQ0`Y-Pvtjy~4%Wrz6}SQJZ^ne4Rc}2D|0_OS4<*{K-YQ6 z(2=L+1A5`>R63%^r@k?%sC|{GX0s5AWuD_A7Ixxxg1yvh&G`9k4W>>&B`!pzMK8d4 z1RCK5Va0)cS$fZ~6sz0f{9g6ThK$)q`^)5bo0a`FwWO;&tERj_ny41P$aVJ`$(KnB zdBIIg=<{ji-X|E%n;}olu`bbV^PZTINU<~K9nbNcMBMLmc;LpRx`eJ2$&kM7kGqz} z9~93bJ8vvabP=KB3g$`MZl!XhlFUs3-WL{q6l3sZQYX7nit?}QoiGY&GI}nyqS4Es z-g%V>O41lv7{atHRG{_t_Q$nDs~p+`k9apL6nU>x0Ax0vFnKcd*5MS5j(92jfW7$$Z&2x^q4k}_gh z<;l(KVxgU8^L_Jj?HFL~#t&$gYyg%VFk&u1QdC3eMl9(@J8ykH-U8?7J9tJ|&#JhB zoOGWzrO#_>Fevwta zOjivx<2W46@AJXdE+zz)%Ym*7tO{fq`aA;mykJq7XqEfE)7z+w>{gD7{S_2Kemvcw zJoc;0{}L8-(VQ}k`ByOAv8nZR?qD9F9S^;#0c)_QoEW8MQ$9a!$4$7Rk(DH-Aeg8P z!AjP~?*_;tb#+pCKh%C~Dhx54<=qLSVGd+uYv}AIm&5Rv+bJP=5{uSl0u|3m5pE8s z#`)X_S9LaM+5*`E@axje@YExPO0HPWf)_taW-Nxpc+FXI&>%kr78gR@(dK$R)1rHi z1{o|Wdhgq>)x{iGXIc`>OrO6FWemPz(sXneyj&RaeA1%(0y&FQ{vFfA`teN26V(w! zhFTmW{4z!d3+6OrbrOWQGEtn%E8K%kqIe%ewbXW__^NuvU{vs(0EP;hh1E9@GZUw7 zx1+nFb+vUS{7UkC4SU?1-M<>w8zpW~cgI6c@BWfv`dTc48k8}u=4%!%ocNEQ`*gNF z_uWUeBg{7&lcM=chm}X(lF*CSKlw_gEkL#3g%lc8fA-1?%OI@GH`IE~x29DS4#Nt?U(^poRv_i* zFUz0s{il`$F{#xFANDKEfBg>vL?B!%Dzn3gO1}n!lk&6vmPtDGT4ZAhmiCd zXD@O4qlO~*n2`GON>*;H_#_`JZ(d=fk`Yf6L-JE+iouvY8NJ?~xi552Ogg|Sh>w!u ze*=1OxYRL0cSIaltKP0aAGara)w3l5GzV`w6y?q7?KfPrDZ2xy*Jr^pdD($ z$daqlEfhPYJLbOmn?iOi@W<*mtJ2n9vS?%6j%hZlxne6_>NWH3h@Dz~#u z5nIm-*6JgoIqq5$InsL`r%#*5ddQ3A+wSd)3+ccOU4dNCiws%Xc53tlFC2##M68R@ zg^!}vMoJsNRANJX9t?i3ybAuiY?`GOl+TJkHV~?X%d)}gfOBT$EGi#V>X#8z;iFzn zN<47{y}3r3esp^<{Er&xm4@h!VA}F1XxYgUe^s&bVJ`RhggOd+hq))4pJoWeEl!1w zoV2T5WE;^-{%tbG^QC@I>WfYWP~YHtOe}1bFnZ9=$k#&fTq-NUsl|x4bM?F3vT>F= z3}#7q4wN>OcgA0nb4Fn9l&lDkOQw*vlwU;4NbI?%zmW@FX^J7gFI?ZI;(t>{p)39- z?6l)hJ+(QI%Xyjv-O7U<{A0EDM_YkvgGXac3n|m#m?OA2RH|4WzcEs0a}4P&rXy1p zxr+quGooExkq6uW22P9<3^Dk>Flbq+(>53T8Mk~*)%8TVY4sX=CoAD8<4a4qCIxXW zT29V*ZDlZa_BH?e49nG?3|uP%=G-zdF(w|}WJDf)?AG~G64qZhB%%v5Fw^5KP5&Tf zC0!0*#~JO+IQ=s8=!$jR+z3$A*)h4d`W2XeUVM(g)hh~r6FwOi(c(uH@d6!?X)n+u znPI)Jl7biRRNW^l0}xTPBCodm6Uf}j>6wK38U}DCtm^)f8{8oNG6o9`ZT0mSB8;kZ zp>e8z`-w)!FK=Rbaccwzr+;4=dRmUaW1VZEWWqv6cL(T3KPWuMoZ}Ttbaa4OfulPr z<9rR#UP{Hn2zc>r_}1QG1YZ$voG_+;Uq%M-nTnliSXYx`LYJ60On%mSRx^;~b>y=? zgt8~*LmK8|E)wOm003zAeqRz|@p=1e1vqIIn;xfM_VkjF##Gu8pMLDzo#tJ?to@DL zr%xU%-L0aLjR3;I-g*BQ#7RACpbRt_{_~Br|cMMfi@*}fW*%;}2}xiB&UvcCmOW5Odyu-wts1)5u0Fz%oA z=9M+=P&N(xMvsa4OQ6i?X?`WfJd3lItq0{~>m{x9MG dFUg)TAntg45mQ0I&#l@3m5-VV^>Uy8`#-~$gk%5! literal 11487 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 A^#A|> From 377de52b389999269abf5534df9f42861ce5e0dc Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 4 Oct 2016 09:19:41 +1000 Subject: [PATCH 2/2] Port generate_test_mask_image.py to python3 --- scripts/generate_test_mask_image.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) 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')