Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_ls_drop_shadow_filter.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <cstdlib>
10
11
12#include <KoUpdater.h>
14
15#include "psd.h"
16
19#include "kis_gaussian_kernel.h"
20
21#include "kis_pixel_selection.h"
22#include "kis_fill_painter.h"
23#include "kis_iterator_ng.h"
25
26#include "kis_psd_layer_style.h"
27
29#include "kis_ls_utils.h"
32
33
34
36 : KisLayerStyleFilter(KoID("lsdropshadow", i18n("Drop Shadow (style)")))
37 , m_mode(mode)
38{
39}
40
46
51
53{
58
59 ShadowRectsData(const QRect &applyRect,
60 const psd_layer_effects_context *context,
62 Direction direction)
63 {
64 spread_size = (shadow->spread() * shadow->size() + 50) / 100;
65 blur_size = shadow->size() - spread_size;
66 offset = shadow->calculateOffset(context);
67
68 // need rect calculation in reverse order
69 dstRect = applyRect;
70
71 const int directionCoeff = direction == NEED_RECT ? -1 : 1;
72 srcRect = dstRect.translated(directionCoeff * offset);
73
74 noiseNeedRect = shadow->noise() > 0 ?
76
79
82
83 // dbgKrita << ppVar(dstRect);
84 // dbgKrita << ppVar(srcRect);
85 // dbgKrita << ppVar(noiseNeedRect);
86 // dbgKrita << ppVar(blurNeedRect);
87 // dbgKrita << ppVar(spreadNeedRect);
88 }
89
90 inline QRect finalNeedRect() const {
91 return spreadNeedRect;
92 }
93
94 inline QRect finalChangeRect() const {
95 // TODO: is it correct?
96 return spreadNeedRect;
97 }
98
100 qint32 blur_size;
101 QPoint offset;
102
103 QRect srcRect;
104 QRect dstRect;
108};
109
112 const QRect &applyRect,
113 const psd_layer_effects_context *context,
114 const psd_layer_effects_shadow_base *shadow,
115 KisResourcesInterfaceSP resourcesInterface,
117{
118 if (applyRect.isEmpty()) return;
119
120 ShadowRectsData d(applyRect, context, shadow, ShadowRectsData::NEED_RECT);
121
123 KisSelectionSP baseSelection = s1.selection();
124 KisLsUtils::selectionFromAlphaChannel(srcDevice, baseSelection, d.spreadNeedRect);
125
126 KisPixelSelectionSP selection = baseSelection->pixelSelection();
127
128 //selection->convertToQImage(0, QRect(0,0,300,300)).save("0_selection_initial.png");
129
130 if (shadow->invertsSelection()) {
131 selection->invert();
132 }
133
138 KisPixelSelectionSP knockOutSelection;
139 if (shadow->knocksOut()) {
140 knockOutSelection = s2.selection()->pixelSelection();
141 knockOutSelection->makeCloneFromRough(selection, selection->selectedRect());
142 }
143
144 if (shadow->technique() == psd_technique_precise) {
145 KisLsUtils::findEdge(selection, d.blurNeedRect, true);
146 }
147
151 if (d.spread_size) {
152 KisLsUtils::applyGaussianWithTransaction(selection, d.blurNeedRect, d.spread_size);
153
154 // TODO: find out why in libpsd we pass false here. If we do so,
155 // the result is fully black, which is not expected
156 KisLsUtils::findEdge(selection, d.blurNeedRect, true /*shadow->edgeHidden()*/);
157 }
158
159 //selection->convertToQImage(0, QRect(0,0,300,300)).save("1_selection_spread.png");
160
161 if (d.blur_size) {
162 KisLsUtils::applyGaussianWithTransaction(selection, d.noiseNeedRect, d.blur_size);
163 }
164 //selection->convertToQImage(0, QRect(0,0,300,300)).save("2_selection_blur.png");
165
166 if (shadow->range() != KisLsUtils::FULL_PERCENT_RANGE) {
167 KisLsUtils::adjustRange(selection, d.noiseNeedRect, shadow->range());
168 }
169
170 const psd_layer_effects_inner_glow *iglow = 0;
171 if ((iglow =
172 dynamic_cast<const psd_layer_effects_inner_glow *>(shadow)) &&
173 iglow->source() == psd_glow_center) {
174
175 selection->invert();
176 }
177
182 d.noiseNeedRect,
183 shadow->contourLookupTable(),
184 shadow->antiAliased(),
185 shadow->edgeHidden());
186
187 //selection->convertToQImage(0, QRect(0,0,300,300)).save("3_selection_contour.png");
188
192 if (shadow->noise() > 0) {
193 KisLsUtils::applyNoise(selection,
194 d.srcRect,
195 shadow->noise(),
196 context,
197 env);
198 }
199 //selection->convertToQImage(0, QRect(0,0,300,300)).save("4_selection_noise.png");
200
201 if (!d.offset.isNull()) {
202 selection->moveTo(selection->offset() + d.offset);
203 }
204
208 if (shadow->knocksOut()) {
209 KIS_ASSERT_RECOVER_RETURN(knockOutSelection);
210
211 QRect knockOutRect = !shadow->invertsSelection() ?
212 d.srcRect : d.spreadNeedRect;
213
214 knockOutRect &= d.dstRect;
215
216 KisPainter gc(selection);
218 gc.bitBlt(knockOutRect.topLeft(), knockOutSelection, knockOutRect);
219 }
220 //selection->convertToQImage(0, QRect(0,0,300,300)).save("5_selection_knockout.png");
221
223 baseSelection,
224 srcDevice,
225 dst,
226 d.srcRect,
227 d.dstRect,
228 context,
229 shadow,
230 resourcesInterface,
231 env);
232}
233
236{
237 const psd_layer_effects_shadow_base *config = 0;
238
239 if (m_mode == DropShadow) {
240 config = style->dropShadow();
241 } else if (m_mode == InnerShadow) {
242 config = style->innerShadow();
243 } else if (m_mode == OuterGlow) {
244 config = style->outerGlow();
245 } else if (m_mode == InnerGlow) {
246 config = style->innerGlow();
247 }
248
249 return config;
250}
251
255 const QRect &applyRect,
256 KisPSDLayerStyleSP style,
258{
259 Q_UNUSED(blower);
261
262 const psd_layer_effects_shadow_base *config = getShadowStruct(style);
263 if (!KisLsUtils::checkEffectEnabled(config, dst)) return;
264
266 applyDropShadow(src, dst, applyRect, style->context(), w.config, style->resourcesInterface(), env);
267}
268
270{
271 const psd_layer_effects_shadow_base *shadowStruct = getShadowStruct(style);
272 if (!shadowStruct->effectEnabled()) return rect;
273
275 ShadowRectsData d(rect, style->context(), w.config, ShadowRectsData::NEED_RECT);
276 return rect | d.finalNeedRect();
277}
278
280{
281 const psd_layer_effects_shadow_base *shadowStruct = getShadowStruct(style);
282 if (!shadowStruct->effectEnabled()) return rect;
283
285 ShadowRectsData d(rect, style->context(), w.config, ShadowRectsData::CHANGE_RECT);
286 return style->context()->keep_original ?
287 d.finalChangeRect() : rect | d.finalChangeRect();
288}
QPointF s1
QPointF s2
const QString COMPOSITE_ERASE
QRect changedRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override
KisLsDropShadowFilter(Mode mode=DropShadow)
const psd_layer_effects_shadow_base * getShadowStruct(KisPSDLayerStyleSP style) const
void applyDropShadow(KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, const QRect &applyRect, const psd_layer_effects_context *context, const psd_layer_effects_shadow_base *shadow, KisResourcesInterfaceSP resourcesInterface, KisLayerStyleFilterEnvironment *env) const
KisLayerStyleFilter * clone() const override
void processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override
QRect neededRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override
QPoint offset() const
void bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
void setCompositeOpId(const KoCompositeOp *op)
Definition KoID.h:30
psd_glow_source source() const
Definition psd.h:606
qint32 range() const
Definition psd.h:351
bool knocksOut() const
Definition psd.h:326
bool effectEnabled() const
Definition psd.h:261
qint32 spread() const
Definition psd.h:301
psd_technique_type technique() const
Definition psd.h:346
qint32 noise() const
Definition psd.h:321
bool invertsSelection() const
Definition psd.h:331
QPoint calculateOffset(const psd_layer_effects_context *context) const
Definition psd.cpp:243
qint32 size() const
Definition psd.h:306
bool edgeHidden() const
Definition psd.h:336
const quint8 * contourLookupTable() const
Definition psd.h:311
bool antiAliased() const
Definition psd.h:316
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
T kisGrowRect(const T &rect, U offset)
Definition kis_global.h:186
void applyContourCorrection(KisPixelSelectionSP selection, const QRect &applyRect, const quint8 *lookup_table, bool antiAliased, bool edgeHidden)
const int noiseNeedBorder
QRect growRectFromRadius(const QRect &rc, int radius)
void adjustRange(KisPixelSelectionSP selection, const QRect &applyRect, const int range)
void findEdge(KisPixelSelectionSP selection, const QRect &applyRect, const bool edgeHidden)
void applyNoise(KisPixelSelectionSP selection, const QRect &applyRect, int noise, const psd_layer_effects_context *context, KisLayerStyleFilterEnvironment *env)
bool checkEffectEnabled(const psd_layer_effects_shadow_base *config, KisMultipleProjection *dst)
void selectionFromAlphaChannel(KisPaintDeviceSP srcDevice, KisSelectionSP dstSelection, const QRect &srcRect)
static const int FULL_PERCENT_RANGE
void applyGaussianWithTransaction(KisPixelSelectionSP selection, const QRect &applyRect, qreal radius)
void applyFinalSelection(const QString &projectionId, KisSelectionSP baseSelection, KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, const QRect &, const QRect &dstRect, const psd_layer_effects_context *, const psd_layer_effects_shadow_base *config, KisResourcesInterfaceSP resourcesInterface, const KisLayerStyleFilterEnvironment *env)
@ psd_glow_center
Definition psd.h:130
@ psd_technique_precise
Definition psd.h:117
void moveTo(const QPoint &pt) override
KisPixelSelectionSP pixelSelection
ShadowRectsData(const QRect &applyRect, const psd_layer_effects_context *context, const psd_layer_effects_shadow_base *shadow, Direction direction)