QGIS API Documentation 3.99.0-Master (357b655ed83)
Loading...
Searching...
No Matches
qgsblureffect.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsblureffect.cpp
3 -----------------
4 begin : December 2014
5 copyright : (C) 2014 Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgsblureffect.h"
19
20#include "qgsimageoperation.h"
21#include "qgsrendercontext.h"
22#include "qgssymbollayerutils.h"
23#include "qgsunittypes.h"
24
25#include <QString>
26
27using namespace Qt::StringLiterals;
28
29QgsPaintEffect *QgsBlurEffect::create( const QVariantMap &map )
30{
31 QgsBlurEffect *newEffect = new QgsBlurEffect();
32 newEffect->readProperties( map );
33 return newEffect;
34}
35
40
42{
43 if ( !enabled() || !context.painter() || source().isNull() )
44 return;
45
47 {
48 //just draw unmodified source, we can't render this effect when forcing vectors
49 drawSource( *context.painter() );
50 return;
51 }
52
53 switch ( mBlurMethod )
54 {
55 case StackBlur:
56 drawStackBlur( context );
57 break;
58 case GaussianBlur:
59 drawGaussianBlur( context );
60 break;
61 }
62}
63
64void QgsBlurEffect::drawStackBlur( QgsRenderContext &context )
65{
66 const int blurLevel = std::round( context.convertToPainterUnits( mBlurLevel, mBlurUnit, mBlurMapUnitScale, Qgis::RenderSubcomponentProperty::BlurSize ) );
67
68 QImage im = sourceAsImage( context ).copy();
69 QgsImageOperation::stackBlur( im, blurLevel, false, context.feedback() );
70 drawBlurredImage( context, im );
71}
72
73void QgsBlurEffect::drawGaussianBlur( QgsRenderContext &context )
74{
75 const int blurLevel = std::round( context.convertToPainterUnits( mBlurLevel, mBlurUnit, mBlurMapUnitScale, Qgis::RenderSubcomponentProperty::BlurSize ) );
76
77 QImage source = sourceAsImage( context ).copy();
78 QImage *im = QgsImageOperation::gaussianBlur( source, blurLevel, context.feedback() );
79 if ( !im->isNull() )
80 drawBlurredImage( context, *im );
81 delete im;
82}
83
84void QgsBlurEffect::drawBlurredImage( QgsRenderContext &context, QImage &image )
85{
86 //opacity
87 QgsImageOperation::multiplyOpacity( image, mOpacity, context.feedback() );
88
89 QPainter *painter = context.painter();
90 const QgsScopedQPainterState painterState( painter );
91 painter->setCompositionMode( mBlendMode );
92 painter->drawImage( imageOffset( context ), image );
93}
94
95QVariantMap QgsBlurEffect::properties() const
96{
97 QVariantMap props;
98 props.insert( u"enabled"_s, mEnabled ? u"1"_s : u"0"_s );
99 props.insert( u"draw_mode"_s, QString::number( static_cast< int >( mDrawMode ) ) );
100 props.insert( u"blend_mode"_s, QString::number( static_cast< int >( mBlendMode ) ) );
101 props.insert( u"opacity"_s, QString::number( mOpacity ) );
102 props.insert( u"blur_level"_s, QString::number( mBlurLevel ) );
103 props.insert( u"blur_unit"_s, QgsUnitTypes::encodeUnit( mBlurUnit ) );
104 props.insert( u"blur_unit_scale"_s, QgsSymbolLayerUtils::encodeMapUnitScale( mBlurMapUnitScale ) );
105 props.insert( u"blur_method"_s, QString::number( static_cast< int >( mBlurMethod ) ) );
106 return props;
107}
108
109void QgsBlurEffect::readProperties( const QVariantMap &props )
110{
111 bool ok;
112 const QPainter::CompositionMode mode = static_cast< QPainter::CompositionMode >( props.value( u"blend_mode"_s ).toInt( &ok ) );
113 if ( ok )
114 {
115 mBlendMode = mode;
116 }
117 if ( props.contains( u"transparency"_s ) )
118 {
119 const double transparency = props.value( u"transparency"_s ).toDouble( &ok );
120 if ( ok )
121 {
122 mOpacity = 1.0 - transparency;
123 }
124 }
125 else
126 {
127 const double opacity = props.value( u"opacity"_s ).toDouble( &ok );
128 if ( ok )
129 {
130 mOpacity = opacity;
131 }
132 }
133
134 mEnabled = props.value( u"enabled"_s, u"1"_s ).toInt();
135 mDrawMode = static_cast< QgsPaintEffect::DrawMode >( props.value( u"draw_mode"_s, u"2"_s ).toInt() );
136 const double level = props.value( u"blur_level"_s ).toDouble( &ok );
137 if ( ok )
138 {
139 mBlurLevel = level;
140 if ( !props.contains( u"blur_unit"_s ) )
141 {
142 // deal with pre blur unit era by assuming 96 dpi and converting pixel values as millimeters
143 mBlurLevel *= 0.2645;
144 }
145 }
146 mBlurUnit = QgsUnitTypes::decodeRenderUnit( props.value( u"blur_unit"_s ).toString() );
147 mBlurMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( u"blur_unit_scale"_s ).toString() );
148 const QgsBlurEffect::BlurMethod method = static_cast< QgsBlurEffect::BlurMethod >( props.value( u"blur_method"_s ).toInt( &ok ) );
149 if ( ok )
150 {
151 mBlurMethod = method;
152 }
153}
154
156{
157 QgsBlurEffect *newEffect = new QgsBlurEffect( *this );
158 return newEffect;
159}
160
161QRectF QgsBlurEffect::boundingRect( const QRectF &rect, const QgsRenderContext &context ) const
162{
163 const int blurLevel = std::round( context.convertToPainterUnits( mBlurLevel, mBlurUnit, mBlurMapUnitScale, Qgis::RenderSubcomponentProperty::BlurSize ) );
164
165 //plus possible extension due to blur, with a couple of extra pixels thrown in for safety
166 const double spread = blurLevel * 2.0 + 10;
167 return rect.adjusted( -spread, -spread, spread, spread );
168}
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
Definition qgis.h:2764
@ RequiresRasterization
The effect requires raster-based rendering.
Definition qgis.h:2864
QFlags< PaintEffectFlag > PaintEffectFlags
Flags which control how paint effects behave.
Definition qgis.h:2873
QgsBlurEffect * clone() const override
Duplicates an effect by creating a deep copy of the effect.
QVariantMap properties() const override
Returns the properties describing the paint effect encoded in a string format.
void draw(QgsRenderContext &context) override
Handles drawing of the effect's result on to the specified render context.
QRectF boundingRect(const QRectF &rect, const QgsRenderContext &context) const override
Returns the bounding rect required for drawing the effect.
static QgsPaintEffect * create(const QVariantMap &map)
Creates a new QgsBlurEffect effect from a properties string map.
QgsBlurEffect()=default
void readProperties(const QVariantMap &props) override
Reads a string map of an effect's properties and restores the effect to the state described by the pr...
BlurMethod
Available blur methods (algorithms).
@ GaussianBlur
Gaussian blur, a slower but high quality blur. Blur level values are the distance in pixels for the b...
@ StackBlur
Stack blur, a fast but low quality blur. Valid blur level values are between 0 - 16.
Qgis::PaintEffectFlags flags() const override
Returns flags which specify how the paint effect behaves.
double opacity() const
Returns the opacity for the effect.
double blurLevel() const
Returns the blur level (radius).
static void multiplyOpacity(QImage &image, double factor, QgsFeedback *feedback=nullptr)
Multiplies opacity of image pixel values by a factor.
static QImage * gaussianBlur(QImage &image, int radius, QgsFeedback *feedback=nullptr)
Performs a gaussian blur on an image.
static void stackBlur(QImage &image, int radius, bool alphaOnly=false, QgsFeedback *feedback=nullptr)
Performs a stack blur on an image.
QgsPaintEffect()=default
void drawSource(QPainter &painter)
Draws the source QPicture onto the specified painter.
QImage sourceAsImage(QgsRenderContext &context)
Returns the source QPicture rendered to a new QImage.
const QPicture & source() const
Returns the source QPicture.
QPointF imageOffset(const QgsRenderContext &context) const
Returns the offset which should be used when drawing the source image on to a destination render cont...
bool enabled() const
Returns whether the effect is enabled.
DrawMode
Drawing modes for effects.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly during rendering to check if rendering shou...
Qgis::RasterizedRenderingPolicy rasterizedRenderingPolicy() const
Returns the policy controlling when rasterisation of content during renders is permitted.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static Q_INVOKABLE Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.