QGIS API Documentation  3.12.1-București (121cc00ff0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  {
73  QgsImageOperation::stackBlur( im, blurLevel );
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  painter->save();
96  painter->setCompositionMode( mBlendMode );
97  painter->drawImage( imageOffset( context ), im );
98  painter->restore();
99 }
100 
102 {
103  QgsStringMap props;
104  props.insert( QStringLiteral( "enabled" ), mEnabled ? "1" : "0" );
105  props.insert( QStringLiteral( "draw_mode" ), QString::number( int( mDrawMode ) ) );
106  props.insert( QStringLiteral( "blend_mode" ), QString::number( int( mBlendMode ) ) );
107  props.insert( QStringLiteral( "opacity" ), QString::number( mOpacity ) );
108  props.insert( QStringLiteral( "blur_level" ), QString::number( mBlurLevel ) );
109  props.insert( QStringLiteral( "blur_unit" ), QgsUnitTypes::encodeUnit( mBlurUnit ) );
110  props.insert( QStringLiteral( "blur_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mBlurMapUnitScale ) );
111  props.insert( QStringLiteral( "spread" ), QString::number( mSpread ) );
112  props.insert( QStringLiteral( "spread_unit" ), QgsUnitTypes::encodeUnit( mSpreadUnit ) );
113  props.insert( QStringLiteral( "spread_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mSpreadMapUnitScale ) );
114  props.insert( QStringLiteral( "color_type" ), QString::number( static_cast< int >( mColorType ) ) );
115  props.insert( QStringLiteral( "single_color" ), QgsSymbolLayerUtils::encodeColor( mColor ) );
116 
117  if ( mRamp )
118  {
119  props.unite( mRamp->properties() );
120  }
121 
122  return props;
123 }
124 
126 {
127  bool ok;
128  QPainter::CompositionMode mode = static_cast< QPainter::CompositionMode >( props.value( QStringLiteral( "blend_mode" ) ).toInt( &ok ) );
129  if ( ok )
130  {
131  mBlendMode = mode;
132  }
133  if ( props.contains( QStringLiteral( "transparency" ) ) )
134  {
135  double transparency = props.value( QStringLiteral( "transparency" ) ).toDouble( &ok );
136  if ( ok )
137  {
138  mOpacity = 1.0 - transparency;
139  }
140  }
141  else
142  {
143  double opacity = props.value( QStringLiteral( "opacity" ) ).toDouble( &ok );
144  if ( ok )
145  {
146  mOpacity = opacity;
147  }
148  }
149  mEnabled = props.value( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ).toInt();
150  mDrawMode = static_cast< QgsPaintEffect::DrawMode >( props.value( QStringLiteral( "draw_mode" ), QStringLiteral( "2" ) ).toInt() );
151  double level = props.value( QStringLiteral( "blur_level" ) ).toDouble( &ok );
152  if ( ok )
153  {
154  mBlurLevel = level;
155  if ( !props.contains( QStringLiteral( "blur_unit" ) ) )
156  {
157  // deal with pre blur unit era by assuming 96 dpi and converting pixel values as millimeters
158  mBlurLevel *= 0.2645;
159  }
160  }
161  mBlurUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "blur_unit" ) ) );
162  mBlurMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "blur_unit_scale" ) ) );
163  double spread = props.value( QStringLiteral( "spread" ) ).toDouble( &ok );
164  if ( ok )
165  {
166  mSpread = spread;
167  }
168  mSpreadUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "spread_unit" ) ) );
169  mSpreadMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "spread_unit_scale" ) ) );
170  QgsGlowEffect::GlowColorType type = static_cast< QgsGlowEffect::GlowColorType >( props.value( QStringLiteral( "color_type" ) ).toInt( &ok ) );
171  if ( ok )
172  {
173  mColorType = type;
174  }
175  if ( props.contains( QStringLiteral( "single_color" ) ) )
176  {
177  mColor = QgsSymbolLayerUtils::decodeColor( props.value( QStringLiteral( "single_color" ) ) );
178  }
179 
180 //attempt to create color ramp from props
181  delete mRamp;
182  if ( props.contains( QStringLiteral( "rampType" ) ) && props[QStringLiteral( "rampType" )] == QStringLiteral( "cpt-city" ) )
183  {
184  mRamp = QgsCptCityColorRamp::create( props );
185  }
186  else
187  {
188  mRamp = QgsGradientColorRamp::create( props );
189  }
190 }
191 
193 {
194  delete mRamp;
195  mRamp = ramp;
196 }
197 
199 {
200  if ( &rhs == this )
201  return *this;
202 
203  delete mRamp;
204 
205  mSpread = rhs.spread();
206  mSpreadUnit = rhs.spreadUnit();
208  mRamp = rhs.ramp() ? rhs.ramp()->clone() : nullptr;
209  mBlurLevel = rhs.blurLevel();
210  mBlurUnit = rhs.mBlurUnit;
212  mOpacity = rhs.opacity();
213  mColor = rhs.color();
214  mBlendMode = rhs.blendMode();
215  mColorType = rhs.colorType();
216 
217  return *this;
218 }
219 
220 QRectF QgsGlowEffect::boundingRect( const QRectF &rect, const QgsRenderContext &context ) const
221 {
222  //blur radius and spread size
223  int blurLevel = std::round( context.convertToPainterUnits( mBlurLevel, mBlurUnit, mBlurMapUnitScale ) );
225  //plus possible extension due to blur, with a couple of extra pixels thrown in for safety
226  spread += blurLevel * 2 + 10;
227  return rect.adjusted( -spread, -spread, spread, spread );
228 }
229 
230 
231 //
232 // QgsOuterGlowEffect
233 //
234 
236  : QgsGlowEffect()
237 {
238 
239 }
240 
242 {
243  QgsOuterGlowEffect *effect = new QgsOuterGlowEffect();
244  effect->readProperties( map );
245  return effect;
246 }
247 
249 {
250  QgsOuterGlowEffect *newEffect = new QgsOuterGlowEffect( *this );
251  return newEffect;
252 }
253 
254 
255 //
256 // QgsInnerGlowEffect
257 //
258 
260  : QgsGlowEffect()
261 {
262 
263 }
264 
266 {
267  QgsInnerGlowEffect *effect = new QgsInnerGlowEffect();
268  effect->readProperties( map );
269  return effect;
270 }
271 
273 {
274  QgsInnerGlowEffect *newEffect = new QgsInnerGlowEffect( *this );
275  return newEffect;
276 }
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:694
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.