QGIS API Documentation 3.34.0-Prizren (ffbdd678812)
Loading...
Searching...
No Matches
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 if ( context.feedback() && context.feedback()->isCanceled() )
35 return;
36
37 QImage colorisedIm = sourceAsImage( context )->copy();
38
39 if ( context.feedback() && context.feedback()->isCanceled() )
40 return;
41
42 QPainter *painter = context.painter();
43 const QgsScopedQPainterState painterState( painter );
44 painter->setCompositionMode( mBlendMode );
45
46 if ( !exteriorShadow() )
47 {
48 //inner shadow, first invert the opacity. The color does not matter since we will
49 //be replacing it anyway
50 colorisedIm.invertPixels( QImage::InvertRgba );
51 }
52
54
56 if ( blurLevel <= 16 )
57 {
58 QgsImageOperation::stackBlur( colorisedIm, blurLevel, false, context.feedback() );
59 }
60 else
61 {
62 QImage *imb = QgsImageOperation::gaussianBlur( colorisedIm, blurLevel, context.feedback() );
63 if ( !imb->isNull() )
64 colorisedIm = QImage( *imb );
65 delete imb;
66 }
67
68 const double offsetDist = context.convertToPainterUnits( mOffsetDist, mOffsetUnit, mOffsetMapUnitScale );
69
70 const double angleRad = mOffsetAngle * M_PI / 180; // to radians
71 const QPointF transPt( -offsetDist * std::cos( angleRad + M_PI_2 ),
72 -offsetDist * std::sin( angleRad + M_PI_2 ) );
73
74 //transparency, scale
75 QgsImageOperation::multiplyOpacity( colorisedIm, mOpacity, context.feedback() );
76
77 if ( !exteriorShadow() )
78 {
79 //inner shadow, do a bit of painter juggling
80 QImage innerShadowIm( colorisedIm.width(), colorisedIm.height(), QImage::Format_ARGB32 );
81 innerShadowIm.fill( Qt::transparent );
82 QPainter imPainter( &innerShadowIm );
83
84 //draw shadow at offset
85 imPainter.drawImage( transPt.x(), transPt.y(), colorisedIm );
86
87 //restrict shadow so it's only drawn on top of original image
88 imPainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
89 imPainter.drawImage( 0, 0, *sourceAsImage( context ) );
90 imPainter.end();
91
92 painter->drawImage( imageOffset( context ), innerShadowIm );
93 }
94 else
95 {
96 painter->drawImage( imageOffset( context ) + transPt, colorisedIm );
97 }
98}
99
101{
102 QVariantMap props;
103 props.insert( QStringLiteral( "enabled" ), mEnabled ? "1" : "0" );
104 props.insert( QStringLiteral( "draw_mode" ), QString::number( int( mDrawMode ) ) );
105 props.insert( QStringLiteral( "blend_mode" ), QString::number( int( mBlendMode ) ) );
106 props.insert( QStringLiteral( "opacity" ), QString::number( mOpacity ) );
107 props.insert( QStringLiteral( "blur_level" ), QString::number( mBlurLevel ) );
108 props.insert( QStringLiteral( "blur_unit" ), QgsUnitTypes::encodeUnit( mBlurUnit ) );
109 props.insert( QStringLiteral( "blur_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mBlurMapUnitScale ) );
110 props.insert( QStringLiteral( "offset_angle" ), QString::number( mOffsetAngle ) );
111 props.insert( QStringLiteral( "offset_distance" ), QString::number( mOffsetDist ) );
112 props.insert( QStringLiteral( "offset_unit" ), QgsUnitTypes::encodeUnit( mOffsetUnit ) );
113 props.insert( QStringLiteral( "offset_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale ) );
114 props.insert( QStringLiteral( "color" ), QgsSymbolLayerUtils::encodeColor( mColor ) );
115 return props;
116}
117
118void QgsShadowEffect::readProperties( const QVariantMap &props )
119{
120 bool ok;
121 const QPainter::CompositionMode mode = static_cast< QPainter::CompositionMode >( props.value( QStringLiteral( "blend_mode" ) ).toInt( &ok ) );
122 if ( ok )
123 {
124 mBlendMode = mode;
125 }
126 if ( props.contains( QStringLiteral( "transparency" ) ) )
127 {
128 const double transparency = props.value( QStringLiteral( "transparency" ) ).toDouble( &ok );
129 if ( ok )
130 {
131 mOpacity = 1.0 - transparency;
132 }
133 }
134 else
135 {
136 const double opacity = props.value( QStringLiteral( "opacity" ) ).toDouble( &ok );
137 if ( ok )
138 {
140 }
141 }
142 mEnabled = props.value( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ).toInt();
143 mDrawMode = static_cast< QgsPaintEffect::DrawMode >( props.value( QStringLiteral( "draw_mode" ), QStringLiteral( "2" ) ).toInt() );
144 const double level = props.value( QStringLiteral( "blur_level" ) ).toDouble( &ok );
145 if ( ok )
146 {
147 mBlurLevel = level;
148 if ( !props.contains( QStringLiteral( "blur_unit" ) ) )
149 {
150 // deal with pre blur unit era by assuming 96 dpi and converting pixel values as millimeters
151 mBlurLevel *= 0.2645;
152 }
153 }
154 mBlurUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "blur_unit" ) ).toString() );
155 mBlurMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "blur_unit_scale" ) ).toString() );
156 const int angle = props.value( QStringLiteral( "offset_angle" ) ).toInt( &ok );
157 if ( ok )
158 {
159 mOffsetAngle = angle;
160 }
161 const double distance = props.value( QStringLiteral( "offset_distance" ) ).toDouble( &ok );
162 if ( ok )
163 {
164 mOffsetDist = distance;
165 }
166 mOffsetUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "offset_unit" ) ).toString() );
167 mOffsetMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "offset_unit_scale" ) ).toString() );
168 if ( props.contains( QStringLiteral( "color" ) ) )
169 {
170 mColor = QgsSymbolLayerUtils::decodeColor( props.value( QStringLiteral( "color" ) ).toString() );
171 }
172}
173
174QRectF QgsShadowEffect::boundingRect( const QRectF &rect, const QgsRenderContext &context ) const
175{
176 //blur radius and offset distance
178
179 // spread is initially the shadow offset size
181
182 //plus possible extension due to blur, with a couple of extra pixels thrown in for safety
183 spread += blurLevel * 2 + 10;
184 return rect.adjusted( -spread, -spread, spread, spread );
185}
186
187
188//
189// QgsDropShadowEffect
190//
191
193{
195 effect->readProperties( map );
196 return effect;
197}
198
204
206{
207 return QStringLiteral( "dropShadow" );
208}
209
211{
212 return new QgsDropShadowEffect( *this );
213}
214
216{
217 return true;
218}
219
220
221//
222// QgsInnerShadowEffect
223//
224
226{
228 effect->readProperties( map );
229 return effect;
230}
231
237
239{
240 return QStringLiteral( "innerShadow" );
241}
242
247
249{
250 return false;
251}
A paint effect which draws an offset and optionally blurred drop shadow.
static QgsPaintEffect * create(const QVariantMap &map)
Creates a new QgsDropShadowEffect effect from a properties string map.
QString type() const override
Returns the effect type.
QgsDropShadowEffect * clone() const override
Duplicates an effect by creating a deep copy of the effect.
bool exteriorShadow() const override
Specifies whether the shadow is drawn outside the picture or within the picture.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:54
static void multiplyOpacity(QImage &image, double factor, QgsFeedback *feedback=nullptr)
Multiplies opacity of image pixel values by a factor.
static void overlayColor(QImage &image, const QColor &color)
Overlays a color onto an image.
static QImage * gaussianBlur(QImage &image, int radius, QgsFeedback *feedback=nullptr)
Performs a gaussian blur on an image.
static void stackBlur(QImage &image, int radius, bool alphaOnly=false, QgsFeedback *feedback=nullptr)
Performs a stack blur on an image.
A paint effect which draws an offset and optionally blurred drop shadow within a picture.
bool exteriorShadow() const override
Specifies whether the shadow is drawn outside the picture or within the picture.
QString type() const override
Returns the effect type.
static QgsPaintEffect * create(const QVariantMap &map)
Creates a new QgsInnerShadowEffect effect from a properties string map.
QgsInnerShadowEffect * clone() const override
Duplicates an effect by creating a deep copy of the effect.
Base class for visual effects which can be applied to QPicture drawings.
QPointF imageOffset(const QgsRenderContext &context) const
Returns the offset which should be used when drawing the source image on to a destination render cont...
const QPicture * source() const
Returns the source QPicture.
bool enabled() const
Returns whether the effect is enabled.
DrawMode
Drawing modes for effects.
QImage * sourceAsImage(QgsRenderContext &context)
Returns the source QPicture rendered to a new QImage.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly during rendering to check if rendering shou...
Scoped object for saving and restoring a QPainter object's state.
Base class for paint effects which offset, blurred shadows.
QVariantMap properties() const override
Returns the properties describing the paint effect encoded in a string format.
double opacity() const
Returns the opacity for the effect.
Qgis::RenderUnit mOffsetUnit
virtual bool exteriorShadow() const =0
Specifies whether the shadow is drawn outside the picture or within the picture.
void draw(QgsRenderContext &context) override
Handles drawing of the effect's result on to the specified render context.
QgsMapUnitScale mOffsetMapUnitScale
Qgis::RenderUnit mBlurUnit
QRectF boundingRect(const QRectF &rect, const QgsRenderContext &context) const override
Returns the bounding rect required for drawing the effect.
double blurLevel() const
Returns the blur level (radius) for the shadow.
QPainter::CompositionMode mBlendMode
void readProperties(const QVariantMap &props) override
Reads a string map of an effect's properties and restores the effect to the state described by the pr...
QgsMapUnitScale mBlurMapUnitScale
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static QColor decodeColor(const QString &str)
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static QString encodeColor(const QColor &color)
static Q_INVOKABLE Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.