From 08ebcff89f56bec3b0f9b346504748e4eb1687af Mon Sep 17 00:00:00 2001 From: Mike Kaganski Date: Fri, 1 May 2020 01:05:24 +0300 Subject: tdf#101181: improve glow effect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The shadow of objects must not be scaled: this displaces any internal areas that need blur, e.g. holes. Instead, it needs to dilate the shadow using kernel with radius equal to blur radius: this allows the borders of dilated objects to be in the middle of the blur area. The following blur makes those new margin points to have 50% intensity, and full glow intensity at the point of old object margins. This also removed artifacts when moving objects with glow effect caused by mismatch between scaling and D2D range calculation. The D2D range therefore is not calculated by scaling, but using grow. Blur filter's "extend bitmap by blur radius" option got obsoleted and removed. There's no need to blur the glow color (24-bit RGB). Instead, glow bitmap must be filled by glow color, and have an alpha mask that is blurred accordingly. This makes the glow properly transparent, and also reduces the blur complexity which now only needs to process 8 bits of alpha channel. The object shadow is created using basegfx::BColorModifier_replace inserted into the 2d decomposition of the effect, as before. To make sure that any non-fully-transparent pixel will become black pixel in the shadow, black color is used, and the result is further processed in VclPixelProcessor2D::processGlowPrimitive2D with monochrome filter using threshold 255. Glow transparency attribute is taken into account: the initial value at the margins of the objects. Color replacement filter is used to replace the object shadow with the attribute value before blur pass. Correct blur radius is used, calculated from glow effect radius, instead of hardcoded value of 5 pixels. This makes the glow to fade gradually along the full width of the effect, instead of only fading in narrow outer border previously. Since blur filter is only implemented for radius up to 254 pixels, and since downsampling the shadow before blur increases performance without noticeable quality loss, the image is downsampled before filtering. It should be noted that the glow effect is almost identical to soft shadow effect, likely with the only difference of using dilation in the former, but not in the latter. The code might be reused later to implement soft shadow as well. Change-Id: I728c532f9df7ccf85f353c23c6c7d8352d7b2086 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/93235 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl Reviewed-by: Mike Kaganski --- include/drawinglayer/attribute/sdrglowattribute.hxx | 15 ++++++--------- include/drawinglayer/primitive2d/glowprimitive2d.hxx | 16 ++++++++-------- 2 files changed, 14 insertions(+), 17 deletions(-) (limited to 'include/drawinglayer') diff --git a/include/drawinglayer/attribute/sdrglowattribute.hxx b/include/drawinglayer/attribute/sdrglowattribute.hxx index f5120c1a2044..b17560bd76af 100644 --- a/include/drawinglayer/attribute/sdrglowattribute.hxx +++ b/include/drawinglayer/attribute/sdrglowattribute.hxx @@ -15,8 +15,7 @@ #include #include #include - -#include +#include namespace drawinglayer { @@ -26,11 +25,10 @@ class DRAWINGLAYER_DLLPUBLIC SdrGlowAttribute { private: sal_Int32 m_nRadius = 0; - mutable std::optional m_oTransfCache; - basegfx::BColor m_color; + Color m_color; // Includes alpha! public: - SdrGlowAttribute(sal_Int32 nRadius, const basegfx::BColor& rColor); + SdrGlowAttribute(sal_Int32 nRadius, const Color& rColor); SdrGlowAttribute(); SdrGlowAttribute(const SdrGlowAttribute&); SdrGlowAttribute(SdrGlowAttribute&&); @@ -41,10 +39,9 @@ public: SdrGlowAttribute& operator=(SdrGlowAttribute&&); // data access - const basegfx::B2DHomMatrix& GetTransfMatrix(basegfx::B2DRange nCenter) const; - const basegfx::BColor& getColor() const { return m_color; }; - sal_Int32 getRadius() const { return m_nRadius; }; - bool isDefault() const { return m_nRadius == 0; }; + const Color& getColor() const { return m_color; } + sal_Int32 getRadius() const { return m_nRadius; } + bool isDefault() const { return m_nRadius == 0; } }; } // end of namespace attribute } // end of namespace drawinglayer diff --git a/include/drawinglayer/primitive2d/glowprimitive2d.hxx b/include/drawinglayer/primitive2d/glowprimitive2d.hxx index 0c77a9a94a6c..1aacdf0dde68 100644 --- a/include/drawinglayer/primitive2d/glowprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/glowprimitive2d.hxx @@ -25,6 +25,7 @@ #include #include #include +#include namespace drawinglayer { @@ -33,20 +34,19 @@ namespace primitive2d class DRAWINGLAYER_DLLPUBLIC GlowPrimitive2D final : public GroupPrimitive2D { private: - /// the Glow transformation, normally just an offset - basegfx::B2DHomMatrix maGlowTransform; + /// the Glow color to which all geometry is to be forced; includes alpha + Color maGlowColor; - /// the Glow color to which all geometry is to be forced - basegfx::BColor maGlowColor; + /// the Glow size, in logical units (100ths of mm) + double mfGlowRadius; public: /// constructor - GlowPrimitive2D(const basegfx::B2DHomMatrix& rGlowTransform, const basegfx::BColor& rGlowColor, - const Primitive2DContainer& rChildren); + GlowPrimitive2D(const Color& rGlowColor, double fRadius, const Primitive2DContainer& rChildren); /// data read access - const basegfx::B2DHomMatrix& getGlowTransform() const { return maGlowTransform; } - const basegfx::BColor& getGlowColor() const { return maGlowColor; } + const Color& getGlowColor() const { return maGlowColor; } + double getGlowRadius() const { return mfGlowRadius; } /// compare operator virtual bool operator==(const BasePrimitive2D& rPrimitive) const override; -- cgit