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)); } }