diff options
author | Xisco Fauli <xiscofauli@libreoffice.org> | 2024-04-05 10:08:36 +0200 |
---|---|---|
committer | Xisco Fauli <xiscofauli@libreoffice.org> | 2024-04-16 09:36:37 +0200 |
commit | cb4698626f17e005c820a7138c63a03c21120ecd (patch) | |
tree | ad153f60368e60065226d8d72b8d17aeb7e95772 /vcl/source | |
parent | ded4d570fde21e55091c9c8c364114e67aa0cdcf (diff) |
tdf#48062: Add support for arithmetic in feComposite
Took https://github.com/w3c/csswg-drafts/issues/3831
as a reference
Change-Id: I42039c481ec114c3faeae51526a5f29b86960146
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165828
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Diffstat (limited to 'vcl/source')
-rw-r--r-- | vcl/source/bitmap/BitmapArithmeticBlendFilter.cxx | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/vcl/source/bitmap/BitmapArithmeticBlendFilter.cxx b/vcl/source/bitmap/BitmapArithmeticBlendFilter.cxx new file mode 100644 index 000000000000..da52a436b6f6 --- /dev/null +++ b/vcl/source/bitmap/BitmapArithmeticBlendFilter.cxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include <comphelper/diagnose_ex.hxx> +#include <vcl/BitmapArithmeticBlendFilter.hxx> +#include <vcl/BitmapWriteAccess.hxx> +#include <vcl/BitmapTools.hxx> + +BitmapArithmeticBlendFilter::BitmapArithmeticBlendFilter(BitmapEx const& rBitmapEx, + BitmapEx const& rBitmapEx2) + : maBitmapEx(rBitmapEx) + , maBitmapEx2(rBitmapEx2) +{ +} + +BitmapArithmeticBlendFilter::~BitmapArithmeticBlendFilter() {} + +static sal_uInt8 lcl_calculate(sal_uInt8 aColor, sal_uInt8 aColor2, double aK1, double aK2, + double aK3, double aK4) +{ + const double i1 = aColor / 255.0; + const double i2 = aColor2 / 255.0; + const double result = aK1 * i1 * i2 + aK2 * i1 + aK3 * i2 + aK4; + + return std::clamp(result, 0.0, 1.0) * 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 BitmapArithmeticBlendFilter::execute(double aK1, double aK2, double aK3, double aK4) +{ + if (maBitmapEx.IsEmpty() || maBitmapEx2.IsEmpty()) + return BitmapEx(); + + Size aSize = maBitmapEx.GetBitmap().GetSizePixel(); + Size aSize2 = maBitmapEx2.GetBitmap().GetSizePixel(); + sal_Int32 nHeight = std::min(aSize.getHeight(), aSize2.getHeight()); + sal_Int32 nWidth = std::min(aSize.getWidth(), aSize2.getWidth()); + + BitmapScopedReadAccess pReadAccess(maBitmapEx.GetBitmap()); + Bitmap aDstBitmap(Size(nWidth, nHeight), maBitmapEx.GetBitmap().getPixelFormat(), + &pReadAccess->GetPalette()); + Bitmap aDstAlpha(AlphaMask(Size(nWidth, nHeight)).GetBitmap()); + + { + // just to be on the safe side: let the + // ScopedAccessors get destructed before + // copy-constructing the resulting bitmap. This will + // rule out the possibility that cached accessor data + // is not yet written back. + + BitmapScopedWriteAccess pWriteAccess(aDstBitmap); + BitmapScopedWriteAccess pAlphaWriteAccess(aDstAlpha); + + if (pWriteAccess.get() != nullptr && pAlphaWriteAccess.get() != nullptr) + { + for (tools::Long y(0); y < nHeight; ++y) + { + Scanline pScanline = pWriteAccess->GetScanline(y); + Scanline pScanAlpha = pAlphaWriteAccess->GetScanline(y); + for (tools::Long x(0); x < nWidth; ++x) + { + BitmapColor i1 = premultiply(maBitmapEx.GetPixelColor(x, y)); + BitmapColor i2 = premultiply(maBitmapEx2.GetPixelColor(x, y)); + sal_uInt8 r(lcl_calculate(i1.GetRed(), i2.GetRed(), aK1, aK2, aK3, aK4)); + sal_uInt8 g(lcl_calculate(i1.GetGreen(), i2.GetGreen(), aK1, aK2, aK3, aK4)); + sal_uInt8 b(lcl_calculate(i1.GetBlue(), i2.GetBlue(), aK1, aK2, aK3, aK4)); + sal_uInt8 a(lcl_calculate(i1.GetAlpha(), i2.GetAlpha(), aK1, aK2, aK3, aK4)); + + pWriteAccess->SetPixelOnData( + pScanline, x, unpremultiply(BitmapColor(ColorAlpha, r, g, b, a))); + pAlphaWriteAccess->SetPixelOnData(pScanAlpha, x, BitmapColor(a)); + } + } + } + else + { + // TODO(E2): Error handling! + ENSURE_OR_THROW(false, "BitmapScreenBlendFilter: could not access bitmap"); + } + } + + return BitmapEx(aDstBitmap, AlphaMask(aDstAlpha)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |