Blur and noise adjustment layers, Image Trim, Inner Glow (12.8c)

This commit is contained in:
雷电芽衣 committed 2026-09-28 08:35:59 -04:00
1 parent 7ae263de80
commit 31e2dd3864
60 files changed
+1673 -105

No files matched your search

+21 -4
View File
@@ -88,7 +88,8 @@ QImage replayed(const QImage &pixels, const LayerEffects &effects)
}
const auto on = [](const auto &effect) { return effect && effect->isEnabled() && effect->opacity > 0; };
const bool stroke = on(effects.stroke) && effects.stroke->size > 0;
std::vector<float> ring(shader.shape.size()), cast(shader.shape.size()), inner(shader.shape.size()), glow(shader.shape.size());
std::vector<float> ring(shader.shape.size()), cast(shader.shape.size()), inner(shader.shape.size()), glow(shader.shape.size()),
innerGlow(shader.shape.size());
if (stroke) {
const int reach = std::max(1, int(std::lround(effects.stroke->size)));
const std::vector<float> moved = shader.spread(shader.spread(shader.shape, reach, effects.stroke->inside, true), reach, effects.stroke->inside, false);
@@ -101,6 +102,12 @@ QImage replayed(const QImage &pixels, const LayerEffects &effects)
const bool glowing = on(effects.outerGlow) && effects.outerGlow->size > 0;
if (glowing)
glow = shader.softened(shader.shape, float(effects.outerGlow->size / 2));
const bool glowingInside = on(effects.innerGlow) && effects.innerGlow->size > 0;
if (glowingInside) {
const std::vector<float> softened = shader.softened(shader.shape, float(effects.innerGlow->size / 2));
for (size_t index = 0; index < innerGlow.size(); ++index)
innerGlow[index] = std::clamp(shader.shape[index] * (1.f - softened[index]), 0.f, 1.f);
}
if (on(effects.innerShadow)) {
const std::vector<float> moved = shader.softened(shader.shift(shader.shape, float(effects.innerShadow->offset().width()),
float(effects.innerShadow->offset().height())),
@@ -133,6 +140,8 @@ QImage replayed(const QImage &pixels, const LayerEffects &effects)
alpha = sourceAlpha + alpha * (1.f - sourceAlpha);
if (on(effects.colorOverlay))
blend(effects.colorOverlay->color(), std::clamp(shader.shape[index] * float(effects.colorOverlay->opacity), 0.f, 1.f));
if (glowingInside)
blend(effects.innerGlow->color(), std::clamp(innerGlow[index] * float(effects.innerGlow->opacity), 0.f, 1.f));
if (on(effects.innerShadow))
blend(effects.innerShadow->color(), std::clamp(inner[index] * float(effects.innerShadow->opacity), 0.f, 1.f));
if (stroke && effects.stroke->inside)
@@ -194,7 +203,7 @@ private slots:
void LayerEffectsKernelTests::everyEffectMatchesTheShader_data()
{
QTest::addColumn<LayerEffects>("effects");
LayerEffects outside, inside, shadow, overlay, inner, glow, hair, all, wide;
LayerEffects outside, inside, shadow, overlay, inner, glow, hair, all, wide, innerGlow, innerHair;
outside.stroke = StrokeEffect{.size = 3, .red = 1, .green = 0.5, .blue = 0.25, .opacity = 0.8};
inside.stroke = StrokeEffect{.size = 2.5, .red = 0.1, .green = 0.2, .blue = 0.9, .opacity = 1, .inside = true};
shadow.shadow = ShadowEffect{.angle = 45, .distance = 3.5, .blur = 4, .red = 0.3, .green = 0.1, .blue = 0.6, .opacity = 0.75};
@@ -202,11 +211,14 @@ void LayerEffectsKernelTests::everyEffectMatchesTheShader_data()
inner.innerShadow = InnerShadowEffect{.angle = -60, .distance = 2, .blur = 3, .red = 0, .green = 0.4, .blue = 0.2, .opacity = 0.9};
glow.outerGlow = OuterGlowEffect{.size = 6, .red = 0.2, .green = 0.9, .blue = 0.4, .opacity = 0.8};
hair.outerGlow = OuterGlowEffect{.size = 0.01, .opacity = 1};
innerGlow.innerGlow = InnerGlowEffect{.size = 7, .red = 0.8, .green = 0.3, .blue = 0.1, .opacity = 0.7};
innerHair.innerGlow = InnerGlowEffect{.size = 0.01, .red = 0, .opacity = 1};
all = outside;
all.shadow = shadow.shadow;
all.colorOverlay = overlay.colorOverlay;
all.innerShadow = inner.innerShadow;
all.outerGlow = glow.outerGlow;
all.innerGlow = innerGlow.innerGlow;
all.shadow->blur = 0;
wide.stroke = StrokeEffect{.size = 9, .red = 1, .opacity = 1};
wide.shadow = ShadowEffect{.angle = 200, .distance = 0.5, .blur = 0.01, .opacity = 1};
@@ -217,6 +229,8 @@ void LayerEffectsKernelTests::everyEffectMatchesTheShader_data()
QTest::newRow("inner shadow") << inner;
QTest::newRow("outer glow") << glow;
QTest::newRow("a glow a hair wide") << hair;
QTest::newRow("inner glow") << innerGlow;
QTest::newRow("an inner glow a hair wide") << innerHair;
QTest::newRow("all, a sharp shadow") << all;
QTest::newRow("wide stroke, a barely blurred shadow") << wide;
}
@@ -244,14 +258,17 @@ void LayerEffectsKernelTests::switchedOffOrEmptyEffectsLeaveThePixels()
hidden.colorOverlay = ColorOverlayEffect{.enabled = false, .red = 1};
hidden.innerShadow = InnerShadowEffect{.enabled = false};
hidden.outerGlow = OuterGlowEffect{.enabled = false};
LayerEffects dim, flat;
hidden.innerGlow = InnerGlowEffect{.enabled = false};
LayerEffects dim, flat, dimInside, flatInside;
dim.outerGlow = OuterGlowEffect{.opacity = 0};
flat.outerGlow = OuterGlowEffect{.size = 0};
dimInside.innerGlow = InnerGlowEffect{.opacity = 0};
flatInside.innerGlow = InnerGlowEffect{.size = 0};
LayerEffects thin;
thin.stroke = StrokeEffect{.size = 0, .red = 1};
LayerEffects clear;
clear.shadow = ShadowEffect{.opacity = 0};
for (const LayerEffects &effects : {LayerEffects(), hidden, thin, clear, dim, flat})
for (const LayerEffects &effects : {LayerEffects(), hidden, thin, clear, dim, flat, dimInside, flatInside})
QCOMPARE(gap(LayerEffectsKernel::render(pixels, effects), pixels), 0);
// Stroke sizes round to whole pixels, one at least.
LayerEffects fraction, one;