svgio/qa/cppunit/SvgImportTest.cxx            |   44 ++++++++++++++++++++++++++
 svgio/qa/cppunit/data/screenBlend.svg         |    8 ++++
 vcl/source/bitmap/BitmapScreenBlendFilter.cxx |   21 ++++++++++--
 3 files changed, 70 insertions(+), 3 deletions(-)

New commits:
commit 357e390be47f774aab8ffb09015aaf312abff06b
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Mon Apr 22 12:00:55 2024 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Apr 22 13:31:44 2024 +0200

    tdf#159660: premultiply colors for screen blend
    
    This is needed after 4b6e0f2c88debaedb514c868e061c21e15215b6e
    "tdf#160726, tdf#48062: Simplify how BitmapExs are created"
    Otherwise, only the common area is displayed
    
    Change-Id: I40c798380049e62df8729c4acdb5db50d988d8e1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166426
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/svgio/qa/cppunit/SvgImportTest.cxx 
b/svgio/qa/cppunit/SvgImportTest.cxx
index 93d43fae85e2..c336458df004 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -1777,6 +1777,50 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf160726)
     CPPUNIT_ASSERT_EQUAL(OUString("ffff00"), aPixels[200]);
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testScreenBlend)
+{
+    xmlDocUniquePtr pDocument = 
dumpAndParseSvg(u"/svgio/qa/cppunit/data/screenBlend.svg");
+
+    assertXPath(pDocument,
+            "/primitive2D/transform/transform/bitmap"_ostr, "height"_ostr, 
"150");
+    assertXPath(pDocument,
+            "/primitive2D/transform/transform/bitmap"_ostr, "width"_ostr, 
"150");
+    assertXPath(pDocument,
+            "/primitive2D/transform/transform/bitmap/data"_ostr, 150);
+
+    assertXPath(pDocument,
+            "/primitive2D/transform/transform/bitmap"_ostr, "xy11"_ostr, 
"150");
+    assertXPath(pDocument,
+            "/primitive2D/transform/transform/bitmap"_ostr, "xy12"_ostr, "0");
+    assertXPath(pDocument,
+            "/primitive2D/transform/transform/bitmap"_ostr, "xy13"_ostr, "20");
+    assertXPath(pDocument,
+            "/primitive2D/transform/transform/bitmap"_ostr, "xy21"_ostr, "0");
+    assertXPath(pDocument,
+            "/primitive2D/transform/transform/bitmap"_ostr, "xy22"_ostr, 
"150");
+    assertXPath(pDocument,
+            "/primitive2D/transform/transform/bitmap"_ostr, "xy23"_ostr, "20");
+    assertXPath(pDocument,
+            "/primitive2D/transform/transform/bitmap"_ostr, "xy31"_ostr, "0");
+    assertXPath(pDocument,
+            "/primitive2D/transform/transform/bitmap"_ostr, "xy32"_ostr, "0");
+    assertXPath(pDocument,
+            "/primitive2D/transform/transform/bitmap"_ostr, "xy33"_ostr, "1");
+
+    // Check the colors in the diagonal
+    OUString sDataRow = getXPath(pDocument, 
"/primitive2D/transform/transform/bitmap/data[25]"_ostr, "row"_ostr);
+    std::vector<OUString> aPixels = comphelper::string::split(sDataRow, ',');
+    CPPUNIT_ASSERT_EQUAL(OUString("ff0000"), aPixels[25]);
+
+    sDataRow = getXPath(pDocument, 
"/primitive2D/transform/transform/bitmap/data[75]"_ostr, "row"_ostr);
+    aPixels = comphelper::string::split(sDataRow, ',');
+    CPPUNIT_ASSERT_EQUAL(OUString("ff8000"), aPixels[75]);
+
+    sDataRow = getXPath(pDocument, 
"/primitive2D/transform/transform/bitmap/data[125]"_ostr, "row"_ostr);
+    aPixels = comphelper::string::split(sDataRow, ',');
+    CPPUNIT_ASSERT_EQUAL(OUString("008000"), aPixels[125]);
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testTdf149880)
 {
     xmlDocUniquePtr pDocument = 
dumpAndParseSvg(u"/svgio/qa/cppunit/data/tdf149880.svg");
diff --git a/svgio/qa/cppunit/data/screenBlend.svg 
b/svgio/qa/cppunit/data/screenBlend.svg
new file mode 100644
index 000000000000..6f1490983f68
--- /dev/null
+++ b/svgio/qa/cppunit/data/screenBlend.svg
@@ -0,0 +1,8 @@
+<svg width="100" height="140" viewBox="0 0 200 280" 
xmlns="http://www.w3.org/2000/svg";>
+  <filter id="filter" filterUnits="userSpaceOnUse" x="0" y="0" width="100%" 
height="100%">
+    <feFlood x="20" y="20" width="100" height="100" flood-color="red" 
flood-opacity="1" result="img1"></feFlood>
+    <feFlood x="50" y="50" width="100" height="100" flood-color="green" 
flood-opacity="1" result="img2"></feFlood>
+    <feBlend in="img1" in2="img2" mode="screen"></feBlend>
+  </filter>
+  <use style="filter: url(#filter)"></use>
+</svg>
diff --git a/vcl/source/bitmap/BitmapScreenBlendFilter.cxx 
b/vcl/source/bitmap/BitmapScreenBlendFilter.cxx
index 67525a24cdf9..0964c519571d 100644
--- a/vcl/source/bitmap/BitmapScreenBlendFilter.cxx
+++ b/vcl/source/bitmap/BitmapScreenBlendFilter.cxx
@@ -30,6 +30,20 @@ static sal_uInt8 lcl_calculate(const sal_uInt8 aColor, const 
sal_uInt8 aColor2)
     return result * 255.0;
 }
 
