QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsshadoweffect.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsshadoweffect.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 "qgsshadoweffect.h"
19 #include "qgsimageoperation.h"
20 #include "qgssymbollayerutils.h"
21 #include "qgsunittypes.h"
22 
24  : mColor( Qt::black )
25 {
26 
27 }
28 
30 {
31  if ( !source() || !enabled() || !context.painter() )
32  return;
33 
34  QImage colorisedIm = sourceAsImage( context )->copy();
35 
36  QPainter *painter = context.painter();
37  painter->save();
38  painter->setCompositionMode( mBlendMode );
39 
40  if ( !exteriorShadow() )
41  {
42  //inner shadow, first invert the opacity. The color does not matter since we will
43  //be replacing it anyway
44  colorisedIm.invertPixels( QImage::InvertRgba );
45  }
46 
48 
49  int blurLevel = std::round( context.convertToPainterUnits( mBlurLevel, mBlurUnit, mBlurMapUnitScale ) );
50  if ( blurLevel <= 16 )
51  {
53  }
54  else
55  {
56  QImage *imb = QgsImageOperation::gaussianBlur( colorisedIm, blurLevel );
57  colorisedIm = QImage( *imb );
58  delete imb;
59  }
60 
61  double offsetDist = context.convertToPainterUnits( mOffsetDist, mOffsetUnit, mOffsetMapUnitScale );
62 
63  double angleRad = mOffsetAngle * M_PI / 180; // to radians
64  QPointF transPt( -offsetDist * std::cos( angleRad + M_PI_2 ),
65  -offsetDist * std::sin( angleRad + M_PI_2 ) );
66 
67  //transparency, scale
69 
70  if ( !exteriorShadow() )
71  {
72  //inner shadow, do a bit of painter juggling
73  QImage innerShadowIm( colorisedIm.width(), colorisedIm.height(), QImage::Format_ARGB32 );
74  innerShadowIm.fill( Qt::transparent );
75  QPainter imPainter( &innerShadowIm );
76 
77  //draw shadow at offset
78  imPainter.drawImage( transPt.x(), transPt.y(), colorisedIm );
79 
80  //restrict shadow so it's only drawn on top of original image
81  imPainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
82  imPainter.drawImage( 0, 0, *sourceAsImage( context ) );
83  imPainter.end();
84 
85  painter->drawImage( imageOffset( context ), innerShadowIm );
86  }
87  else
88  {
89  painter->drawImage( imageOffset( context ) + transPt, colorisedIm );
90  }
91  painter->restore();
92 }
93 
95 {
96  QgsStringMap props;
97  props.insert( QStringLiteral( "enabled" ), mEnabled ? "1" : "0" );
98  props.insert( QStringLiteral( "draw_mode" ), QString::number( int( mDrawMode ) ) );
99  props.insert( QStringLiteral( "blend_mode" ), QString::number( int( mBlendMode ) ) );
100  props.insert( QStringLiteral( "opacity" ), QString::number( mOpacity ) );
101  props.insert( QStringLiteral( "blur_level" ), QString::number( mBlurLevel ) );
102  props.insert( QStringLiteral( "blur_unit" ), QgsUnitTypes::encodeUnit( mBlurUnit ) );
103  props.insert( QStringLiteral( "blur_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mBlurMapUnitScale ) );
104  props.insert( QStringLiteral( "offset_angle" ), QString::number( mOffsetAngle ) );
105  props.insert( QStringLiteral( "offset_distance" ), QString::number( mOffsetDist ) );
106  props.insert( QStringLiteral( "offset_unit" ), QgsUnitTypes::encodeUnit( mOffsetUnit ) );
107  props.insert( QStringLiteral( "offset_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale ) );
108  props.insert( QStringLiteral( "color" ), QgsSymbolLayerUtils::encodeColor( mColor ) );
109  return props;
110 }
111 
113 {
114  bool ok;
115  QPainter::CompositionMode mode = static_cast< QPainter::CompositionMode >( props.value( QStringLiteral( "blend_mode" ) ).toInt( &ok ) );
116  if ( ok )
117  {
118  mBlendMode = mode;
119  }
120  if ( props.contains( QStringLiteral( "transparency" ) ) )
121  {
122  double transparency = props.value( QStringLiteral( "transparency" ) ).toDouble( &ok );
123  if ( ok )
124  {
125  mOpacity = 1.0 - transparency;
126  }
127  }
128  else
129  {
130  double opacity = props.value( QStringLiteral( "opacity" ) ).toDouble( &ok );
131  if ( ok )
132  {
133  mOpacity = opacity;
134  }
135  }
136  mEnabled = props.value( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ).toInt();
137  mDrawMode = static_cast< QgsPaintEffect::DrawMode >( props.value( QStringLiteral( "draw_mode" ), QStringLiteral( "2" ) ).toInt() );
138  double level = props.value( QStringLiteral( "blur_level" ) ).toDouble( &ok );
139  if ( ok )
140  {
141  mBlurLevel = level;
142  if ( !props.contains( QStringLiteral( "blur_unit" ) ) )
143  {
144  // deal with pre blur unit era by assuming 96 dpi and converting pixel values as millimeters
145  mBlurLevel *= 0.2645;
146  }
147  }
148  mBlurUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "blur_unit" ) ) );
149  mBlurMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "blur_unit_scale" ) ) );
150  int angle = props.value( QStringLiteral( "offset_angle" ) ).toInt( &ok );
151  if ( ok )
152  {
154  }
155  double distance = props.value( QStringLiteral( "offset_distance" ) ).toDouble( &ok );
156  if ( ok )
157  {
158  mOffsetDist = distance;
159  }
160  mOffsetUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "offset_unit" ) ) );
161  mOffsetMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "offset_unit_scale" ) ) );
162  if ( props.contains( QStringLiteral( "color" ) ) )
163  {
164  mColor = QgsSymbolLayerUtils::decodeColor( props.value( QStringLiteral( "color" ) ) );
165  }
166 }
167 
168 QRectF QgsShadowEffect::boundingRect( const QRectF &rect, const QgsRenderContext &context ) const
169 {
170  //blur radius and offset distance
171  int blurLevel = std::round( context.convertToPainterUnits( mBlurLevel, mBlurUnit, mBlurMapUnitScale ) );
173  //plus possible extension due to blur, with a couple of extra pixels thrown in for safety
174  spread += blurLevel * 2 + 10;
175  return rect.adjusted( -spread, -spread, spread, spread );
176 }
177 
178 
179 //
180 // QgsDropShadowEffect
181 //
182 
184 {
186  effect->readProperties( map );
187  return effect;
188 }
189 
191  : QgsShadowEffect()
192 {
193 
194 }
195 
197 {
198  return QStringLiteral( "dropShadow" );
199 }
200 
202 {
203  return new QgsDropShadowEffect( *this );
204 }
205 
207 {
208  return true;
209 }
210 
211 
212 //
213 // QgsInnerShadowEffect
214 //
215 
217 {
219  effect->readProperties( map );
220  return effect;
221 }
222 
224  : QgsShadowEffect()
225 {
226 
227 }
228 
230 {
231  return QStringLiteral( "innerShadow" );
232 }
233 
235 {
236  return new QgsInnerShadowEffect( *this );
237 }
238 
240 {
241  return false;
242 }
QgsShadowEffect::mOpacity
double mOpacity
Definition: qgsshadoweffect.h:240
QgsDropShadowEffect::QgsDropShadowEffect
QgsDropShadowEffect()
Definition: qgsshadoweffect.cpp:190
QgsPaintEffect::DrawMode
DrawMode
Drawing modes for effects.
Definition: qgspainteffect.h:104
QgsDropShadowEffect::exteriorShadow
bool exteriorShadow() const override
Specifies whether the shadow is drawn outside the picture or within the picture.
Definition: qgsshadoweffect.cpp:206
QgsSymbolLayerUtils::encodeColor
static QString encodeColor(const QColor &color)
Definition: qgssymbollayerutils.cpp:52
QgsRenderContext::convertToPainterUnits
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
Definition: qgsrendercontext.cpp:287
QgsSymbolLayerUtils::encodeMapUnitScale
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
Definition: qgssymbollayerutils.cpp:558
QgsInnerShadowEffect
A paint effect which draws an offset and optionally blurred drop shadow within a picture.
Definition: qgsshadoweffect.h:285
QgsShadowEffect::mOffsetUnit
QgsUnitTypes::RenderUnit mOffsetUnit
Definition: qgsshadoweffect.h:238
QgsShadowEffect::mColor
QColor mColor
Definition: qgsshadoweffect.h:241
QgsDropShadowEffect::type
QString type() const override
Returns the effect type.
Definition: qgsshadoweffect.cpp:196
QgsShadowEffect::properties
QgsStringMap properties() const override
Returns the properties describing the paint effect encoded in a string format.
Definition: qgsshadoweffect.cpp:94
qgssymbollayerutils.h
QgsImageOperation::multiplyOpacity
static void multiplyOpacity(QImage &image, double factor)
Multiplies opacity of image pixel values by a factor.
Definition: qgsimageoperation.cpp:322
QgsShadowEffect::mBlurUnit
QgsUnitTypes::RenderUnit mBlurUnit
Definition: qgsshadoweffect.h:234
QgsRenderContext
Definition: qgsrendercontext.h:57
QgsShadowEffect::mBlurLevel
double mBlurLevel
Definition: qgsshadoweffect.h:233
qgsunittypes.h
qgsimageoperation.h
QgsShadowEffect::readProperties
void readProperties(const QgsStringMap &props) override
Reads a string map of an effect's properties and restores the effect to the state described by the pr...
Definition: qgsshadoweffect.cpp:112
QgsInnerShadowEffect::create
static QgsPaintEffect * create(const QgsStringMap &map)
Creates a new QgsInnerShadowEffect effect from a properties string map.
Definition: qgsshadoweffect.cpp:216
QgsSymbolLayerUtils::decodeColor
static QColor decodeColor(const QString &str)
Definition: qgssymbollayerutils.cpp:57
QgsShadowEffect::mBlendMode
QPainter::CompositionMode mBlendMode
Definition: qgsshadoweffect.h:242
QgsPaintEffect::mEnabled
bool mEnabled
Definition: qgspainteffect.h:225
QgsShadowEffect::QgsShadowEffect
QgsShadowEffect()
Definition: qgsshadoweffect.cpp:23
QgsShadowEffect::opacity
double opacity() const
Returns the opacity for the effect.
Definition: qgsshadoweffect.h:202
QgsUnitTypes::decodeRenderUnit
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
Definition: qgsunittypes.cpp:2900
QgsUnitTypes::encodeUnit
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
Definition: qgsunittypes.cpp:122
QgsDropShadowEffect::clone
QgsDropShadowEffect * clone() const override
Duplicates an effect by creating a deep copy of the effect.
Definition: qgsshadoweffect.cpp:201
QgsShadowEffect::mOffsetMapUnitScale
QgsMapUnitScale mOffsetMapUnitScale
Definition: qgsshadoweffect.h:239
QgsDropShadowEffect
A paint effect which draws an offset and optionally blurred drop shadow.
Definition: qgsshadoweffect.h:254
QgsShadowEffect::exteriorShadow
virtual bool exteriorShadow() const =0
Specifies whether the shadow is drawn outside the picture or within the picture.
QgsShadowEffect::blurLevel
double blurLevel() const
Returns the blur level (radius) for the shadow.
Definition: qgsshadoweffect.h:62
QgsPaintEffect::imageOffset
QPointF imageOffset(const QgsRenderContext &context) const
Returns the offset which should be used when drawing the source image on to a destination render cont...
Definition: qgspainteffect.cpp:198
QgsInnerShadowEffect::QgsInnerShadowEffect
QgsInnerShadowEffect()
Definition: qgsshadoweffect.cpp:223
QgsInnerShadowEffect::type
QString type() const override
Returns the effect type.
Definition: qgsshadoweffect.cpp:229
QgsPaintEffect::mDrawMode
DrawMode mDrawMode
Definition: qgspainteffect.h:226
QgsStringMap
QMap< QString, QString > QgsStringMap
Definition: qgis.h:714
QgsImageOperation::gaussianBlur
static QImage * gaussianBlur(QImage &image, int radius)
Performs a gaussian blur on an image.
Definition: qgsimageoperation.cpp:603
qgsshadoweffect.h
QgsPaintEffect::sourceAsImage
QImage * sourceAsImage(QgsRenderContext &context)
Returns the source QPicture rendered to a new QImage.
Definition: qgspainteffect.cpp:173
QgsShadowEffect::boundingRect
QRectF boundingRect(const QRectF &rect, const QgsRenderContext &context) const override
Returns the bounding rect required for drawing the effect.
Definition: qgsshadoweffect.cpp:168
QgsPaintEffect::source
const QPicture * source() const
Returns the source QPicture.
Definition: qgspainteffect.h:254
QgsShadowEffect::mOffsetDist
double mOffsetDist
Definition: qgsshadoweffect.h:237
QgsPaintEffect
Base class for visual effects which can be applied to QPicture drawings.
Definition: qgspainteffect.h:53
QgsImageOperation::stackBlur
static void stackBlur(QImage &image, int radius, bool alphaOnly=false)
Performs a stack blur on an image.
Definition: qgsimageoperation.cpp:558
QgsShadowEffect::mBlurMapUnitScale
QgsMapUnitScale mBlurMapUnitScale
Definition: qgsshadoweffect.h:235
QgsInnerShadowEffect::exteriorShadow
bool exteriorShadow() const override
Specifies whether the shadow is drawn outside the picture or within the picture.
Definition: qgsshadoweffect.cpp:239
QgsDropShadowEffect::create
static QgsPaintEffect * create(const QgsStringMap &map)
Creates a new QgsDropShadowEffect effect from a properties string map.
Definition: qgsshadoweffect.cpp:183
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:174
QgsPaintEffect::enabled
bool enabled() const
Returns whether the effect is enabled.
Definition: qgspainteffect.h:198
QgsShadowEffect::draw
void draw(QgsRenderContext &context) override
Handles drawing of the effect's result on to the specified render context.
Definition: qgsshadoweffect.cpp:29
QgsImageOperation::overlayColor
static void overlayColor(QImage &image, const QColor &color)
Overlays a color onto an image.
Definition: qgsimageoperation.cpp:356
MathUtils::angle
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
QgsInnerShadowEffect::clone
QgsInnerShadowEffect * clone() const override
Duplicates an effect by creating a deep copy of the effect.
Definition: qgsshadoweffect.cpp:234
QgsShadowEffect::mOffsetAngle
int mOffsetAngle
Definition: qgsshadoweffect.h:236
QgsSymbolLayerUtils::decodeMapUnitScale
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Definition: qgssymbollayerutils.cpp:568
QgsShadowEffect
Base class for paint effects which offset, blurred shadows.
Definition: qgsshadoweffect.h:34