QGIS API Documentation  2.14.0-Essen
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 "qgssymbollayerv2utils.h"
21 #include "qgsunittypes.h"
22 
24  : QgsPaintEffect()
25  , mBlurLevel( 10 )
26  , mOffsetAngle( 135 )
27  , mOffsetDist( 2.0 )
28  , mOffsetUnit( QgsSymbolV2::MM )
29  , mTransparency( 0.0 )
30  , mColor( Qt::black )
31  , mBlendMode( QPainter::CompositionMode_Multiply )
32 {
33 
34 }
35 
37 {
38 
39 }
40 
42 {
43  if ( !source() || !enabled() || !context.painter() )
44  return;
45 
46  QImage colorisedIm = sourceAsImage( context )->copy();
47 
48  QPainter* painter = context.painter();
49  painter->save();
50  painter->setCompositionMode( mBlendMode );
51 
52  if ( !exteriorShadow() )
53  {
54  //inner shadow, first invert the opacity. The color does not matter since we will
55  //be replacing it anyway
56  colorisedIm.invertPixels( QImage::InvertRgba );
57  }
58 
61 
62  double offsetDist = mOffsetDist *
64 
65  double angleRad = mOffsetAngle * M_PI / 180; // to radians
66  QPointF transPt( -offsetDist * cos( angleRad + M_PI / 2 ),
67  -offsetDist * sin( angleRad + M_PI / 2 ) );
68 
69  //transparency, scale
71 
72  if ( !exteriorShadow() )
73  {
74  //inner shadow, do a bit of painter juggling
75  QImage innerShadowIm( colorisedIm.width(), colorisedIm.height(), QImage::Format_ARGB32 );
76  innerShadowIm.fill( Qt::transparent );
77  QPainter imPainter( &innerShadowIm );
78 
79  //draw shadow at offset
80  imPainter.drawImage( transPt.x(), transPt.y(), colorisedIm );
81 
82  //restrict shadow so it's only drawn on top of original image
83  imPainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
84  imPainter.drawImage( 0, 0, *sourceAsImage( context ) );
85  imPainter.end();
86 
87  painter->drawImage( imageOffset( context ), innerShadowIm );
88  }
89  else
90  {
91  painter->drawImage( imageOffset( context ) + transPt, colorisedIm );
92  }
93  painter->restore();
94 }
95 
97 {
98  QgsStringMap props;
99  props.insert( "enabled", mEnabled ? "1" : "0" );
100  props.insert( "draw_mode", QString::number( int( mDrawMode ) ) );
101  props.insert( "blend_mode", QString::number( int( mBlendMode ) ) );
102  props.insert( "transparency", QString::number( mTransparency ) );
103  props.insert( "blur_level", QString::number( mBlurLevel ) );
104  props.insert( "offset_angle", QString::number( mOffsetAngle ) );
105  props.insert( "offset_distance", QString::number( mOffsetDist ) );
108  props.insert( "color", QgsSymbolLayerV2Utils::encodeColor( mColor ) );
109  return props;
110 }
111 
113 {
114  bool ok;
115  QPainter::CompositionMode mode = static_cast< QPainter::CompositionMode >( props.value( "blend_mode" ).toInt( &ok ) );
116  if ( ok )
117  {
118  mBlendMode = mode;
119  }
120  double transparency = props.value( "transparency" ).toDouble( &ok );
121  if ( ok )
122  {
124  }
125  mEnabled = props.value( "enabled", "1" ).toInt();
126  mDrawMode = static_cast< QgsPaintEffect::DrawMode >( props.value( "draw_mode", "2" ).toInt() );
127  int level = props.value( "blur_level" ).toInt( &ok );
128  if ( ok )
129  {
130  mBlurLevel = level;
131  }
132  int angle = props.value( "offset_angle" ).toInt( &ok );
133  if ( ok )
134  {
136  }
137  double distance = props.value( "offset_distance" ).toDouble( &ok );
138  if ( ok )
139  {
140  mOffsetDist = distance;
141  }
142  mOffsetUnit = QgsSymbolLayerV2Utils::decodeOutputUnit( props.value( "offset_unit" ) );
143  mOffsetMapUnitScale = QgsSymbolLayerV2Utils::decodeMapUnitScale( props.value( "offset_unit_scale" ) );
144  if ( props.contains( "color" ) )
145  {
146  mColor = QgsSymbolLayerV2Utils::decodeColor( props.value( "color" ) );
147  }
148 }
149 
150 QRectF QgsShadowEffect::boundingRect( const QRectF &rect, const QgsRenderContext& context ) const
151 {
152  //offset distance
154  //plus possible extension due to blur, with a couple of extra pixels thrown in for safety
155  spread += mBlurLevel * 2 + 10;
156  return rect.adjusted( -spread, -spread, spread, spread );
157 }
158 
159 
160 //
161 // QgsDropShadowEffect
162 //
163 
165 {
167  effect->readProperties( map );
168  return effect;
169 }
170 
172  : QgsShadowEffect()
173 {
174 
175 }
176 
178 {
179 
180 }
181 
183 {
184  return new QgsDropShadowEffect( *this );
185 }
186 
187 
188 //
189 // QgsInnerShadowEffect
190 //
191 
193 {
195  effect->readProperties( map );
196  return effect;
197 }
198 
200  : QgsShadowEffect()
201 {
202 
203 }
204 
206 {
207 
208 }
209 
211 {
212  return new QgsInnerShadowEffect( *this );
213 }
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
static void overlayColor(QImage &image, const QColor &color)
Overlays a color onto an image.
bool end()
bool contains(const Key &key) const
void setCompositionMode(CompositionMode mode)
DrawMode mDrawMode
static void multiplyOpacity(QImage &image, const double factor)
Multiplies opacity of image pixel values by a factor.
static QString encodeColor(const QColor &color)
bool enabled() const
Returns whether the effect is enabled.
Base class for visual effects which can be applied to QPicture drawings.
void save()
virtual QgsStringMap properties() const override
Returns the properties describing the paint effect encoded in a string format.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
QImage copy(const QRect &rectangle) const
virtual QgsDropShadowEffect * clone() const override
Duplicates an effect by creating a deep copy of the effect.
virtual bool exteriorShadow() const =0
Specifies whether the shadow is drawn outside the picture or within the picture.
static double pixelSizeScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns scale factor painter units -> pixel dimensions.
QImage * sourceAsImage(QgsRenderContext &context)
Returns the source QPicture rendered to a new QImage.
static QgsSymbolV2::OutputUnit decodeOutputUnit(const QString &str)
QgsMapUnitScale mOffsetMapUnitScale
QString number(int n, int base)
qreal x() const
qreal y() const
void fill(uint pixelValue)
int width() const
virtual QRectF boundingRect(const QRectF &rect, const QgsRenderContext &context) const override
Returns the bounding rect required for drawing the effect.
double transparency() const
Returns the transparency for the effect.
#define M_PI
QPainter::CompositionMode mBlendMode
QPointF imageOffset(const QgsRenderContext &context) const
Returns the offset which should be used when drawing the source image on to a destination render cont...
virtual ~QgsShadowEffect()
A paint effect which draws an offset and optionally blurred drop shadow.
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
virtual void draw(QgsRenderContext &context) override
Handles drawing of the effect&#39;s result on to the specified render context.
DrawMode
Drawing modes for effects.
virtual QgsInnerShadowEffect * clone() const override
Duplicates an effect by creating a deep copy of the effect.
void invertPixels(InvertMode mode)
void restore()
A paint effect which draws an offset and optionally blurred drop shadow within a picture.
Contains information about the context of a rendering operation.
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, QFlags< Qt::ImageConversionFlag > flags)
QPainter * painter()
static void stackBlur(QImage &image, const int radius, const bool alphaOnly=false)
Performs a stack blur on an image.
QgsSymbolV2::OutputUnit mOffsetUnit
virtual 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...
static QgsPaintEffect * create(const QgsStringMap &map)
Creates a new QgsInnerShadowEffect effect from a properties string map.
Base class for paint effects which offset, blurred shadows.
QRectF adjusted(qreal dx1, qreal dy1, qreal dx2, qreal dy2) const
int height() const
static QColor decodeColor(const QString &str)
iterator insert(const Key &key, const T &value)
const QPicture * source() const
Returns the source QPicture.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
const T value(const Key &key) const
static QgsPaintEffect * create(const QgsStringMap &map)
Creates a new QgsDropShadowEffect effect from a properties string map.