QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 "qgscolorramp.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;
69 
70  int blurLevel = std::round( context.convertToPainterUnits( mBlurLevel, mBlurUnit, mBlurMapUnitScale ) );
71  if ( blurLevel <= 16 )
72  {
74  }
75  else
76  {
77  QImage *imb = QgsImageOperation::gaussianBlur( im, blurLevel );
78  im = QImage( *imb );
79  delete imb;
80  }
81 
83 
84  if ( !shadeExterior() )
85  {
86  //only keep interior portion
87  QPainter p( &im );
88  p.setRenderHint( QPainter::Antialiasing );
89  p.setCompositionMode( QPainter::CompositionMode_DestinationIn );
90  p.drawImage( 0, 0, *sourceAsImage( context ) );
91  p.end();
92  }
93 
94  QPainter *painter = context.painter();
95  QgsScopedQPainterState painterState( painter );
96  painter->setCompositionMode( mBlendMode );
97  painter->drawImage( imageOffset( context ), im );
98 }
99 
100 QVariantMap QgsGlowEffect::properties() const
101 {
102  QVariantMap props;
103  props.insert( QStringLiteral( "enabled" ), mEnabled ? "1" : "0" );
104  props.insert( QStringLiteral( "draw_mode" ), QString::number( int( mDrawMode ) ) );
105  props.insert( QStringLiteral( "blend_mode" ), QString::number( int( mBlendMode ) ) );
106  props.insert( QStringLiteral( "opacity" ), QString::number( mOpacity ) );
107  props.insert( QStringLiteral( "blur_level" ), QString::number( mBlurLevel ) );
108  props.insert( QStringLiteral( "blur_unit" ), QgsUnitTypes::encodeUnit( mBlurUnit ) );
109  props.insert( QStringLiteral( "blur_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mBlurMapUnitScale ) );
110  props.insert( QStringLiteral( "spread" ), QString::number( mSpread ) );
111  props.insert( QStringLiteral( "spread_unit" ), QgsUnitTypes::encodeUnit( mSpreadUnit ) );
112  props.insert( QStringLiteral( "spread_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mSpreadMapUnitScale ) );
113  props.insert( QStringLiteral( "color_type" ), QString::number( static_cast< int >( mColorType ) ) );
114  props.insert( QStringLiteral( "single_color" ), QgsSymbolLayerUtils::encodeColor( mColor ) );
115 
116  if ( mRamp )
117  {
118 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
119  props.unite( mRamp->properties() );
120 #else
121  props.insert( mRamp->properties() );
122 #endif
123  }
124 
125  return props;
126 }
127 
128 void QgsGlowEffect::readProperties( const QVariantMap &props )
129 {
130  bool ok;
131  QPainter::CompositionMode mode = static_cast< QPainter::CompositionMode >( props.value( QStringLiteral( "blend_mode" ) ).toInt( &ok ) );
132  if ( ok )
133  {
134  mBlendMode = mode;
135  }
136  if ( props.contains( QStringLiteral( "transparency" ) ) )
137  {
138  double transparency = props.value( QStringLiteral( "transparency" ) ).toDouble( &ok );
139  if ( ok )
140  {
141  mOpacity = 1.0 - transparency;
142  }
143  }
144  else
145  {
146  double opacity = props.value( QStringLiteral( "opacity" ) ).toDouble( &ok );
147  if ( ok )
148  {
149  mOpacity = opacity;
150  }
151  }
152  mEnabled = props.value( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ).toInt();
153  mDrawMode = static_cast< QgsPaintEffect::DrawMode >( props.value( QStringLiteral( "draw_mode" ), QStringLiteral( "2" ) ).toInt() );
154  double level = props.value( QStringLiteral( "blur_level" ) ).toDouble( &ok );
155  if ( ok )
156  {
157  mBlurLevel = level;
158  if ( !props.contains( QStringLiteral( "blur_unit" ) ) )
159  {
160  // deal with pre blur unit era by assuming 96 dpi and converting pixel values as millimeters
161  mBlurLevel *= 0.2645;
162  }
163  }
164  mBlurUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "blur_unit" ) ).toString() );
165  mBlurMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "blur_unit_scale" ) ).toString() );
166  double spread = props.value( QStringLiteral( "spread" ) ).toDouble( &ok );
167  if ( ok )
168  {
169  mSpread = spread;
170  }
171  mSpreadUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "spread_unit" ) ).toString() );
172  mSpreadMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "spread_unit_scale" ) ).toString() );
173  QgsGlowEffect::GlowColorType type = static_cast< QgsGlowEffect::GlowColorType >( props.value( QStringLiteral( "color_type" ) ).toInt( &ok ) );
174  if ( ok )
175  {
176  mColorType = type;
177  }
178  if ( props.contains( QStringLiteral( "single_color" ) ) )
179  {
180  mColor = QgsSymbolLayerUtils::decodeColor( props.value( QStringLiteral( "single_color" ) ).toString() );
181  }
182 
183  //attempt to create color ramp from props
184  delete mRamp;
185  if ( props.contains( QStringLiteral( "rampType" ) ) && props[QStringLiteral( "rampType" )] == QgsCptCityColorRamp::typeString() )
186  {
188  }
189  else
190  {
192  }
193 }
194 
196 {
197  delete mRamp;
198  mRamp = ramp;
199 }
200 
202 {
203  if ( &rhs == this )
204  return *this;
205 
206  delete mRamp;
207 
208  mSpread = rhs.spread();
209  mSpreadUnit = rhs.spreadUnit();
211  mRamp = rhs.ramp() ? rhs.ramp()->clone() : nullptr;
212  mBlurLevel = rhs.blurLevel();
213  mBlurUnit = rhs.mBlurUnit;
215  mOpacity = rhs.opacity();
216  mColor = rhs.color();
217  mBlendMode = rhs.blendMode();
218  mColorType = rhs.colorType();
219 
220  return *this;
221 }
222 
223 QRectF QgsGlowEffect::boundingRect( const QRectF &rect, const QgsRenderContext &context ) const
224 {
225  //blur radius and spread size
226  int blurLevel = std::round( context.convertToPainterUnits( mBlurLevel, mBlurUnit, mBlurMapUnitScale ) );
228  //plus possible extension due to blur, with a couple of extra pixels thrown in for safety
229  spread += blurLevel * 2 + 10;
230  return rect.adjusted( -spread, -spread, spread, spread );
231 }
232 
233 
234 //
235 // QgsOuterGlowEffect
236 //
237 
239  : QgsGlowEffect()
240 {
241 
242 }
243 
244 QgsPaintEffect *QgsOuterGlowEffect::create( const QVariantMap &map )
245 {
246  QgsOuterGlowEffect *effect = new QgsOuterGlowEffect();
247  effect->readProperties( map );
248  return effect;
249 }
250 
252 {
253  QgsOuterGlowEffect *newEffect = new QgsOuterGlowEffect( *this );
254  return newEffect;
255 }
256 
257 
258 //
259 // QgsInnerGlowEffect
260 //
261 
263  : QgsGlowEffect()
264 {
265 
266 }
267 
268 QgsPaintEffect *QgsInnerGlowEffect::create( const QVariantMap &map )
269 {
270  QgsInnerGlowEffect *effect = new QgsInnerGlowEffect();
271  effect->readProperties( map );
272  return effect;
273 }
274 
276 {
277  QgsInnerGlowEffect *newEffect = new QgsInnerGlowEffect( *this );
278  return newEffect;
279 }
Abstract base class for color ramps.
Definition: qgscolorramp.h:32
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.
Definition: qgscolorramp.h:712
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.
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.
QgsColorRamp * ramp() const
Returns the color ramp used for the glow.
GlowColorType mColorType
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.
const QgsMapUnitScale & spreadMapUnitScale() const
Returns the map unit scale used for the spread distance.
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 ...
Definition: qgscolorramp.h:151
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsColorRamp from a map of properties.
static void multiplyOpacity(QImage &image, double factor)
Multiplies opacity of image pixel values by a factor.
static void stackBlur(QImage &image, int radius, bool alphaOnly=false)
Performs a stack blur on an image.
static void distanceTransform(QImage &image, const QgsImageOperation::DistanceTransformProperties &properties)
Performs a distance transform on the source image and shades the result using a color ramp.
static QImage * gaussianBlur(QImage &image, int radius)
Performs a gaussian 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
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.
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()) const
Converts a size from the specified units to painter units (pixels).
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.