diff options
author | Regina Henschel <rb.henschel@t-online.de> | 2020-07-14 22:52:56 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2020-08-07 13:44:19 +0200 |
commit | 855420811e13d620dd1d0f016ac4f7da9535954c (patch) | |
tree | 789283dfffe457873303c651d8c1134f9b47df5e | |
parent | ad4f819be0502bdf30ab4644a91f53ff224d16f8 (diff) |
tdf#128345 pptx export: add transparence gradient in solid fill
In case of solid color fill a transparence gradient was not saved.
OOXML has no separate element for gradient transparency but has
transparency in color gradient stop elements. The patch detects
a transparence gradient, combines it with the fill color and exports
it as gradFill element.
The import was already correct, besides a wrong start or end value
in case of a symmetric gradient, which becomes AXIAL in LibreOffice.
(cherry picked from commit d187f22b7ff73954e1da39fb954c64bc315298cb)
Conflicts:
sd/qa/unit/export-tests-ooxml1.cxx
Change-Id: I4243656821629f90125d0408a38165a8a29e6e24
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100282
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
-rw-r--r-- | oox/source/drawingml/fillproperties.cxx | 6 | ||||
-rw-r--r-- | oox/source/export/drawingml.cxx | 106 | ||||
-rw-r--r-- | sd/qa/unit/data/odp/tdf128345_FullTransparentGradient.odp | bin | 0 -> 11244 bytes | |||
-rw-r--r-- | sd/qa/unit/data/odp/tdf128345_GradientAxial.odp | bin | 0 -> 12561 bytes | |||
-rw-r--r-- | sd/qa/unit/data/odp/tdf128345_GradientLinear.odp | bin | 0 -> 13384 bytes | |||
-rw-r--r-- | sd/qa/unit/data/odp/tdf128345_GradientRadial.odp | bin | 0 -> 14774 bytes | |||
-rw-r--r-- | sd/qa/unit/export-tests-ooxml1.cxx | 80 |
7 files changed, 155 insertions, 37 deletions
diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx index 963c4009becf..f203e9e2823e 100644 --- a/oox/source/drawingml/fillproperties.cxx +++ b/oox/source/drawingml/fillproperties.cxx @@ -537,10 +537,8 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, aGradient.StartColor = sal_Int32(aStartColor.getColor( rGraphicHelper, nPhClr )); aGradient.EndColor = sal_Int32(aEndColor.getColor( rGraphicHelper, nPhClr )); - if( aStartColor.hasTransparency() ) - nStartTrans = aStartColor.getTransparency()*255/100; - if( aEndColor.hasTransparency() ) - nEndTrans = aEndColor.getTransparency()*255/100; + nStartTrans = aStartColor.hasTransparency() ? aStartColor.getTransparency()*255/100 : 0; + nEndTrans = aEndColor.hasTransparency() ? aEndColor.getTransparency()*255/100 : 0; aGradient.Border = rtl::math::round(100*nBorder); } diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 8a49546c94bd..14910f759598 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -397,8 +397,38 @@ void DrawingML::WriteSolidFill( const Reference< XPropertySet >& rXPropSet ) nAlpha = (MAX_PERCENT - ( PER_PERCENT * nTransparency ) ); } + // OOXML has no separate transparence gradient but uses transparency in the gradient stops. + // So we merge transparency and color and use gradient fill in such case. + awt::Gradient aTransparenceGradient; + bool bNeedGradientFill(false); + if (GetProperty(rXPropSet, "FillTransparenceGradient")) + { + mAny >>= aTransparenceGradient; + if (aTransparenceGradient.StartColor != aTransparenceGradient.EndColor) + bNeedGradientFill = true; + else if (aTransparenceGradient.StartColor != 0) + nAlpha = GetAlphaFromTransparenceGradient(aTransparenceGradient, true); + } + // write XML - if ( nFillColor != nOriginalColor ) + if (bNeedGradientFill) + { + awt::Gradient aPseudoColorGradient; + aPseudoColorGradient.XOffset = aTransparenceGradient.XOffset; + aPseudoColorGradient.YOffset = aTransparenceGradient.YOffset; + aPseudoColorGradient.StartIntensity = 100; + aPseudoColorGradient.EndIntensity = 100; + aPseudoColorGradient.Angle = aTransparenceGradient.Angle; + aPseudoColorGradient.Border = aTransparenceGradient.Border; + aPseudoColorGradient.Style = aTransparenceGradient.Style; + aPseudoColorGradient.StartColor = nFillColor; + aPseudoColorGradient.EndColor = nFillColor; + aPseudoColorGradient.StepCount = aTransparenceGradient.StepCount; + mpFS->startElementNS(XML_a, XML_gradFill, XML_rotWithShape, "0"); + WriteGradientFill(aPseudoColorGradient, aTransparenceGradient); + mpFS->endElementNS( XML_a, XML_gradFill ); + } + else if ( nFillColor != nOriginalColor ) { // the user has set a different color for the shape WriteSolidFill( ::Color(nFillColor & 0xffffff), nAlpha ); @@ -578,25 +608,25 @@ void DrawingML::WriteGrabBagGradientFill( const Sequence< PropertyValue >& aGrad void DrawingML::WriteGradientFill(awt::Gradient rGradient, awt::Gradient rTransparenceGradient, const uno::Reference<beans::XPropertySet>& rXPropSet) { + sal_Int32 nStartAlpha; + sal_Int32 nEndAlpha; + if( rXPropSet.is() && GetProperty(rXPropSet, "FillTransparence") ) + { + sal_Int32 nTransparency = 0; + mAny >>= nTransparency; + nStartAlpha = nEndAlpha = (MAX_PERCENT - (PER_PERCENT * nTransparency)); + } + else + { + nStartAlpha = GetAlphaFromTransparenceGradient(rTransparenceGradient, true); + nEndAlpha = GetAlphaFromTransparenceGradient(rTransparenceGradient, false); + } switch( rGradient.Style ) { default: case awt::GradientStyle_LINEAR: { mpFS->startElementNS(XML_a, XML_gsLst); - sal_Int32 nStartAlpha; - sal_Int32 nEndAlpha; - if( rXPropSet.is() && GetProperty(rXPropSet, "FillTransparence") ) - { - sal_Int32 nTransparency = 0; - mAny >>= nTransparency; - nStartAlpha = nEndAlpha = (MAX_PERCENT - (PER_PERCENT * nTransparency)); - } - else - { - nStartAlpha = GetAlphaFromTransparenceGradient(rTransparenceGradient, true); - nEndAlpha = GetAlphaFromTransparenceGradient(rTransparenceGradient, false); - } WriteGradientStop(rGradient.Border, ColorWithIntensity(rGradient.StartColor, rGradient.StartIntensity), nStartAlpha); WriteGradientStop(100, ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity), @@ -611,23 +641,22 @@ void DrawingML::WriteGradientFill(awt::Gradient rGradient, awt::Gradient rTransp case awt::GradientStyle_AXIAL: { mpFS->startElementNS(XML_a, XML_gsLst); - sal_Int32 nStartAlpha; - sal_Int32 nEndAlpha; - if (rXPropSet.is() && GetProperty(rXPropSet, "FillTransparence")) - { - sal_Int32 nTransparency = 0; - mAny >>= nTransparency; - nStartAlpha = nEndAlpha = (MAX_PERCENT - (PER_PERCENT * nTransparency)); - } - else - { - nStartAlpha = GetAlphaFromTransparenceGradient(rTransparenceGradient, true); - nEndAlpha = GetAlphaFromTransparenceGradient(rTransparenceGradient, false); - } WriteGradientStop(0, ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity), nEndAlpha); + if (rGradient.Border > 0 && rGradient.Border < 100) + { + WriteGradientStop(rGradient.Border/2, + ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity), + nEndAlpha); + } WriteGradientStop(50, ColorWithIntensity(rGradient.StartColor, rGradient.StartIntensity), nStartAlpha); + if (rGradient.Border > 0 && rGradient.Border < 100) + { + WriteGradientStop(100 - rGradient.Border/2, + ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity), + nEndAlpha); + } WriteGradientStop(100, ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity), nEndAlpha); mpFS->endElementNS(XML_a, XML_gsLst); @@ -643,15 +672,19 @@ void DrawingML::WriteGradientFill(awt::Gradient rGradient, awt::Gradient rTransp case awt::GradientStyle_SQUARE: { mpFS->startElementNS(XML_a, XML_gsLst); - WriteGradientStop(0, ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity)); + WriteGradientStop(0, ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity), + nEndAlpha); if (rGradient.Border > 0 && rGradient.Border < 100) + { // Map border to an additional gradient stop, which has the // same color as the final stop. - WriteGradientStop( - 100 - rGradient.Border, - ColorWithIntensity(rGradient.StartColor, rGradient.StartIntensity)); + WriteGradientStop(100 - rGradient.Border, + ColorWithIntensity(rGradient.StartColor, rGradient.StartIntensity), + nStartAlpha); + } WriteGradientStop(100, - ColorWithIntensity(rGradient.StartColor, rGradient.StartIntensity)); + ColorWithIntensity(rGradient.StartColor, rGradient.StartIntensity), + nStartAlpha); mpFS->endElementNS(XML_a, XML_gsLst); WriteGradientPath(rGradient, mpFS, rGradient.Style == awt::GradientStyle_RADIAL || rGradient.Style == awt::GradientStyle_ELLIPTICAL); @@ -3484,14 +3517,21 @@ void DrawingML::WriteFill( const Reference< XPropertySet >& xPropSet ) FillStyle aFillStyle( FillStyle_NONE ); xPropSet->getPropertyValue( "FillStyle" ) >>= aFillStyle; + // map full transparent background to no fill if ( aFillStyle == FillStyle_SOLID && GetProperty( xPropSet, "FillTransparence" ) ) { - // map full transparent background to no fill sal_Int16 nVal = 0; xPropSet->getPropertyValue( "FillTransparence" ) >>= nVal; if ( nVal == 100 ) aFillStyle = FillStyle_NONE; } + if (aFillStyle == FillStyle_SOLID && GetProperty( xPropSet, "FillTransparenceGradient")) + { + awt::Gradient aTransparenceGradient; + mAny >>= aTransparenceGradient; + if (aTransparenceGradient.StartColor == 0xffffff && aTransparenceGradient.EndColor == 0xffffff) + aFillStyle = FillStyle_NONE; + } switch( aFillStyle ) { diff --git a/sd/qa/unit/data/odp/tdf128345_FullTransparentGradient.odp b/sd/qa/unit/data/odp/tdf128345_FullTransparentGradient.odp Binary files differnew file mode 100644 index 000000000000..904490d4313f --- /dev/null +++ b/sd/qa/unit/data/odp/tdf128345_FullTransparentGradient.odp diff --git a/sd/qa/unit/data/odp/tdf128345_GradientAxial.odp b/sd/qa/unit/data/odp/tdf128345_GradientAxial.odp Binary files differnew file mode 100644 index 000000000000..55b8ec1aac60 --- /dev/null +++ b/sd/qa/unit/data/odp/tdf128345_GradientAxial.odp diff --git a/sd/qa/unit/data/odp/tdf128345_GradientLinear.odp b/sd/qa/unit/data/odp/tdf128345_GradientLinear.odp Binary files differnew file mode 100644 index 000000000000..1eadfa11f08b --- /dev/null +++ b/sd/qa/unit/data/odp/tdf128345_GradientLinear.odp diff --git a/sd/qa/unit/data/odp/tdf128345_GradientRadial.odp b/sd/qa/unit/data/odp/tdf128345_GradientRadial.odp Binary files differnew file mode 100644 index 000000000000..634d1dc1bd5f --- /dev/null +++ b/sd/qa/unit/data/odp/tdf128345_GradientRadial.odp diff --git a/sd/qa/unit/export-tests-ooxml1.cxx b/sd/qa/unit/export-tests-ooxml1.cxx index f7cec3010dc7..74620cba8517 100644 --- a/sd/qa/unit/export-tests-ooxml1.cxx +++ b/sd/qa/unit/export-tests-ooxml1.cxx @@ -91,6 +91,10 @@ public: void testRoundtripPrstDash(); void testDashOnHairline(); void testCustomshapeBitmapfillSrcrect(); + void testTdf128345FullTransparentGradient(); + void testTdf128345GradientLinear(); + void testTdf128345GradientRadial(); + void testTdf128345GradientAxial(); CPPUNIT_TEST_SUITE(SdOOXMLExportTest1); @@ -131,6 +135,10 @@ public: CPPUNIT_TEST(testRoundtripPrstDash); CPPUNIT_TEST(testDashOnHairline); CPPUNIT_TEST(testCustomshapeBitmapfillSrcrect); + CPPUNIT_TEST(testTdf128345FullTransparentGradient); + CPPUNIT_TEST(testTdf128345GradientLinear); + CPPUNIT_TEST(testTdf128345GradientRadial); + CPPUNIT_TEST(testTdf128345GradientAxial); CPPUNIT_TEST_SUITE_END(); @@ -1095,6 +1103,78 @@ void SdOOXMLExportTest1::testCustomshapeBitmapfillSrcrect() CPPUNIT_ASSERT_EQUAL(4.0, fRightPercent); } +void SdOOXMLExportTest1::testTdf128345FullTransparentGradient() +{ + ::sd::DrawDocShellRef xDocShRef + = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/tdf128345_FullTransparentGradient.odp"), ODP); + utl::TempFile tempFile; + xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile); + xDocShRef->DoClose(); + + // Make sure the shape has no fill. Without the patch, fill was solid red. + xmlDocUniquePtr pXmlDoc = parseExport(tempFile, "ppt/slides/slide1.xml"); + const OString sPathStart("//p:sld/p:cSld/p:spTree/p:sp/p:spPr"); + assertXPath(pXmlDoc, sPathStart + "/a:noFill"); +} + +void SdOOXMLExportTest1::testTdf128345GradientLinear() +{ + ::sd::DrawDocShellRef xDocShRef + = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/tdf128345_GradientLinear.odp"), ODP); + utl::TempFile tempFile; + xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile); + xDocShRef->DoClose(); + + // Make sure the shape has a lin fill. Without the patch, fill was solid red. + xmlDocUniquePtr pXmlDoc = parseExport(tempFile, "ppt/slides/slide1.xml"); + const OString sPathStart("//p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:gradFill"); + assertXPath(pXmlDoc, sPathStart + "/a:lin", "ang", "3600000"); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs",2); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]", "pos", "25000"); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]/a:srgbClr", "val", "ff0000"); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]/a:srgbClr/a:alpha", "val", "20000"); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]", "pos", "100000"); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr", "val", "ff0000"); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr/a:alpha", "val", "80000"); +} + +void SdOOXMLExportTest1::testTdf128345GradientRadial() +{ + ::sd::DrawDocShellRef xDocShRef + = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/tdf128345_GradientRadial.odp"), ODP); + utl::TempFile tempFile; + xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile); + xDocShRef->DoClose(); + + // Make sure the shape has transparency. In OOXML alpha means 'opacity' with default + // 100000 for full opak, so only the full transparency with val 0 should be written. + xmlDocUniquePtr pXmlDoc = parseExport(tempFile, "ppt/slides/slide1.xml"); + const OString sPathStart("//p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:gradFill"); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs",2); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]/a:srgbClr", "val", "ff0000"); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]/a:srgbClr/a:alpha", 0); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr", "val", "ffffff"); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr/a:alpha", "val", "0"); +} + +void SdOOXMLExportTest1::testTdf128345GradientAxial() +{ + // Without the patch, symmtetric linear gradient with full transparence outside and + // full opak in the middle were imported as full transparent. + ::sd::DrawDocShellRef xDocShRef + = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/tdf128345_GradientAxial.odp"), ODP); + xDocShRef = saveAndReload(xDocShRef.get(), PPTX); + uno::Reference<beans::XPropertySet> xShapePropSet(getShapeFromPage(0, 0, xDocShRef)); + + awt::Gradient aTransparenceGradient; + xShapePropSet->getPropertyValue("FillTransparenceGradient") >>= aTransparenceGradient; + CPPUNIT_ASSERT_EQUAL(sal_Int32(0x000000), aTransparenceGradient.StartColor); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xffffff), aTransparenceGradient.EndColor); + CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_AXIAL, aTransparenceGradient.Style); + + xDocShRef->DoClose(); +} + CPPUNIT_TEST_SUITE_REGISTRATION(SdOOXMLExportTest1); CPPUNIT_PLUGIN_IMPLEMENT(); |