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