oox/inc/drawingml/fillproperties.hxx | 1 oox/source/drawingml/fillproperties.cxx | 40 +++++++++ oox/source/drawingml/misccontexts.cxx | 4 sd/qa/unit/data/pptx/tdf89928-blackWhiteEffectThreshold.pptx |binary sd/qa/unit/import-tests2.cxx | 45 +++++++++++ 5 files changed, 90 insertions(+)
New commits: commit 9ecc76988ec46ba0d6c5cb72ac88f65da48867b1 Author: Sarper Akdemir <sarper.akde...@collabora.com> AuthorDate: Mon Sep 19 09:56:57 2022 +0300 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Sep 20 08:29:29 2022 +0200 tdf#89928 pptx import: implement import of BiLevel threshold Implement import BiLevel effect's threshold value. If threshold isn't exactly 50%, we can't map it to the doc model. Therefore as a workaround apply the BiLevel (Black/White) effect with specified threshold directly to the graphic. Change-Id: Ib24d149d74b103d926560708c68bb937b02c4cfe Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140136 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/oox/inc/drawingml/fillproperties.hxx b/oox/inc/drawingml/fillproperties.hxx index 9cef3c98f2b1..828c858e12f2 100644 --- a/oox/inc/drawingml/fillproperties.hxx +++ b/oox/inc/drawingml/fillproperties.hxx @@ -113,6 +113,7 @@ struct BlipFillProperties std::optional< sal_Int32 > moColorEffect; /// XML token for a color effect. std::optional< sal_Int32 > moBrightness; /// Brightness in the range [-100000,100000]. std::optional< sal_Int32 > moContrast; /// Contrast in the range [-100000,100000]. + std::optional< sal_Int32 > moBiLevelThreshold; /// Bi-Level (Black/White) effect threshold (1/1000 percent) Color maColorChangeFrom; /// Start color of color transformation. Color maColorChangeTo; /// Destination color of color transformation. Color maDuotoneColors[2]; /// Duotone Colors diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx index 1ef7579a7725..7933a79f5dba 100644 --- a/oox/source/drawingml/fillproperties.cxx +++ b/oox/source/drawingml/fillproperties.cxx @@ -24,6 +24,8 @@ #include <comphelper/propertyvalue.hxx> #include <drawingml/graphicproperties.hxx> #include <vcl/graph.hxx> +#include <vcl/BitmapFilter.hxx> +#include <vcl/BitmapMonochromeFilter.hxx> #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/awt/Gradient.hpp> @@ -185,6 +187,32 @@ Reference< XGraphic > lclGreysScaleGraphic(uno::Reference<graphic::XGraphic> con return aReturnGraphic.GetXGraphic(); } +/// Applies the graphic Black&White (Monochrome) effect with the imported threshold +Reference<XGraphic> lclApplyBlackWhiteEffect(const BlipFillProperties& aBlipProps, + const uno::Reference<graphic::XGraphic>& xGraphic) +{ + const auto& oBiLevelThreshold = aBlipProps.moBiLevelThreshold; + if (oBiLevelThreshold.has_value()) + { + sal_uInt8 nThreshold + = static_cast<sal_uInt8>(oBiLevelThreshold.value() * 255 / MAX_PERCENT); + + ::Graphic aGraphic(xGraphic); + ::Graphic aReturnGraphic; + + BitmapEx aBitmapEx(aGraphic.GetBitmapEx()); + AlphaMask aMask(aBitmapEx.GetAlpha()); + + BitmapEx aTmpBmpEx(aBitmapEx.GetBitmap()); + BitmapFilter::Filter(aTmpBmpEx, BitmapMonochromeFilter{ nThreshold }); + + aReturnGraphic = ::Graphic(BitmapEx(aTmpBmpEx.GetBitmap(), aMask)); + aReturnGraphic.setOriginURL(aGraphic.getOriginURL()); + return aReturnGraphic.GetXGraphic(); + } + return xGraphic; +} + Reference< XGraphic > lclCheckAndApplyChangeColorTransform(const BlipFillProperties &aBlipProps, uno::Reference<graphic::XGraphic> const & xGraphic, const GraphicHelper& rGraphicHelper, const ::Color nPhClr) { @@ -350,6 +378,7 @@ void BlipFillProperties::assignUsed( const BlipFillProperties& rSourceProps ) assignIfUsed( moColorEffect, rSourceProps.moColorEffect ); assignIfUsed( moBrightness, rSourceProps.moBrightness ); assignIfUsed( moContrast, rSourceProps.moContrast ); + assignIfUsed( moBiLevelThreshold, rSourceProps.moBiLevelThreshold ); maColorChangeFrom.assignIfUsed( rSourceProps.maColorChangeFrom ); maColorChangeTo.assignIfUsed( rSourceProps.maColorChangeTo ); maDuotoneColors[0].assignIfUsed( rSourceProps.maDuotoneColors[0] ); @@ -907,6 +936,17 @@ void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const GraphicHelpe uno::Reference<graphic::XGraphic> xGraphic = lclCheckAndApplyChangeColorTransform(maBlipProps, maBlipProps.mxFillGraphic, rGraphicHelper, API_RGB_TRANSPARENT); xGraphic = lclCheckAndApplyDuotoneTransform(maBlipProps, xGraphic, rGraphicHelper, API_RGB_TRANSPARENT); + if( eColorMode == ColorMode_MONO ) + { + // ColorMode_MONO is the same with MSO's biLevel with 50000 (50%) threshold, + // when threshold isn't 50000 bake the effect instead. + if( maBlipProps.moBiLevelThreshold != 50000 ) + { + xGraphic = lclApplyBlackWhiteEffect(maBlipProps, xGraphic); + eColorMode = ColorMode_STANDARD; + } + } + if (eColorMode == ColorMode_STANDARD && nBrightness == 70 && nContrast == -70) { // map MSO 'washout' to our Watermark colormode diff --git a/oox/source/drawingml/misccontexts.cxx b/oox/source/drawingml/misccontexts.cxx index ceeeca3d5c62..e7ec679ad318 100644 --- a/oox/source/drawingml/misccontexts.cxx +++ b/oox/source/drawingml/misccontexts.cxx @@ -172,6 +172,10 @@ ContextHandlerRef BlipContext::onCreateContext( switch( nElement ) { case A_TOKEN( biLevel ): + mrBlipProps.moBiLevelThreshold = rAttribs.getInteger( XML_thresh ); + mrBlipProps.moColorEffect = getBaseToken(nElement); + break; + case A_TOKEN( grayscl ): mrBlipProps.moColorEffect = getBaseToken( nElement ); break; diff --git a/sd/qa/unit/data/pptx/tdf89928-blackWhiteEffectThreshold.pptx b/sd/qa/unit/data/pptx/tdf89928-blackWhiteEffectThreshold.pptx new file mode 100644 index 000000000000..90edf8ea0afb Binary files /dev/null and b/sd/qa/unit/data/pptx/tdf89928-blackWhiteEffectThreshold.pptx differ diff --git a/sd/qa/unit/import-tests2.cxx b/sd/qa/unit/import-tests2.cxx index 17c793d08ab8..bf4939c39365 100644 --- a/sd/qa/unit/import-tests2.cxx +++ b/sd/qa/unit/import-tests2.cxx @@ -141,6 +141,7 @@ public: void testDefaultTabStop(); void testCropToZero(); void testTdf144092TableHeight(); + void testTdf89928BlackWhiteThreshold(); CPPUNIT_TEST_SUITE(SdImportTest2); @@ -215,6 +216,7 @@ public: CPPUNIT_TEST(testDefaultTabStop); CPPUNIT_TEST(testCropToZero); CPPUNIT_TEST(testTdf144092TableHeight); + CPPUNIT_TEST(testTdf89928BlackWhiteThreshold); CPPUNIT_TEST_SUITE_END(); }; @@ -2121,6 +2123,49 @@ void SdImportTest2::testTdf144092TableHeight() xDocShRef->DoClose(); } +void SdImportTest2::testTdf89928BlackWhiteThreshold() +{ + // A slide with two graphics, one with color HSV{0,0,74%} and one with HSV{0,0,76%} + // where both have an applied 75% Black/White Color Effect. + sd::DrawDocShellRef xDocShRef + = loadURL(m_directories.getURLFromSrc( + u"sd/qa/unit/data/pptx/tdf89928-blackWhiteEffectThreshold.pptx"), + PPTX); + + // First graphic should appear black + { + uno::Reference<beans::XPropertySet> xShape(getShapeFromPage(0, 0, xDocShRef), + uno::UNO_SET_THROW); + uno::Reference<graphic::XGraphic> xGraphic; + xShape->getPropertyValue("Graphic") >>= xGraphic; + CPPUNIT_ASSERT(xGraphic.is()); + + Graphic aGraphic(xGraphic); + BitmapEx aBitmap(aGraphic.GetBitmapEx()); + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: Color: R:0 G:0 B:0 A:0 + // - Actual : Color: R:189 G:189 B:189 A:0 + CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0x000000), aBitmap.GetPixelColor(0, 0)); + } + + // Second graphic should appear white + { + uno::Reference<beans::XPropertySet> xShape(getShapeFromPage(1, 0, xDocShRef), + uno::UNO_SET_THROW); + uno::Reference<graphic::XGraphic> xGraphic; + xShape->getPropertyValue("Graphic") >>= xGraphic; + CPPUNIT_ASSERT(xGraphic.is()); + + Graphic aGraphic(xGraphic); + BitmapEx aBitmap(aGraphic.GetBitmapEx()); + + CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0xFFFFFF), aBitmap.GetPixelColor(0, 0)); + } + + xDocShRef->DoClose(); +} + CPPUNIT_TEST_SUITE_REGISTRATION(SdImportTest2); CPPUNIT_PLUGIN_IMPLEMENT();