include/editeng/unoprnms.hxx | 1 include/svx/svdograf.hxx | 2 include/svx/unoshprp.hxx | 2 include/xmloff/shapeexport.hxx | 6 ++ svx/source/svdraw/svdograf.cxx | 72 +++++++++++++++++++++++++++++++++ svx/source/unodraw/unoprov.cxx | 1 svx/source/unodraw/unoshap2.cxx | 7 ++- xmloff/source/draw/shapeexport.cxx | 80 +++++++++++++++++++++++++++++++++++-- 8 files changed, 166 insertions(+), 5 deletions(-)
New commits: commit d73d26e8d74988f5a4c2afcaae715dd50425100a Author: Caolán McNamara <[email protected]> AuthorDate: Fri Sep 12 15:36:30 2025 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Wed Sep 17 09:44:05 2025 +0200 optionally explode pdf into odf elements as fodg export time e.g. instdir/program/soffice --headless --convert-to \ 'fodg:OpenDocument Drawing Flat XML:{"DecomposePDF":{"type":"boolean","value":"true"}}' \ sample.pdf Change-Id: I1e36b3d0c12e8716aada52e5d34526d06fe28cc5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190967 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/include/editeng/unoprnms.hxx b/include/editeng/unoprnms.hxx index b42c03bca762..327a32dc47b6 100644 --- a/include/editeng/unoprnms.hxx +++ b/include/editeng/unoprnms.hxx @@ -178,6 +178,7 @@ inline constexpr OUString UNO_NAME_HYPERLINK = u"Hyperlink"_ustr; inline constexpr OUString UNO_NAME_GRAPHOBJ_FILLBITMAP = u"GraphicObjectFillBitmap"_ustr; inline constexpr OUString UNO_NAME_GRAPHOBJ_REPLACEMENT_GRAPHIC = u"ReplacementGraphic"_ustr; +inline constexpr OUString UNO_NAME_GRAPHOBJ_REPLACEMENT_MODEL = u"ReplacementModel"_ustr; inline constexpr OUString UNO_NAME_GRAPHOBJ_GRAFSTREAMURL = u"GraphicStreamURL"_ustr; #define UNO_NAME_GRAPHOBJ_URLPKGPREFIX "vnd.sun.star.Package:" inline constexpr OUString UNO_NAME_GRAPHOBJ_GRAPHIC = u"Graphic"_ustr; diff --git a/include/svx/svdograf.hxx b/include/svx/svdograf.hxx index fae28c0a72dc..9618b884bf18 100644 --- a/include/svx/svdograf.hxx +++ b/include/svx/svdograf.hxx @@ -124,6 +124,8 @@ public: void SetGraphicObject( const GraphicObject& rGrfObj ); const GraphicObject& GetGraphicObject(bool bForceSwapIn = false) const; SAL_DLLPRIVATE const GraphicObject* GetReplacementGraphicObject() const; + // An exploded view of a pdf page as a draw document. + SAL_DLLPRIVATE css::uno::Reference<css::lang::XComponent> GetReplacementGraphicModel() const; SAL_DLLPRIVATE void NbcSetGraphic(const Graphic& rGrf); void SetGraphic(const Graphic& rGrf); diff --git a/include/svx/unoshprp.hxx b/include/svx/unoshprp.hxx index cbb2521684be..358576ac23ce 100644 --- a/include/svx/unoshprp.hxx +++ b/include/svx/unoshprp.hxx @@ -117,6 +117,7 @@ /// reuse attr slots for GraphicObject which will never be used together with graphic object #define OWN_ATTR_REPLACEMENT_GRAPHIC (OWN_ATTR_VALUE_START+14) +#define OWN_ATTR_REPLACEMENT_MODEL (OWN_ATTR_VALUE_START+15) #define OWN_ATTR_APPLET_DOCBASE (OWN_ATTR_VALUE_START+48) #define OWN_ATTR_APPLET_CODEBASE (OWN_ATTR_VALUE_START+49) @@ -471,6 +472,7 @@ SPECIAL_GRAPHOBJ_PROPERTIES_DEFAULTS \ { UNO_NAME_GRAPHIC_GRAPHICCROP, SDRATTR_GRAFCROP , ::cppu::UnoType<css::text::GraphicCrop>::get(), 0, 0 }, \ { UNO_NAME_GRAPHOBJ_REPLACEMENT_GRAPHIC, OWN_ATTR_REPLACEMENT_GRAPHIC, cppu::UnoType<css::graphic::XGraphic>::get() , 0, 0}, \ + { UNO_NAME_GRAPHOBJ_REPLACEMENT_MODEL , OWN_ATTR_REPLACEMENT_MODEL, cppu::UnoType<css::lang::XComponent>::get() , 0, 0}, \ { UNO_NAME_GRAPHOBJ_GRAFSTREAMURL, OWN_ATTR_GRAFSTREAMURL , ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 }, \ { UNO_NAME_GRAPHOBJ_FILLBITMAP, OWN_ATTR_VALUE_FILLBITMAP , cppu::UnoType<css::awt::XBitmap>::get() , 0, 0}, \ { UNO_NAME_GRAPHOBJ_GRAPHIC, OWN_ATTR_VALUE_GRAPHIC , cppu::UnoType<css::graphic::XGraphic>::get() , 0, 0}, \ diff --git a/include/xmloff/shapeexport.hxx b/include/xmloff/shapeexport.hxx index 0d0e4ce6521e..7cf99533cf7a 100644 --- a/include/xmloff/shapeexport.hxx +++ b/include/xmloff/shapeexport.hxx @@ -39,6 +39,7 @@ namespace com::sun::star::awt { struct Point; } namespace com::sun::star::beans { class XPropertySet; } namespace com::sun::star::drawing { class XShape; } namespace com::sun::star::drawing { class XShapes; } +namespace com::sun::star::lang { class XComponent; } class XMLTableExport; namespace comphelper { class AttributeList; } @@ -135,6 +136,7 @@ struct ImplXMLShapeExportInfo XmlShapeType meShapeType; css::uno::Reference< css::drawing::XShape > xCustomShapeReplacement; + css::uno::Reference<css::lang::XComponent> xPDFModelReplacement; ImplXMLShapeExportInfo() : mnFamily( XmlStyleFamily::SD_GRAPHICS_ID ), meShapeType( XmlShapeType::NotYetSet ) {} }; @@ -289,6 +291,10 @@ public: css::uno::Reference < css::drawing::XShape > checkForCustomShapeReplacement( const css::uno::Reference < css::drawing::XShape >& ); + /** replacing PDF with drawing objects */ + css::uno::Reference<css::lang::XComponent> checkForPDFShapeReplacement( + const css::uno::Reference<css::drawing::XShape>& xShape); + /** helper to export the style for graphic defaults */ void ExportGraphicDefaults(); diff --git a/svx/source/svdraw/svdograf.cxx b/svx/source/svdraw/svdograf.cxx index 3a11aa0a0d49..c766e7d4780d 100644 --- a/svx/source/svdraw/svdograf.cxx +++ b/svx/source/svdraw/svdograf.cxx @@ -29,11 +29,13 @@ #include <vcl/svapp.hxx> #include <sfx2/linkmgr.hxx> +#include <sfx2/viewsh.hxx> #include <svx/dialmgr.hxx> #include <svx/strings.hrc> #include <svx/svdhdl.hxx> #include <svx/svdmodel.hxx> #include <svx/svdpage.hxx> +#include <svx/svdview.hxx> #include <svx/svdograf.hxx> #include <svx/svdogrp.hxx> #include <svx/xbtmpit.hxx> @@ -54,6 +56,15 @@ #include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx> #include <memory> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/frame/DispatchHelper.hpp> +#include <com/sun/star/frame/XDesktop2.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <vcl/filter/PDFiumLibrary.hxx> +#include <svdpdf.hxx> +#include <svx/unoapi.hxx> + using namespace ::com::sun::star; class SdrGraphicLink : public sfx2::SvBaseLink @@ -349,6 +360,67 @@ const GraphicObject* SdrGrafObj::GetReplacementGraphicObject() const return mpReplacementGraphicObject.get(); } +css::uno::Reference<css::lang::XComponent> SdrGrafObj::GetReplacementGraphicModel() const +{ + if (!mpGraphicObject) + return nullptr; + + const Graphic& rGraphic = mpGraphicObject->GetGraphic(); + auto const & rVectorGraphicDataPtr = rGraphic.getVectorGraphicData(); + if (!rVectorGraphicDataPtr) + return nullptr; + + if (rVectorGraphicDataPtr->getType() != VectorGraphicDataType::Pdf) + return nullptr; + + auto pPdfium = vcl::pdf::PDFiumLibrary::get(); + if (!pPdfium) + return nullptr; + + // Create an empty Draw component. + uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext(); + uno::Reference<frame::XDesktop2> xDesktop = css::frame::Desktop::create(xContext); + if (!xDesktop) + return nullptr; + uno::Reference<lang::XComponent> xComponent = xDesktop->loadComponentFromURL(u"private:factory/sdraw"_ustr, u"_default"_ustr, 0, {}); + uno::Reference<frame::XModel> xModel(xComponent, uno::UNO_QUERY); + if (!xModel) + return nullptr; + uno::Reference<frame::XController> xController(xModel->getCurrentController()); + SfxViewShell* pViewShell = SfxViewShell::Get(xController); + if (!pViewShell) + return nullptr; + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(xComponent, uno::UNO_QUERY); + if (!xDrawPagesSupplier) + return nullptr; + uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages(); + if (!xDrawPages) + return nullptr; + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY); + SdrPage* pSdrPage = GetSdrPageFromXDrawPage(xDrawPage); + if (!pSdrPage) + return nullptr; + + SdrModel& rSdrModel = pSdrPage->getSdrModelFromSdrPage(); + + tools::Rectangle aLogicRect = GetLogicRect(); + + ImpSdrPdfImport aFilter(rSdrModel, GetLayer(), aLogicRect, rGraphic); + if (rGraphic.getPageNumber() < aFilter.GetPageCount()) + { + aFilter.DoImport(*pSdrPage, 0, rGraphic.getPageNumber(), nullptr); + } + + if (SdrView* pView = pViewShell->GetDrawView()) + { + // Group shapes together + pView->MarkAllObj(); + pView->GroupMarked(); + } + + return xComponent; +} + void SdrGrafObj::NbcSetGraphic(const Graphic& rGraphic) { mpGraphicObject->SetGraphic(rGraphic); diff --git a/svx/source/unodraw/unoprov.cxx b/svx/source/unodraw/unoprov.cxx index e4de02447d68..ca67ef523415 100644 --- a/svx/source/unodraw/unoprov.cxx +++ b/svx/source/unodraw/unoprov.cxx @@ -763,6 +763,7 @@ static std::span<SfxItemPropertyMapEntry const> ImplGetSvxTableShapePropertyMap( { u"UseBandingRowStyle"_ustr, OWN_ATTR_TABLETEMPLATE_BANDINGROWS, cppu::UnoType<bool>::get(),0, 0}, { u"UseBandingColumnStyle"_ustr, OWN_ATTR_TABLETEMPLATE_BANDINGCOLUMNS, cppu::UnoType<bool>::get(),0, 0}, { u"ReplacementGraphic"_ustr, OWN_ATTR_REPLACEMENT_GRAPHIC, cppu::UnoType<css::graphic::XGraphic>::get(), css::beans::PropertyAttribute::READONLY, 0}, + { u"ReplacementModel"_ustr, OWN_ATTR_REPLACEMENT_MODEL, cppu::UnoType<css::lang::XComponent>::get(), css::beans::PropertyAttribute::READONLY, 0}, }; return aTableShapePropertyMap_Impl; diff --git a/svx/source/unodraw/unoshap2.cxx b/svx/source/unodraw/unoshap2.cxx index d1a8c86d0f6c..f425c2fb76a6 100644 --- a/svx/source/unodraw/unoshap2.cxx +++ b/svx/source/unodraw/unoshap2.cxx @@ -65,7 +65,6 @@ #include <cppuhelper/queryinterface.hxx> #include <tools/stream.hxx> - #include <memory> using namespace ::cppu; @@ -1452,6 +1451,12 @@ bool SvxGraphicObject::getPropertyValueImpl( const OUString& rName, const SfxIte break; } + case OWN_ATTR_REPLACEMENT_MODEL: + { + rValue <<= static_cast<SdrGrafObj*>(GetSdrObject())->GetReplacementGraphicModel(); + break; + } + case OWN_ATTR_GRAFSTREAMURL: { const OUString aStreamURL( static_cast<SdrGrafObj*>( GetSdrObject() )->GetGrafStreamURL() ); diff --git a/xmloff/source/draw/shapeexport.cxx b/xmloff/source/draw/shapeexport.cxx index 5eb127ac8a89..db0448342990 100644 --- a/xmloff/source/draw/shapeexport.cxx +++ b/xmloff/source/draw/shapeexport.cxx @@ -60,6 +60,7 @@ #include <com/sun/star/drawing/ShadeMode.hpp> #include <com/sun/star/drawing/XControlShape.hpp> #include <com/sun/star/drawing/XCustomShapeEngine.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> #include <com/sun/star/drawing/XGluePointsSupplier.hpp> #include <com/sun/star/drawing/BarCode.hpp> #include <com/sun/star/drawing/BarCodeErrorCorrection.hpp> @@ -81,6 +82,7 @@ #include <com/sun/star/table/XColumnRowRange.hpp> #include <com/sun/star/text/WritingMode2.hpp> #include <com/sun/star/text/XText.hpp> +#include <com/sun/star/util/XCloseable.hpp> #include <comphelper/classids.hxx> #include <comphelper/processfactory.hxx> @@ -217,6 +219,50 @@ XMLShapeExport::~XMLShapeExport() { } +static css::uno::Reference<css::drawing::XShape> GetPDFShape(const uno::Reference<lang::XComponent>& xReplacementModel) +{ + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(xReplacementModel, uno::UNO_QUERY); + if (!xDrawPagesSupplier) + return nullptr; + uno::Reference<drawing::XDrawPages> xDrawPages(xDrawPagesSupplier->getDrawPages()); + if (!xDrawPages) + return nullptr; + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY); + if (!xDrawPage) + return nullptr; + return uno::Reference<drawing::XShape>(xDrawPage->getByIndex(0), uno::UNO_QUERY); +} + +uno::Reference<lang::XComponent> XMLShapeExport::checkForPDFShapeReplacement(const uno::Reference<drawing::XShape>& xShape) +{ + if (!GetExport().decomposePDF()) + return nullptr; + + OUString aType( xShape->getShapeType() ); + if (aType != "com.sun.star.drawing.GraphicObjectShape") + return nullptr; + + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return nullptr; + + uno::Reference<graphic::XGraphic> xGraphic; + xPropSet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic; + + OUString sOutMimeType; + GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType); + + if (sOutMimeType != "application/pdf") + return nullptr; + + // To export PDF as exploded drawing object replacements + uno::Reference<lang::XComponent> xReplacementModel; + xPropSet->getPropertyValue(u"ReplacementModel"_ustr) >>= xReplacementModel; + SAL_WARN_IF(!xReplacementModel.is(), "xmloff", "no xModel for pdf format"); + + return xReplacementModel; +} + // sj: replacing CustomShapes with standard objects that are also supported in OpenOffice.org format uno::Reference< drawing::XShape > XMLShapeExport::checkForCustomShapeReplacement( const uno::Reference< drawing::XShape >& xShape ) { @@ -284,9 +330,18 @@ void XMLShapeExport::collectShapeAutoStyles(const uno::Reference< drawing::XShap ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex]; - uno::Reference< drawing::XShape > xCustomShapeReplacement = checkForCustomShapeReplacement( xShape ); - if ( xCustomShapeReplacement.is() ) - aShapeInfo.xCustomShapeReplacement = std::move(xCustomShapeReplacement); + css::uno::Reference<css::lang::XComponent> xPDFModelReplacement = checkForPDFShapeReplacement(xShape); + if (xPDFModelReplacement) + { + aShapeInfo.xPDFModelReplacement = std::move(xPDFModelReplacement); + aShapeInfo.xCustomShapeReplacement = GetPDFShape(aShapeInfo.xPDFModelReplacement); + } + else + { + uno::Reference<drawing::XShape> xCustomShapeReplacement = checkForCustomShapeReplacement(xShape); + if ( xCustomShapeReplacement.is() ) + aShapeInfo.xCustomShapeReplacement = std::move(xCustomShapeReplacement); + } // first compute the shapes type ImpCalcShapeType(xShape, aShapeInfo.meShapeType); @@ -828,7 +883,24 @@ void XMLShapeExport::exportShape(const uno::Reference< drawing::XShape >& xShape case XmlShapeType::DrawGraphicObjectShape: case XmlShapeType::PresGraphicObjectShape: { - ImpExportGraphicObjectShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + if (aShapeInfo.xCustomShapeReplacement.is()) // exploded PDF + { + ImpExportGroupShape(aShapeInfo.xCustomShapeReplacement, nFeatures, pRefPoint); + uno::Reference<css::util::XCloseable> xClose(aShapeInfo.xPDFModelReplacement, uno::UNO_QUERY); + if (xClose.is()) + { + try + { + xClose->close(true); + } + catch (const uno::RuntimeException& e) + { + SAL_WARN("xmloff", "Couldn't close PDF replacement model: " << e.Message); + } + } + } + else + ImpExportGraphicObjectShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); break; }