+static BitmapColor premultiply(const BitmapColor c)
+{
+    return BitmapColor(ColorAlpha, vcl::bitmap::premultiply(c.GetRed(), 
c.GetAlpha()),
+                       vcl::bitmap::premultiply(c.GetGreen(), c.GetAlpha()),
+                       vcl::bitmap::premultiply(c.GetBlue(), c.GetAlpha()), 
c.GetAlpha());
+}
+
+static BitmapColor unpremultiply(const BitmapColor c)
+{
+    return BitmapColor(ColorAlpha, vcl::bitmap::unpremultiply(c.GetRed(), 
c.GetAlpha()),
+                       vcl::bitmap::unpremultiply(c.GetGreen(), c.GetAlpha()),
+                       vcl::bitmap::unpremultiply(c.GetBlue(), c.GetAlpha()), 
c.GetAlpha());
+}
+
 BitmapEx BitmapScreenBlendFilter::execute()
 {
     if (maBitmapEx.IsEmpty() || maBitmapEx2.IsEmpty())
@@ -63,14 +77,15 @@ BitmapEx BitmapScreenBlendFilter::execute()
                 Scanline pScanAlpha = pAlphaWriteAccess->GetScanline(y);
                 for (tools::Long x(0); x < nWidth; ++x)
                 {
-                    BitmapColor i1 = maBitmapEx.GetPixelColor(x, y);
-                    BitmapColor i2 = maBitmapEx2.GetPixelColor(x, y);
+                    BitmapColor i1 = premultiply(maBitmapEx.GetPixelColor(x, 
y));
+                    BitmapColor i2 = premultiply(maBitmapEx2.GetPixelColor(x, 
y));
                     sal_uInt8 r(lcl_calculate(i1.GetRed(), i2.GetRed()));
                     sal_uInt8 g(lcl_calculate(i1.GetGreen(), i2.GetGreen()));
                     sal_uInt8 b(lcl_calculate(i1.GetBlue(), i2.GetBlue()));
                     sal_uInt8 a(lcl_calculate(i1.GetAlpha(), i2.GetAlpha()));
 
-                    pWriteAccess->SetPixelOnData(pScanline, x, BitmapColor(r, 
g, b));
+                    pWriteAccess->SetPixelOnData(
+                        pScanline, x, unpremultiply(BitmapColor(ColorAlpha, r, 
g, b, a)));
                     pAlphaWriteAccess->SetPixelOnData(pScanAlpha, x, 
BitmapColor(a));
                 }
             }

Reply via email to