QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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::floor( 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.
DrawMode mDrawMode
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
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.
bool enabled() const
Returns whether the effect is enabled.
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:577
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)
~QgsGlowEffect() override
double spread() const
Returns the spread distance used for drawing the glow effect.
Definition: qgsgloweffect.h:73
QgsColorRamp * ramp
Color ramp to use for shading the distance transform.
GlowColorType mColorType
virtual QString type() const =0
Returns the effect type.
static QgsPaintEffect * create(const QgsStringMap &map)
Creates a new QgsOuterGlowEffect effect from a properties string map.
double blurLevel() const
Returns the blur level (radius) for the glow.
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...
QgsUnitTypes::RenderUnit spreadUnit() const
Returns the units used for the glow spread distance.
Definition: qgsgloweffect.h:91
GlowColorType
Color sources for the glow.
Definition: qgsgloweffect.h:44
QPointF imageOffset(const QgsRenderContext &context) const
Returns the offset which should be used when drawing the source image on to a destination render cont...
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
const QgsMapUnitScale & spreadMapUnitScale() const
Returns the map unit scale used for the spread distance.
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.
QPainter * painter()
Returns the destination QPainter for the render operation.
Use colors from a color ramp.
Definition: qgsgloweffect.h:47
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.
QColor color() const
Returns the color for the glow.
GlowColorType colorType() const
Returns the color mode used for the glow.
double opacity() const
Returns the opacity for the effect.
QgsMapUnitScale mBlurMapUnitScale
QgsColorRamp * ramp() const
Returns the color ramp used for the glow.
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.
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)
QPainter::CompositionMode blendMode() const
Returns the blend mode for the effect.
Struct for storing properties of a distance transform operation.
QgsUnitTypes::RenderUnit mSpreadUnit