include/svx/unoshape.hxx | 2 + svx/source/unodraw/unoshap4.cxx | 25 +++++++++++++++ xmloff/CppunitTest_xmloff_draw.mk | 3 + xmloff/qa/unit/data/video-snapshot.odp |binary xmloff/qa/unit/draw.cxx | 50 ++++++++++++++++++++++++++++++ xmloff/source/draw/shapeexport.cxx | 54 ++++++++++++++++++++++++++++++++- xmloff/source/draw/ximpshap.cxx | 14 +++++++- 7 files changed, 146 insertions(+), 2 deletions(-)
New commits: commit 245124406bad17e3ca6526d472f97971e2095832 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Aug 29 09:23:22 2022 +0200 Commit: Sarper Akdemir <sarper.akde...@collabora.com> CommitDate: Wed Aug 31 10:00:04 2022 +0200 avmedia: implement video crop support in the ODP filter And also import/export the video preview as well. The naming follows the style used for table shape previews. The preview is important, since the cropping is relative to the bitmap's preferred logic size. (cherry picked from commit cbc6e67d3c88fb6ae39c304604a98eaa504f19cc) Conflicts: xmloff/source/draw/shapeexport.cxx Change-Id: I6115284c1f4cf342b3296cd0ac3beb70a809fd1b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138972 Tested-by: Jenkins Reviewed-by: Sarper Akdemir <sarper.akde...@collabora.com> diff --git a/include/svx/unoshape.hxx b/include/svx/unoshape.hxx index 61f33f46f9a1..6a898ceac515 100644 --- a/include/svx/unoshape.hxx +++ b/include/svx/unoshape.hxx @@ -858,6 +858,8 @@ private: // override these for special property handling in subcasses. Return true if property is handled virtual bool setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue ) override; virtual bool getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue ) override; + bool getPropertyStateImpl(const SfxItemPropertyMapEntry* pProperty, + css::beans::PropertyState& rState) override; OUString referer_; }; diff --git a/svx/source/unodraw/unoshap4.cxx b/svx/source/unodraw/unoshap4.cxx index 4aabe5929d28..3a1d2eda3402 100644 --- a/svx/source/unodraw/unoshap4.cxx +++ b/svx/source/unodraw/unoshap4.cxx @@ -1070,4 +1070,29 @@ bool SvxMediaShape::getPropertyValueImpl( const OUString& rName, const SfxItemPr } } +bool SvxMediaShape::getPropertyStateImpl(const SfxItemPropertyMapEntry* pProperty, + css::beans::PropertyState& rState) +{ +#if HAVE_FEATURE_AVMEDIA + if (pProperty->nWID == SDRATTR_GRAFCROP) + { + auto pMedia = static_cast<SdrMediaObj*>(GetSdrObject()); + const avmedia::MediaItem& rItem = pMedia->getMediaProperties(); + const text::GraphicCrop& rCrop = rItem.getCrop(); + if (rCrop.Bottom > 0 || rCrop.Left > 0 || rCrop.Right > 0 || rCrop.Top > 0) + { + // The media has a crop, expose it to UNO-based export filters. + rState = beans::PropertyState_DIRECT_VALUE; + } + else + { + rState = beans::PropertyState_AMBIGUOUS_VALUE; + } + return true; + } +#endif + + return SvxShape::getPropertyStateImpl(pProperty, rState); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/CppunitTest_xmloff_draw.mk b/xmloff/CppunitTest_xmloff_draw.mk index 42c7a9526661..a503cc9f2c1d 100644 --- a/xmloff/CppunitTest_xmloff_draw.mk +++ b/xmloff/CppunitTest_xmloff_draw.mk @@ -28,6 +28,9 @@ $(eval $(call gb_CppunitTest_use_libraries,xmloff_draw, \ test \ unotest \ utl \ + avmedia \ + svxcore \ + vcl \ )) $(eval $(call gb_CppunitTest_use_sdk_api,xmloff_draw)) diff --git a/xmloff/qa/unit/data/video-snapshot.odp b/xmloff/qa/unit/data/video-snapshot.odp new file mode 100644 index 000000000000..ca3b7f21dc6c Binary files /dev/null and b/xmloff/qa/unit/data/video-snapshot.odp differ diff --git a/xmloff/qa/unit/draw.cxx b/xmloff/qa/unit/draw.cxx index 3c6d7c707be9..f2aeb834c64e 100644 --- a/xmloff/qa/unit/draw.cxx +++ b/xmloff/qa/unit/draw.cxx @@ -24,6 +24,7 @@ #include <com/sun/star/util/Color.hpp> #include <com/sun/star/text/XTextRange.hpp> #include <com/sun/star/text/XTextTable.hpp> +#include <com/sun/star/text/GraphicCrop.hpp> #include <comphelper/configuration.hxx> #include <officecfg/Office/Common.hxx> @@ -31,6 +32,9 @@ #include <unotools/tempfile.hxx> #include <unotools/ucbstreamhelper.hxx> #include <unotools/saveopt.hxx> +#include <svx/unopage.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdomedia.hxx> using namespace ::com::sun::star; @@ -173,6 +177,52 @@ CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testThemeExport) assertXPath(pXmlDoc, "//style:master-page/loext:theme/loext:color-table/loext:color", 12); } +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testVideoSnapshot) +{ + // Execute ODP import: + OUString aURL = m_directories.getURLFromSrc(u"xmloff/qa/unit/data/video-snapshot.odp"); + getComponent() = loadFromDesktop(aURL, "com.sun.star.presentation.PresentationDocument"); + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), + uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT(xDrawPagesSupplier.is()); + uno::Reference<drawing::XDrawPages> xDrawPages(xDrawPagesSupplier->getDrawPages()); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT(xDrawPage.is()); + auto pUnoPage = dynamic_cast<SvxDrawPage*>(xDrawPage.get()); + SdrPage* pSdrPage = pUnoPage->GetSdrPage(); + auto pMedia = dynamic_cast<SdrMediaObj*>(pSdrPage->GetObj(0)); + + // Check that the preview was imported: + const avmedia::MediaItem& rItem = pMedia->getMediaProperties(); + const Graphic& rGraphic = rItem.getGraphic(); + CPPUNIT_ASSERT(!rGraphic.IsNone()); + + // Check that the crop was imported: + const text::GraphicCrop& rCrop = rItem.getCrop(); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), rCrop.Top); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), rCrop.Bottom); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1356), rCrop.Left); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1356), rCrop.Right); + + // Execute ODP export: + utl::TempFile aTempFile; + save("impress8", aTempFile); + + std::unique_ptr<SvStream> pStream = parseExportStream(aTempFile, "content.xml"); + xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get()); + // Check that the preview was exported: + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // - XPath '//draw:frame[@draw:style-name='gr1']/draw:image' number of nodes is incorrect + // i.e. the preview wasn't exported to ODP. + assertXPath(pXmlDoc, "//draw:frame[@draw:style-name='gr1']/draw:image", "href", + "Pictures/MediaPreview1.png"); + // Check that the crop was exported: + assertXPath(pXmlDoc, "//style:style[@style:name='gr1']/style:graphic-properties", "clip", + "rect(0cm, 1.356cm, 0cm, 1.356cm)"); +} + CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testThemeImport) { // Given a document that has a master page with a theme associated: diff --git a/xmloff/source/draw/shapeexport.cxx b/xmloff/source/draw/shapeexport.cxx index 89eceb95982c..727489f5b7a5 100644 --- a/xmloff/source/draw/shapeexport.cxx +++ b/xmloff/source/draw/shapeexport.cxx @@ -103,6 +103,7 @@ #include <tools/globname.hxx> #include <tools/helpers.hxx> #include <tools/diagnose_ex.h> +#include <vcl/graph.hxx> #include <xmloff/contextid.hxx> #include <xmloff/families.hxx> @@ -3400,7 +3401,7 @@ void XMLShapeExport::ImpExportMediaShape( mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, sMimeType ); // write plugin - SvXMLElementExport aPluginOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & XMLShapeExportFlags::NO_WS ), true); + auto pPluginOBJ = std::make_unique<SvXMLElementExport>(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & XMLShapeExportFlags::NO_WS ), true); // export parameters const OUString aFalseStr( "false" ), aTrueStr( "true" ); @@ -3450,6 +3451,57 @@ void XMLShapeExport::ImpExportMediaShape( delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); } + pPluginOBJ.reset(); + + uno::Reference<graphic::XGraphic> xGraphic; + xPropSet->getPropertyValue("Graphic") >>= xGraphic; + Graphic aGraphic(xGraphic); + if (!aGraphic.IsNone()) + { + // The media has a preview, export it. + uno::Reference<embed::XStorage> xPictureStorage; + uno::Reference<embed::XStorage> xStorage; + uno::Reference<io::XStream> xPictureStream; + OUString sPictureName; + xStorage.set(GetExport().GetTargetStorage(), uno::UNO_SET_THROW); + xPictureStorage.set( + xStorage->openStorageElement("Pictures", embed::ElementModes::READWRITE), + uno::UNO_SET_THROW); + sal_Int32 nIndex = 0; + while (true) + { + sPictureName = "MediaPreview" + OUString::number(++nIndex) + ".png"; + if (!xPictureStorage->hasByName(sPictureName)) + { + break; + } + } + + xPictureStream.set( + xPictureStorage->openStreamElement(sPictureName, ::embed::ElementModes::READWRITE), + uno::UNO_SET_THROW); + + uno::Reference<uno::XComponentContext> xContext = GetExport().getComponentContext(); + uno::Reference<graphic::XGraphicProvider> xProvider( + graphic::GraphicProvider::create(xContext)); + uno::Sequence<beans::PropertyValue> aArgs{ + comphelper::makePropertyValue("MimeType", OUString("image/png")), + comphelper::makePropertyValue("OutputStream", xPictureStream->getOutputStream()) + }; + xProvider->storeGraphic(xGraphic, aArgs); + if (xPictureStorage.is()) + { + uno::Reference<embed::XTransactedObject> xTrans(xPictureStorage, uno::UNO_QUERY); + if (xTrans.is()) + xTrans->commit(); + } + OUString sURL = "Pictures/" + sPictureName; + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD); + SvXMLElementExport aImageElem(GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, false, true); + } } void XMLShapeExport::ImpExport3DSceneShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) diff --git a/xmloff/source/draw/ximpshap.cxx b/xmloff/source/draw/ximpshap.cxx index 9e2973403142..b1e208c9c351 100644 --- a/xmloff/source/draw/ximpshap.cxx +++ b/xmloff/source/draw/ximpshap.cxx @@ -2916,6 +2916,12 @@ void SdXMLPluginShapeContext::startFastElement (sal_Int32 /*nElement*/, if( !mxShape.is() ) return; + if (mbMedia) + { + // The media may have a crop, apply it. + SetStyle(/*bSupportsStyle=*/false); + } + SetLayer(); if(bIsPresShape) @@ -3310,6 +3316,7 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLFrameShapeContext pShapeContext->setHyperlink( msHyperlink ); auto nToken = nElement & TOKEN_MASK; + bool bMedia = false; // Ignore gltf model if necessary and so the fallback image will be imported if( nToken == XML_PLUGIN ) { @@ -3319,10 +3326,15 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLFrameShapeContext mxImplContext = nullptr; return new SvXMLImportContext(GetImport()); } + else if (pPluginContext && pPluginContext->getMimeType() == "application/vnd.sun.star.media") + { + // The media may have a preview, import it. + bMedia = true; + } } mxImplContext = xContext; - mbSupportsReplacement = (nToken == XML_OBJECT ) || (nToken == XML_OBJECT_OLE); + mbSupportsReplacement = (nToken == XML_OBJECT ) || (nToken == XML_OBJECT_OLE) || bMedia; setSupportsMultipleContents(nToken == XML_IMAGE); if(getSupportsMultipleContents() && dynamic_cast< SdXMLGraphicObjectShapeContext* >(xContext.get()))