From 363b2d374be736e713c4b8aa0f7b9fda8849335b Mon Sep 17 00:00:00 2001 From: Gülşah Köse Date: Mon, 1 Feb 2021 17:03:33 +0300 Subject: tdf#134210 Import crop position of bitmap filled shape. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I6a62d68cd0f57e53934851a2f53dae05bf7d3730 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110262 Tested-by: Jenkins Reviewed-by: Gülşah Köse Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110964 Tested-by: Jenkins CollaboraOffice Reviewed-by: Miklos Vajna --- oox/source/drawingml/fillproperties.cxx | 84 ++++++++++++++++++++++++-------- oox/source/export/drawingml.cxx | 23 +++++++-- sd/qa/unit/data/pptx/crop-position.pptx | Bin 0 -> 175724 bytes sd/qa/unit/export-tests-ooxml1.cxx | 29 +++++++++-- sd/qa/unit/import-tests.cxx | 16 ++++++ 5 files changed, 121 insertions(+), 31 deletions(-) create mode 100644 sd/qa/unit/data/pptx/crop-position.pptx diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx index f17a613b444e..5ac24b948f98 100644 --- a/oox/source/drawingml/fillproperties.cxx +++ b/oox/source/drawingml/fillproperties.cxx @@ -93,6 +93,30 @@ Reference< XGraphic > lclRotateGraphic(uno::Reference const & return aReturnGraphic.GetXGraphic(); } +void lclCalculateCropPercentage(uno::Reference const & xGraphic, geometry::IntegerRectangle2D &aFillRect) +{ + ::Graphic aGraphic(xGraphic); + assert (aGraphic.GetType() == GraphicType::Bitmap); + + BitmapEx aBitmapEx(aGraphic.GetBitmapEx()); + + sal_Int32 nScaledWidth = aBitmapEx.GetSizePixel().Width(); + sal_Int32 nScaledHeight = aBitmapEx.GetSizePixel().Height(); + + sal_Int32 nOrigWidth = (nScaledWidth * (100000 - aFillRect.X1 - aFillRect.X2)) / 100000; + sal_Int32 nOrigHeight = (nScaledHeight * (100000 - aFillRect.Y1 - aFillRect.Y2)) / 100000; + + sal_Int32 nLeftPercentage = nScaledWidth * aFillRect.X1 / nOrigWidth; + sal_Int32 nRightPercentage = nScaledWidth * aFillRect.X2 / nOrigWidth; + sal_Int32 nTopPercentage = nScaledHeight * aFillRect.Y1 / nOrigHeight; + sal_Int32 nBottomPercentage = nScaledHeight * aFillRect.Y2 / nOrigHeight; + + aFillRect.X1 = -nLeftPercentage; + aFillRect.X2 = -nRightPercentage; + aFillRect.Y1 = -nTopPercentage; + aFillRect.Y2 = -nBottomPercentage; +} + Reference< XGraphic > lclCropGraphic(uno::Reference const & xGraphic, geometry::IntegerRectangle2D aFillRect) { ::Graphic aGraphic(xGraphic); @@ -109,8 +133,15 @@ Reference< XGraphic > lclCropGraphic(uno::Reference const & x sal_Int32 nBottomCorr = nOrigHeight * -1 * static_cast(aFillRect.Y2) / 100000; nHeight += nBottomCorr; - aBitmapEx.Scale(Size(aBitmapEx.GetSizePixel().Width(), nHeight)); - aBitmapEx.Crop(tools::Rectangle(Point(0, nTopCorr), Size(aBitmapEx.GetSizePixel().Width(), nOrigHeight))); + sal_Int32 nOrigWidth = aBitmapEx.GetSizePixel().Width(); + sal_Int32 nWidth = nOrigWidth; + sal_Int32 nLeftCorr = nOrigWidth * -1 * static_cast(aFillRect.X1) / 100000; + nWidth += nLeftCorr; + sal_Int32 nRightCorr = nOrigWidth * -1 * static_cast(aFillRect.X2) / 100000; + nWidth += nRightCorr; + + aBitmapEx.Scale(Size(nWidth, nHeight)); + aBitmapEx.Crop(tools::Rectangle(Point(nLeftCorr, nTopCorr), Size(nOrigWidth, nOrigHeight))); aReturnGraphic = ::Graphic(aBitmapEx); aReturnGraphic.setOriginURL(aGraphic.getOriginURL()); @@ -807,6 +838,36 @@ void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const GraphicHelpe nContrast = 0; } + // cropping + if ( maBlipProps.moClipRect.has() ) + { + geometry::IntegerRectangle2D oClipRect( maBlipProps.moClipRect.get() ); + awt::Size aOriginalSize( rGraphicHelper.getOriginalSize( xGraphic ) ); + if ( aOriginalSize.Width && aOriginalSize.Height ) + { + text::GraphicCrop aGraphCrop( 0, 0, 0, 0 ); + if ( oClipRect.X1 ) + aGraphCrop.Left = rtl::math::round( ( static_cast< double >( aOriginalSize.Width ) * oClipRect.X1 ) / 100000 ); + if ( oClipRect.Y1 ) + aGraphCrop.Top = rtl::math::round( ( static_cast< double >( aOriginalSize.Height ) * oClipRect.Y1 ) / 100000 ); + if ( oClipRect.X2 ) + aGraphCrop.Right = rtl::math::round( ( static_cast< double >( aOriginalSize.Width ) * oClipRect.X2 ) / 100000 ); + if ( oClipRect.Y2 ) + aGraphCrop.Bottom = rtl::math::round( ( static_cast< double >( aOriginalSize.Height ) * oClipRect.Y2 ) / 100000 ); + rPropMap.setProperty(PROP_GraphicCrop, aGraphCrop); + } + + if(mbIsCustomShape) + { + geometry::IntegerRectangle2D aCropRect = oClipRect; + lclCalculateCropPercentage(xGraphic, aCropRect); + xGraphic = lclCropGraphic(xGraphic, aCropRect); + + rPropMap.setProperty(PROP_FillBitmap, xGraphic); + } + + } + if(mbIsCustomShape) { // it is a cropped graphic. @@ -831,25 +892,6 @@ void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const GraphicHelpe else rPropMap.setProperty(PROP_Graphic, xGraphic); - // cropping - if ( maBlipProps.moClipRect.has() ) - { - geometry::IntegerRectangle2D oClipRect( maBlipProps.moClipRect.get() ); - awt::Size aOriginalSize( rGraphicHelper.getOriginalSize( xGraphic ) ); - if ( aOriginalSize.Width && aOriginalSize.Height ) - { - text::GraphicCrop aGraphCrop( 0, 0, 0, 0 ); - if ( oClipRect.X1 ) - aGraphCrop.Left = rtl::math::round( ( static_cast< double >( aOriginalSize.Width ) * oClipRect.X1 ) / 100000 ); - if ( oClipRect.Y1 ) - aGraphCrop.Top = rtl::math::round( ( static_cast< double >( aOriginalSize.Height ) * oClipRect.Y1 ) / 100000 ); - if ( oClipRect.X2 ) - aGraphCrop.Right = rtl::math::round( ( static_cast< double >( aOriginalSize.Width ) * oClipRect.X2 ) / 100000 ); - if ( oClipRect.Y2 ) - aGraphCrop.Bottom = rtl::math::round( ( static_cast< double >( aOriginalSize.Height ) * oClipRect.Y2 ) / 100000 ); - rPropMap.setProperty(PROP_GraphicCrop, aGraphCrop); - } - } if ( maBlipProps.moAlphaModFix.has() ) { diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index db2cb733bebc..fd4f67732607 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -1553,9 +1553,25 @@ void DrawingML::WritePattFill(const Reference& rXPropSet, const cs mpFS->endElementNS( XML_a , XML_pattFill ); } -void DrawingML::WriteGraphicCropProperties(uno::Reference const & rXPropSet, Size const & rOriginalSize, MapMode const & rMapMode) +void DrawingML::WriteGraphicCropProperties(uno::Reference const & rXPropSet, + Size const & rOriginalSize, + MapMode const & rMapMode) { - if (GetProperty(rXPropSet, "GraphicCrop")) + if (!GetProperty(rXPropSet, "GraphicCrop")) + return; + + css::text::GraphicCrop aGraphicCropStruct; + mAny >>= aGraphicCropStruct; + + if(GetProperty(rXPropSet, "CustomShapeGeometry")) + { + // tdf#134210 GraphicCrop property is handled in import filter because of LibreOffice has not core + // feature. We croped the bitmap physically and MSO shouldn't crop bitmap one more time. When we + // have core feature for graphic cropping in custom shapes, we should uncomment the code anymore. + + mpFS->singleElementNS( XML_a, XML_srcRect); + } + else { Size aOriginalSize(rOriginalSize); @@ -1563,9 +1579,6 @@ void DrawingML::WriteGraphicCropProperties(uno::Reference c if (rMapMode.GetMapUnit() == MapUnit::MapPixel) aOriginalSize = Application::GetDefaultDevice()->PixelToLogic(aOriginalSize, MapMode(MapUnit::Map100thMM)); - css::text::GraphicCrop aGraphicCropStruct; - mAny >>= aGraphicCropStruct; - if ( (0 != aGraphicCropStruct.Left) || (0 != aGraphicCropStruct.Top) || (0 != aGraphicCropStruct.Right) || (0 != aGraphicCropStruct.Bottom) ) { mpFS->singleElementNS( XML_a, XML_srcRect, diff --git a/sd/qa/unit/data/pptx/crop-position.pptx b/sd/qa/unit/data/pptx/crop-position.pptx new file mode 100644 index 000000000000..69507514e0b7 Binary files /dev/null and b/sd/qa/unit/data/pptx/crop-position.pptx differ diff --git a/sd/qa/unit/export-tests-ooxml1.cxx b/sd/qa/unit/export-tests-ooxml1.cxx index a71952ffd413..1660e7b0c26c 100644 --- a/sd/qa/unit/export-tests-ooxml1.cxx +++ b/sd/qa/unit/export-tests-ooxml1.cxx @@ -1091,17 +1091,36 @@ void SdOOXMLExportTest1::testCustomshapeBitmapfillSrcrect() xDocShRef->DoClose(); xmlDocPtr pXmlDoc = parseExport(tempFile, "ppt/slides/slide1.xml"); - const OString sXmlPath = "//a:blipFill/a:srcRect"; + + // tdf#132680 + // We are preventing the side effect of DOCX improvement to PPTX case. // Without the accompanying fix in place, this test would have failed with: // - Expected: 1 // - Actual : 0 // - XPath '//a:blipFill/a:srcRect' number of nodes is incorrect // i.e. was exported as in , which made part of the image // invisible. - double fLeftPercent = std::round(getXPath(pXmlDoc, sXmlPath, "l").toDouble() / 1000); - CPPUNIT_ASSERT_EQUAL(4.0, fLeftPercent); - double fRightPercent = std::round(getXPath(pXmlDoc, sXmlPath, "r").toDouble() / 1000); - CPPUNIT_ASSERT_EQUAL(4.0, fRightPercent); + + // tdf#134210 + // Original values of attribute of l and r in xml files: + // Because of we have not core feature for cropping bitmap in custom shapes, we added cropping + // support to import filter. We modified the bitmap during import. As result the original + // image is cropped anymore (if we had the core feature for that, the original image would + // remain same, just we would see like cropped in the shape) To see the image in correct + // position in Microsoft Office too, we have to remove left right top bottom percentages + // anymore. In the future if we add core feature to LibreOffice, this test will failed with + // When we add the core feature, we should change the control value with 4393 as following. + + //const OString sXmlPath = "//a:blipFill/a:srcRect"; + //sal_Int32 nLeftPercent = getXPath(pXmlDoc, sXmlPath, "l").toInt32(); + //CPPUNIT_ASSERT_EQUAL(sal_Int32(4393), nLeftPercent); + //sal_Int32 nRightPercent = getXPath(pXmlDoc, sXmlPath, "r").toInt32(); + //CPPUNIT_ASSERT_EQUAL(sal_Int32(4393), nRightPercent); + + assertXPathNoAttribute(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:blipFill/a:srcRect", "l"); + assertXPathNoAttribute(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:blipFill/a:srcRect", "r"); + assertXPathNoAttribute(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:blipFill/a:srcRect", "t"); + assertXPathNoAttribute(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:blipFill/a:srcRect", "b"); } void SdOOXMLExportTest1::testTdf128345FullTransparentGradient() diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx index d75c89185f66..e0c725031f10 100644 --- a/sd/qa/unit/import-tests.cxx +++ b/sd/qa/unit/import-tests.cxx @@ -209,6 +209,7 @@ public: void testTdf128684(); void testTdf119187(); void testMirroredGraphic(); + void testCropPositionGraphic(); bool checkPattern(sd::DrawDocShellRef const & rDocRef, int nShapeNumber, std::vector& rExpected); void testPatternImport(); @@ -336,6 +337,7 @@ public: CPPUNIT_TEST(testTdf113198); CPPUNIT_TEST(testTdf119187); CPPUNIT_TEST(testMirroredGraphic); + CPPUNIT_TEST(testCropPositionGraphic); CPPUNIT_TEST_SUITE_END(); }; @@ -3238,6 +3240,20 @@ void SdImportTest::testMirroredGraphic() xDocShRef->DoClose(); } +void SdImportTest::testCropPositionGraphic() +{ + sd::DrawDocShellRef xDocShRef = loadURL(m_directories.getURLFromSrc(u"sd/qa/unit/data/pptx/crop-position.pptx"), PPTX); + uno::Reference xShape(getShapeFromPage(0, 0, xDocShRef), uno::UNO_SET_THROW); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference xGraphic; + xShape->getPropertyValue("FillBitmap") >>= xGraphic; + CPPUNIT_ASSERT(xGraphic.is()); + Graphic aGraphic(xGraphic); + BitmapEx aBitmap(aGraphic.GetBitmapEx()); + CPPUNIT_ASSERT_EQUAL( Color(8682893), aBitmap.GetPixelColor( 0, 0 )); + xDocShRef->DoClose(); +} + CPPUNIT_TEST_SUITE_REGISTRATION(SdImportTest); CPPUNIT_PLUGIN_IMPLEMENT(); -- cgit