QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsgloweffect.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsgloweffect.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 "qgsgloweffect.h"
19#include "qgssymbollayerutils.h"
20#include "qgsimageoperation.h"
21#include "qgscolorrampimpl.h"
22#include "qgsunittypes.h"
23
25 : mColor( Qt::white )
26{
27
28}
29
31 : QgsPaintEffect( other )
32{
33 operator=( other );
34}
35
37{
38 delete mRamp;
39}
40
42{
43 if ( !source() || !enabled() || !context.painter() )
44 return;
45
46 QImage im = sourceAsImage( context )->copy();
47
48 QgsColorRamp *ramp = nullptr;
49 std::unique_ptr< QgsGradientColorRamp > tempRamp;
50 if ( mColorType == ColorRamp && mRamp )
51 {
52 ramp = mRamp;
53 }
54 else
55 {
56 //create a temporary ramp
57 QColor transparentColor = mColor;
58 transparentColor.setAlpha( 0 );
59 tempRamp.reset( new QgsGradientColorRamp( mColor, transparentColor ) );
60 ramp = tempRamp.get();
61 }
62
65 dtProps.useMaxDistance = false;
66 dtProps.shadeExterior = shadeExterior();
67 dtProps.ramp = ramp;
68 QgsImageOperation::distanceTransform( im, dtProps, context.feedback() );
69
70 if ( context.feedback() && context.feedback()->isCanceled() )
71 return;
72
74 if ( blurLevel <= 16 )
75 {
76 QgsImageOperation::stackBlur( im, blurLevel, false, context.feedback() );
77 }
78 else
79 {
80 QImage *imb = QgsImageOperation::gaussianBlur( im, blurLevel, context.feedback() );
81 if ( !imb->isNull() )
82 im = QImage( *imb );
83 delete imb;
84 }
85
86 if ( context.feedback() && context.feedback()->isCanceled() )
87 return;
88
90
91 if ( context.feedback() && context.feedback()->isCanceled() )
92 return;
93
94 if ( !shadeExterior() )
95 {
96 //only keep interior portion
97 QPainter p( &im );
98 p.setRenderHint( QPainter::Antialiasing );
99 p.setCompositionMode( QPainter::CompositionMode_DestinationIn );
100 p.drawImage( 0, 0, *sourceAsImage( context ) );
101 p.end();
102 }
103
104 QPainter *painter = context.painter();
105 const QgsScopedQPainterState painterState( painter );
106 painter->setCompositionMode( mBlendMode );
107 painter->drawImage( imageOffset( context ), im );
108}
109
110QVariantMap QgsGlowEffect::properties() const
111{
112 QVariantMap props;
113 props.insert( QStringLiteral( "enabled" ), mEnabled ? "1" : "0" );
114 props.insert( QStringLiteral( "draw_mode" ), QString::number( int( mDrawMode ) ) );
115 props.insert( QStringLiteral( "blend_mode" ), QString::number( int( mBlendMode ) ) );
116 props.insert( QStringLiteral( "opacity" ), QString::number( mOpacity ) );
117 props.insert( QStringLiteral( "blur_level" ), QString::number( mBlurLevel ) );
118 props.insert( QStringLiteral( "blur_unit" ), QgsUnitTypes::encodeUnit( mBlurUnit ) );
119 props.insert( QStringLiteral( "blur_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mBlurMapUnitScale ) );
120 props.insert( QStringLiteral( "spread" ), QString::number( mSpread ) );
121 props.insert( QStringLiteral( "spread_unit" ), QgsUnitTypes::encodeUnit( mSpreadUnit ) );
122 props.insert( QStringLiteral( "spread_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mSpreadMapUnitScale ) );
123 props.insert( QStringLiteral( "color_type" ), QString::number( static_cast< int >( mColorType ) ) );
124 props.insert( QStringLiteral( "single_color" ), QgsSymbolLayerUtils::encodeColor( mColor ) );
125
126 if ( mRamp )
127 {
128#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
129 props.unite( mRamp->properties() );
130#else
131 props.insert( mRamp->properties() );
132#endif
133 }
134
135 return props;
136}
137
138void QgsGlowEffect::readProperties( const QVariantMap &props )
139{
140 bool ok;
141 const QPainter::CompositionMode mode = static_cast< QPainter::CompositionMode >( props.value( QStringLiteral( "blend_mode" ) ).toInt( &ok ) );
142 if ( ok )
143 {
144 mBlendMode = mode;
145 }
146 if ( props.contains( QStringLiteral( "transparency" ) ) )
147 {
148 const double transparency = props.value( QStringLiteral( "transparency" ) ).toDouble( &ok );
149 if ( ok )
150 {
151 mOpacity = 1.0 - transparency;
152 }
153 }
154 else
155 {
156 const double opacity = props.value( QStringLiteral( "opacity" ) ).toDouble( &ok );
157 if ( ok )
158 {
160 }
161 }
162 mEnabled = props.value( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ).toInt();
163 mDrawMode = static_cast< QgsPaintEffect::DrawMode >( props.value( QStringLiteral( "draw_mode" ), QStringLiteral( "2" ) ).toInt() );
164 const double level = props.value( QStringLiteral( "blur_level" ) ).toDouble( &ok );
165 if ( ok )
166 {
167 mBlurLevel = level;
168 if ( !props.contains( QStringLiteral( "blur_unit" ) ) )
169 {
170 // deal with pre blur unit era by assuming 96 dpi and converting pixel values as millimeters
171 mBlurLevel *= 0.2645;
172 }
173 }
174 mBlurUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "blur_unit" ) ).toString() );
175 mBlurMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "blur_unit_scale" ) ).toString() );
176 const double spread = props.value( QStringLiteral( "spread" ) ).toDouble( &ok );
177 if ( ok )
178 {
179 mSpread = spread;
180 }
181 mSpreadUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "spread_unit" ) ).toString() );
182 mSpreadMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "spread_unit_scale" ) ).toString() );
183 const QgsGlowEffect::GlowColorType type = static_cast< QgsGlowEffect::GlowColorType >( props.value( QStringLiteral( "color_type" ) ).toInt( &ok ) );
184 if ( ok )
185 {
187 }
188 if ( props.contains( QStringLiteral( "single_color" ) ) )
189 {
190 mColor = QgsSymbolLayerUtils::decodeColor( props.value( QStringLiteral( "single_color" ) ).toString() );
191 }
192
193 //attempt to create color ramp from props
194 delete mRamp;
195 if ( props.contains( QStringLiteral( "rampType" ) ) && props[QStringLiteral( "rampType" )] == QgsCptCityColorRamp::typeString() )
196 {
198 }
199 else
200 {
202 }
203}
204
206{
207 delete mRamp;
208 mRamp = ramp;
209}
210
212{
213 if ( &rhs == this )
214 return *this;
215
216 delete mRamp;
217
218 mSpread = rhs.spread();
219 mSpreadUnit = rhs.spreadUnit();
221 mRamp = rhs.ramp() ? rhs.ramp()->clone() : nullptr;
222 mBlurLevel = rhs.blurLevel();
223 mBlurUnit = rhs.mBlurUnit;
225 mOpacity = rhs.opacity();
226 mColor = rhs.color();
227 mBlendMode = rhs.blendMode();
228 mColorType = rhs.colorType();
229
230 return *this;
231}
232
233QRectF QgsGlowEffect::boundingRect( const QRectF &rect, const QgsRenderContext &context ) const
234{
235 //blur radius and spread size
238
239 //plus possible extension due to blur, with a couple of extra pixels thrown in for safety
240 spread += blurLevel * 2 + 10;
241 return rect.adjusted( -spread, -spread, spread, spread );
242}
243
244
245//
246// QgsOuterGlowEffect
247//
248
250 : QgsGlowEffect()
251{
252
253}
254
256{
258 effect->readProperties( map );
259 return effect;
260}
261
263{
264 QgsOuterGlowEffect *newEffect = new QgsOuterGlowEffect( *this );
265 return newEffect;
266}
267
268
269//
270// QgsInnerGlowEffect
271//
272
274 : QgsGlowEffect()
275{
276
277}
278
280{
282 effect->readProperties( map );
283 return effect;
284}
285
287{
288 QgsInnerGlowEffect *newEffect = new QgsInnerGlowEffect( *this );
289 return newEffect;
290}
Abstract base class for color ramps.
Definition: qgscolorramp.h:30
virtual QVariantMap properties() const =0
Returns a string map containing all the color ramp's properties.
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates the symbol layer.
static QString typeString()
Returns the string identifier for QgsCptCityColorRamp.
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Base class for paint effect which draw a glow inside or outside a picture.
Definition: qgsgloweffect.h:40
QgsUnitTypes::RenderUnit spreadUnit() const
Returns the units used for the glow spread distance.
Definition: qgsgloweffect.h:92
QgsGlowEffect & operator=(const QgsGlowEffect &rhs)
QgsMapUnitScale mBlurMapUnitScale
~QgsGlowEffect() override
void draw(QgsRenderContext &context) override
Handles drawing of the effect's result on to the specified render context.
double spread() const
Returns the spread distance used for drawing the glow effect.
Definition: qgsgloweffect.h:74
virtual bool shadeExterior() const =0
Specifies whether the glow is drawn outside the picture or within the picture.
const QgsMapUnitScale & spreadMapUnitScale() const
Returns the map unit scale used for the spread distance.
GlowColorType
Color sources for the glow.
Definition: qgsgloweffect.h:46
@ ColorRamp
Use colors from a color ramp.
Definition: qgsgloweffect.h:48
QPainter::CompositionMode blendMode() const
Returns the blend mode for the effect.
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...
QgsColorRamp * mRamp
QgsUnitTypes::RenderUnit mSpreadUnit
double blurLevel() const
Returns the blur level (radius) for the glow.
double opacity() const
Returns the opacity for the effect.
QgsUnitTypes::RenderUnit mBlurUnit
QColor color() const
Returns the color for the glow.
GlowColorType mColorType
QgsColorRamp * ramp() const
Returns the color ramp used for the glow.
QPainter::CompositionMode mBlendMode
QgsMapUnitScale mSpreadMapUnitScale
void setRamp(QgsColorRamp *ramp)
Sets the color ramp for the glow.
QVariantMap properties() const override
Returns the properties describing the paint effect encoded in a string format.
QRectF boundingRect(const QRectF &rect, const QgsRenderContext &context) const override
Returns the bounding rect required for drawing the effect.
GlowColorType colorType() const
Returns the color mode used for the glow.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsColorRamp from a map of properties.
static void multiplyOpacity(QImage &image, double factor, QgsFeedback *feedback=nullptr)
Multiplies opacity of image pixel values by a factor.
static void distanceTransform(QImage &image, const QgsImageOperation::DistanceTransformProperties &properties, QgsFeedback *feedback=nullptr)
Performs a distance transform on the source image and shades the result using a color ramp.
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.
A paint effect which draws a glow within a picture.
QgsInnerGlowEffect * clone() const override
Duplicates an effect by creating a deep copy of the effect.
static QgsPaintEffect * create(const QVariantMap &map)
Creates a new QgsInnerGlowEffect effect from a properties string map.
A paint effect which draws a glow outside of a picture.
QgsOuterGlowEffect * clone() const override
Duplicates an effect by creating a deep copy of the effect.
static QgsPaintEffect * create(const QVariantMap &map)
Creates a new QgsOuterGlowEffect effect from a properties string map.
Base class for visual effects which can be applied to QPicture drawings.
DrawMode mDrawMode
QPointF imageOffset(const QgsRenderContext &context) const
Returns the offset which should be used when drawing the source image on to a destination render cont...
const QPicture * source() const
Returns the source QPicture.
bool enabled() const
Returns whether the effect is enabled.
DrawMode
Drawing modes for effects.
virtual QString type() const =0
Returns the effect type.
QImage * sourceAsImage(QgsRenderContext &context)
Returns the source QPicture rendered to a new QImage.
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly during rendering to check if rendering shou...
Scoped object for saving and restoring a QPainter object's state.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static QColor decodeColor(const QString &str)
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static QString encodeColor(const QColor &color)
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
Struct for storing properties of a distance transform operation.
bool useMaxDistance
Set to true to automatically calculate the maximum distance in the transform to use as the spread val...
bool shadeExterior
Set to true to perform the distance transform on transparent pixels in the source image,...
double spread
Maximum distance (in pixels) for the distance transform shading to spread.
QgsColorRamp * ramp
Color ramp to use for shading the distance transform.