include/oox/export/drawingml.hxx | 4 + oox/inc/drawingml/fillproperties.hxx | 2 oox/source/drawingml/fillproperties.cxx | 89 ++++++++++++++++++++++++++------ oox/source/drawingml/shape.cxx | 5 + oox/source/export/drawingml.cxx | 78 ++++++++++++++++++++++++++++ oox/source/ppt/slidepersist.cxx | 7 ++ sd/qa/unit/data/odp/tdf153105.odp |binary sd/qa/unit/data/pptx/tdf153466.pptx |binary sd/qa/unit/export-tests-ooxml3.cxx | 18 ++++++ sd/qa/unit/import-tests.cxx | 22 +++++++ 10 files changed, 209 insertions(+), 16 deletions(-)
New commits: commit a1acb19ec4c239a24b23ec9c03ad52465895606d Author: Tibor Nagy <nagy.tib...@nisz.hu> AuthorDate: Wed Mar 8 16:26:10 2023 +0100 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Tue Jun 27 16:00:35 2023 +0200 tdf#153466 PPTX import: fix "Custom position/size" background image Custom sized background with the value "tile" was imported as "stretched", losing the preset size. Restore also the exported preset positions, and map the other values to the preset positions supported by OpenDocument/Impress. Follow-up to commit 11451781d4c562f506a3aae3732e35b92387b4db (tdf#153105 PPTX export: fix "Custom position/size" background image) Change-Id: Ibf9b487ecd31b3ad7b06bda668c51e6b7a98c4af Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148482 Tested-by: László Németh <nem...@numbertext.org> Reviewed-by: László Németh <nem...@numbertext.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153580 Reviewed-by: Jaume Pujantell <jaume.pujant...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/oox/inc/drawingml/fillproperties.hxx b/oox/inc/drawingml/fillproperties.hxx index 828c858e12f2..3323907fcad8 100644 --- a/oox/inc/drawingml/fillproperties.hxx +++ b/oox/inc/drawingml/fillproperties.hxx @@ -24,6 +24,7 @@ #include <com/sun/star/beans/PropertyValue.hpp> #include <com/sun/star/geometry/IntegerRectangle2D.hpp> +#include <com/sun/star/awt/Size.hpp> #include <com/sun/star/uno/Any.hxx> #include <com/sun/star/uno/Reference.hxx> #include <oox/drawingml/color.hxx> @@ -147,6 +148,7 @@ struct FillProperties const GraphicHelper& rGraphicHelper, sal_Int32 nShapeRotation = 0, ::Color nPhClr = API_RGB_TRANSPARENT, + const css::awt::Size& rSize = {}, sal_Int16 nPhClrTheme = -1, bool bFlipH = false, bool bFlipV = false, diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx index 0a2e53928076..becc632fd923 100644 --- a/oox/source/drawingml/fillproperties.cxx +++ b/oox/source/drawingml/fillproperties.cxx @@ -400,9 +400,10 @@ Color FillProperties::getBestSolidColor() const return aSolidColor; } -void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, - const GraphicHelper& rGraphicHelper, sal_Int32 nShapeRotation, ::Color nPhClr, sal_Int16 nPhClrTheme, - bool bFlipH, bool bFlipV, bool bIsCustomShape) const +void FillProperties::pushToPropMap(ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper, + sal_Int32 nShapeRotation, ::Color nPhClr, + const css::awt::Size& rSize, sal_Int16 nPhClrTheme, bool bFlipH, + bool bFlipV, bool bIsCustomShape) const { if( !moFillType.has_value() ) return; @@ -588,7 +589,6 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, { // bitmap mode (single, repeat, stretch) BitmapMode eBitmapMode = lclGetBitmapMode( maBlipProps.moBitmapMode.value_or( XML_TOKEN_INVALID ) ); - rPropMap.setProperty( ShapeProperty::FillBitmapMode, eBitmapMode ); // additional settings for repeated bitmap if( eBitmapMode == BitmapMode_REPEAT ) @@ -636,21 +636,82 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, // Negative GraphicCrop values means "crop" here. bool bNeedCrop = aGraphCrop.Left <= 0 && aGraphCrop.Right <= 0 && aGraphCrop.Top <= 0 && aGraphCrop.Bottom <= 0; - if(bIsCustomShape && bHasCropValues && bNeedCrop) + if (bHasCropValues) { - // Physically crop the image - // In this case, don't set the PROP_GraphicCrop because that - // would lead to applying the crop twice after roundtrip - xGraphic = lclCropGraphic(xGraphic, CropQuotientsFromFillRect(aFillRect)); - if (rPropMap.supportsProperty(ShapeProperty::FillBitmapName)) - rPropMap.setProperty(ShapeProperty::FillBitmapName, xGraphic); + if (bIsCustomShape && bNeedCrop) + { + // Physically crop the image + // In this case, don't set the PROP_GraphicCrop because that + // would lead to applying the crop twice after roundtrip + xGraphic = lclCropGraphic(xGraphic, CropQuotientsFromFillRect(aFillRect)); + if (rPropMap.supportsProperty(ShapeProperty::FillBitmapName)) + rPropMap.setProperty(ShapeProperty::FillBitmapName, xGraphic); + else + rPropMap.setProperty(ShapeProperty::FillBitmap, xGraphic); + } + else if ((aFillRect.X1 != 0 && aFillRect.X2 != 0 + && aFillRect.X1 != aFillRect.X2) + || (aFillRect.Y1 != 0 && aFillRect.Y2 != 0 + && aFillRect.Y1 != aFillRect.Y2)) + { + rPropMap.setProperty(PROP_GraphicCrop, aGraphCrop); + } else - rPropMap.setProperty(ShapeProperty::FillBitmap, xGraphic); + { + double nL = aFillRect.X1 / static_cast<double>(MAX_PERCENT); + double nT = aFillRect.Y1 / static_cast<double>(MAX_PERCENT); + double nR = aFillRect.X2 / static_cast<double>(MAX_PERCENT); + double nB = aFillRect.Y2 / static_cast<double>(MAX_PERCENT); + + sal_Int32 nSizeX; + if (nL || nR) + nSizeX = rSize.Width * (1 - (nL + nR)); + else + nSizeX = rSize.Width; + rPropMap.setProperty(ShapeProperty::FillBitmapSizeX, nSizeX); + + sal_Int32 nSizeY; + if (nT || nB) + nSizeY = rSize.Height * (1 - (nT + nB)); + else + nSizeY = rSize.Height; + rPropMap.setProperty(ShapeProperty::FillBitmapSizeY, nSizeY); + + RectanglePoint eRectPoint; + if (!aFillRect.X1 && aFillRect.X2) + { + if (!aFillRect.Y1 && aFillRect.Y2) + eRectPoint = lclGetRectanglePoint(XML_tl); + else if (aFillRect.Y1 && !aFillRect.Y2) + eRectPoint = lclGetRectanglePoint(XML_bl); + else + eRectPoint = lclGetRectanglePoint(XML_l); + } + else if (aFillRect.X1 && !aFillRect.X2) + { + if (!aFillRect.Y1 && aFillRect.Y2) + eRectPoint = lclGetRectanglePoint(XML_tr); + else if (aFillRect.Y1 && !aFillRect.Y2) + eRectPoint = lclGetRectanglePoint(XML_br); + else + eRectPoint = lclGetRectanglePoint(XML_r); + } + else + { + if (!aFillRect.Y1 && aFillRect.Y2) + eRectPoint = lclGetRectanglePoint(XML_t); + else if (aFillRect.Y1 && !aFillRect.Y2) + eRectPoint = lclGetRectanglePoint(XML_b); + else + eRectPoint = lclGetRectanglePoint(XML_ctr); + } + rPropMap.setProperty(ShapeProperty::FillBitmapRectanglePoint, eRectPoint); + eBitmapMode = BitmapMode_NO_REPEAT; + } } - else - rPropMap.setProperty(PROP_GraphicCrop, aGraphCrop); } } + rPropMap.setProperty(ShapeProperty::FillBitmapMode, eBitmapMode); } if (maBlipProps.moAlphaModFix.has_value()) diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index 48acc4efa945..497fd57db922 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -1433,7 +1433,10 @@ Reference< XShape > const & Shape::createAndInsert( if (getFillProperties().moFillType.has_value() && getFillProperties().moFillType.value() == XML_grpFill) getFillProperties().assignUsed(aFillProperties); if(!bIsCroppedGraphic) - aFillProperties.pushToPropMap( aShapeProps, rGraphicHelper, mnRotation, nFillPhClr, nFillPhClrTheme, mbFlipH, mbFlipV, bIsCustomShape ); + aFillProperties.pushToPropMap(aShapeProps, rGraphicHelper, mnRotation, nFillPhClr, + css::awt::Size(aShapeRectHmm.Width, aShapeRectHmm.Height), + nFillPhClrTheme, mbFlipH, mbFlipV, bIsCustomShape); + LineProperties aLineProperties = getActualLineProperties(pTheme); aLineProperties.pushToPropMap( aShapeProps, rGraphicHelper, nLinePhClr, nLinePhClrTheme); EffectProperties aEffectProperties = getActualEffectProperties(pTheme); diff --git a/oox/source/ppt/slidepersist.cxx b/oox/source/ppt/slidepersist.cxx index 349262fc6b8f..0f7479e8ede9 100644 --- a/oox/source/ppt/slidepersist.cxx +++ b/oox/source/ppt/slidepersist.cxx @@ -193,11 +193,16 @@ void SlidePersist::createBackground( const XmlFilterBase& rFilterBase ) ::Color nPhClr = maBackgroundColor.isUsed() ? maBackgroundColor.getColor( rFilterBase.getGraphicHelper() ) : API_RGB_TRANSPARENT; + css::awt::Size aSize; + Reference< css::beans::XPropertySet > xSet(mxPage, UNO_QUERY); + xSet->getPropertyValue("Width") >>= aSize.Width; + xSet->getPropertyValue("Height") >>= aSize.Height; + oox::drawingml::ShapePropertyIds aPropertyIds = oox::drawingml::ShapePropertyInfo::DEFAULT.mrPropertyIds; aPropertyIds[oox::drawingml::ShapeProperty::FillGradient] = PROP_FillGradientName; oox::drawingml::ShapePropertyInfo aPropInfo( aPropertyIds, true, false, true, false, false ); oox::drawingml::ShapePropertyMap aPropMap( rFilterBase.getModelObjectHelper(), aPropInfo ); - mpBackgroundPropertiesPtr->pushToPropMap( aPropMap, rFilterBase.getGraphicHelper(), 0, nPhClr ); + mpBackgroundPropertiesPtr->pushToPropMap( aPropMap, rFilterBase.getGraphicHelper(), 0, nPhClr, aSize); PropertySet( mxPage ).setProperty( PROP_Background, aPropMap.makePropertySet() ); } } diff --git a/sd/qa/unit/data/pptx/tdf153466.pptx b/sd/qa/unit/data/pptx/tdf153466.pptx new file mode 100644 index 000000000000..8900083ba7bf Binary files /dev/null and b/sd/qa/unit/data/pptx/tdf153466.pptx differ diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx index 13353ad00986..706214950411 100644 --- a/sd/qa/unit/import-tests.cxx +++ b/sd/qa/unit/import-tests.cxx @@ -52,6 +52,7 @@ #include <com/sun/star/presentation/XCustomPresentationSupplier.hpp> #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp> #include <com/sun/star/drawing/ConnectorType.hpp> +#include <com/sun/star/drawing/RectanglePoint.hpp> #include <stlpool.hxx> #include <unotools/syslocaleoptions.hxx> @@ -84,6 +85,7 @@ public: void testDocumentLayout(); void testTdf154363(); + void testTdf153466(); void testTdf152434(); void testStandardConnectors(); void testConnectors(); @@ -163,6 +165,7 @@ public: CPPUNIT_TEST(testDocumentLayout); CPPUNIT_TEST(testTdf154363); + CPPUNIT_TEST(testTdf153466); CPPUNIT_TEST(testTdf152434); CPPUNIT_TEST(testStandardConnectors); CPPUNIT_TEST(testConnectors); @@ -383,6 +386,25 @@ void SdImportTest::testTdf154363() } } +void SdImportTest::testTdf153466() +{ + createSdImpressDoc("pptx/tdf153466.pptx"); + + uno::Reference<drawing::XDrawPagesSupplier> xDoc(mxComponent, uno::UNO_QUERY_THROW); + uno::Reference<drawing::XDrawPage> xPage(xDoc->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xPageSet(xPage, uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertySet> xBackground( + xPageSet->getPropertyValue("Background").get<uno::Reference<beans::XPropertySet>>()); + + com::sun::star::drawing::RectanglePoint aRectanglePoint; + xBackground->getPropertyValue("FillBitmapRectanglePoint") >>= aRectanglePoint; + CPPUNIT_ASSERT_EQUAL(drawing::RectanglePoint::RectanglePoint_RIGHT_BOTTOM, aRectanglePoint); + + uno::Reference<beans::XPropertySet> xShape(getShapeFromPage(0, 0), uno::UNO_SET_THROW); + xShape->getPropertyValue("FillBitmapRectanglePoint") >>= aRectanglePoint; + CPPUNIT_ASSERT_EQUAL(drawing::RectanglePoint::RectanglePoint_LEFT_MIDDLE, aRectanglePoint); +} + void SdImportTest::testTdf152434() { createSdImpressDoc("pptx/tdf152434.pptx"); commit d2d3d9e21630a7d063b45943ef5432943640ded2 Author: Tibor Nagy <nagy.tib...@nisz.hu> AuthorDate: Mon Feb 20 16:13:17 2023 +0100 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Tue Jun 27 16:00:25 2023 +0200 tdf#153105 PPTX export: fix "Custom position/size" background image Map size and the 9 preset positions of the ODF background image style "Custom position/size" to the OOXML a:stretch/a:fillRect with the appropriate left/top/right/bottom arguments. Note: it seems, applying a:stretch or a:tile was not mandatory, but missing a:stretch resulted non-editable document in Office 365. Note: the import of the PPTX mapping hasn't been implemented, yet. Follow-up to commit e8335bac5690b6beccb5ca9b36281c89fb2f28f5 "tdf#153107 OOXML export: fix scale of tile of shape background". Change-Id: Ie940ebc2610c5b75126da05678a04ed1552cacb3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147337 Tested-by: László Németh <nem...@numbertext.org> Reviewed-by: László Németh <nem...@numbertext.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153578 Reviewed-by: Jaume Pujantell <jaume.pujant...@collabora.com> Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx index 89fb0cab1128..be0633110c74 100644 --- a/include/oox/export/drawingml.hxx +++ b/include/oox/export/drawingml.hxx @@ -413,6 +413,10 @@ public: css::uno::Reference<css::graphic::XGraphic> const& rxGraphic, css::awt::Size const& rSize); + void WriteXGraphicCustomPosition(css::uno::Reference<css::beans::XPropertySet> const& rXPropSet, + css::uno::Reference<css::graphic::XGraphic> const& rxGraphic, + css::awt::Size const& rSize); + void WriteLinespacing(const css::style::LineSpacing& rLineSpacing, float fFirstCharHeight); OUString WriteXGraphicBlip(css::uno::Reference<css::beans::XPropertySet> const & rXPropSet, diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index f7f67595c025..c0d82d41996b 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -1720,6 +1720,9 @@ void DrawingML::WriteXGraphicBlipMode(uno::Reference<beans::XPropertySet> const case BitmapMode_STRETCH: WriteXGraphicStretch(rXPropSet, rxGraphic); break; + case BitmapMode_NO_REPEAT: + WriteXGraphicCustomPosition(rXPropSet, rxGraphic, rSize); + break; default: break; } @@ -2059,6 +2062,81 @@ void DrawingML::WriteXGraphicTile(uno::Reference<beans::XPropertySet> const& rXP OUString::number(nSizeY), XML_algn, sRectanglePoint); } +void DrawingML::WriteXGraphicCustomPosition(uno::Reference<beans::XPropertySet> const& rXPropSet, + uno::Reference<graphic::XGraphic> const& rxGraphic, + css::awt::Size const& rSize) +{ + Graphic aGraphic(rxGraphic); + Size aOriginalSize(aGraphic.GetPrefSize()); + const MapMode& rMapMode = aGraphic.GetPrefMapMode(); + // if the original size is in pixel, convert it to mm100 + if (rMapMode.GetMapUnit() == MapUnit::MapPixel) + aOriginalSize = Application::GetDefaultDevice()->PixelToLogic(aOriginalSize, + MapMode(MapUnit::Map100thMM)); + double nSizeX = 0; + if (GetProperty(rXPropSet, "FillBitmapSizeX")) + { + mAny >>= nSizeX; + if (nSizeX <= 0) + { + if (nSizeX == 0) + nSizeX = aOriginalSize.Width(); + else + nSizeX /= 100; // percentage + } + } + + double nSizeY = 0; + if (GetProperty(rXPropSet, "FillBitmapSizeY")) + { + mAny >>= nSizeY; + if (nSizeY <= 0) + { + if (nSizeY == 0) + nSizeY = aOriginalSize.Height(); + else + nSizeY /= 100; // percentage + } + } + + if (nSizeX < 0 && nSizeY < 0 && rSize.Width != 0 && rSize.Height != 0) + { + nSizeX = rSize.Width * std::abs(nSizeX); + nSizeY = rSize.Height * std::abs(nSizeY); + } + + sal_Int32 nL = 0, nT = 0, nR = 0, nB = 0; + if (GetProperty(rXPropSet, "FillBitmapRectanglePoint")) + { + sal_Int32 nWidth = (1 - (nSizeX / rSize.Width)) * 100000; + sal_Int32 nHeight = (1 - (nSizeY / rSize.Height)) * 100000; + + switch (*o3tl::doAccess<RectanglePoint>(mAny)) + { + case RectanglePoint_LEFT_TOP: nR = nWidth; nB = nHeight; break; + case RectanglePoint_RIGHT_TOP: nL = nWidth; nB = nHeight; break; + case RectanglePoint_LEFT_BOTTOM: nR = nWidth; nT = nHeight; break; + case RectanglePoint_RIGHT_BOTTOM: nL = nWidth; nT = nHeight; break; + case RectanglePoint_LEFT_MIDDLE: nR = nWidth; nT = nB = nHeight / 2; break; + case RectanglePoint_RIGHT_MIDDLE: nL = nWidth; nT = nB = nHeight / 2; break; + case RectanglePoint_MIDDLE_TOP: nB = nHeight; nL = nR = nWidth / 2; break; + case RectanglePoint_MIDDLE_BOTTOM: nT = nHeight; nL = nR = nWidth / 2; break; + case RectanglePoint_MIDDLE_MIDDLE: nL = nR = nWidth / 2; nT = nB = nHeight / 2; break; + default: break; + } + } + + mpFS->startElementNS(XML_a, XML_stretch); + + mpFS->singleElementNS(XML_a, XML_fillRect, XML_l, + sax_fastparser::UseIf(OString::number(nL), nL != 0), XML_t, + sax_fastparser::UseIf(OString::number(nT), nT != 0), XML_r, + sax_fastparser::UseIf(OString::number(nR), nR != 0), XML_b, + sax_fastparser::UseIf(OString::number(nB), nB != 0)); + + mpFS->endElementNS(XML_a, XML_stretch); +} + namespace { bool IsTopGroupObj(const uno::Reference<drawing::XShape>& xShape) diff --git a/sd/qa/unit/data/odp/tdf153105.odp b/sd/qa/unit/data/odp/tdf153105.odp new file mode 100644 index 000000000000..a5f765f9b084 Binary files /dev/null and b/sd/qa/unit/data/odp/tdf153105.odp differ diff --git a/sd/qa/unit/export-tests-ooxml3.cxx b/sd/qa/unit/export-tests-ooxml3.cxx index 7917e0f21a40..fa80e6c6b46c 100644 --- a/sd/qa/unit/export-tests-ooxml3.cxx +++ b/sd/qa/unit/export-tests-ooxml3.cxx @@ -40,6 +40,7 @@ public: { } + void testTdf153105(); void testTdf92222(); void testTdf129430(); void testTdf114848(); @@ -137,6 +138,7 @@ public: CPPUNIT_TEST_SUITE(SdOOXMLExportTest3); + CPPUNIT_TEST(testTdf153105); CPPUNIT_TEST(testTdf92222); CPPUNIT_TEST(testTdf129430); CPPUNIT_TEST(testTdf114848); @@ -238,6 +240,22 @@ public: } }; +void SdOOXMLExportTest3::testTdf153105() +{ + createSdImpressDoc("odp/tdf153105.odp"); + save("Impress Office Open XML"); + + xmlDocUniquePtr pXmlDoc1 = parseExport("ppt/slides/slide1.xml"); + assertXPath(pXmlDoc1, "/p:sld/p:cSld/p:bg/p:bgPr/a:blipFill/a:stretch/a:fillRect", "l", + "20000"); + assertXPath(pXmlDoc1, "/p:sld/p:cSld/p:bg/p:bgPr/a:blipFill/a:stretch/a:fillRect", "t", + "30000"); + assertXPath(pXmlDoc1, "/p:sld/p:cSld/p:bg/p:bgPr/a:blipFill/a:stretch/a:fillRect", "r", + "20000"); + assertXPath(pXmlDoc1, "/p:sld/p:cSld/p:bg/p:bgPr/a:blipFill/a:stretch/a:fillRect", "b", + "30000"); +} + void SdOOXMLExportTest3::testTdf92222() { createSdImpressDoc("pptx/tdf92222.pptx");