diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2023-12-03 13:21:35 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2023-12-04 10:33:34 +0100 |
commit | bfbbf06bcea4d58117c14fd3f3b8743a3714f97e (patch) | |
tree | a2f14a18ead422a6ea4ae0afb283c1ea38c42861 /oox | |
parent | 09200875ce643e66f293d39bb27630a3fdbb984d (diff) |
tdf#126084 support writing SVG images into OOXML using the MS OOXML extension
SVG files aren't supported in OOXML, but we can write it using the
MS OOXML extension, which is supported in the latest MSO versions.
For now this only implements the support in the exporter.
Change-Id: I688180fb5772f3999c2ee3020bc234f90d57cc2f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157237
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'oox')
-rw-r--r-- | oox/source/export/drawingml.cxx | 103 | ||||
-rw-r--r-- | oox/source/token/namespaces-strict.txt | 1 | ||||
-rw-r--r-- | oox/source/token/namespaces.txt | 1 | ||||
-rw-r--r-- | oox/source/token/tokens.txt | 2 |
4 files changed, 101 insertions, 6 deletions
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 228aa2326cc0..05c96c9ad798 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -1283,12 +1283,34 @@ OUString DrawingML::GetRelationCompPrefix() const return OUString(getRelationCompPrefix(meDocumentType)); } +void GraphicExport::writeSvgExtension(OUString const& rSvgRelId) +{ + if (rSvgRelId.isEmpty()) + return; + + mpFS->startElementNS(XML_a, XML_extLst); + mpFS->startElementNS(XML_a, XML_ext, XML_uri, "{96DAC541-7B7A-43D3-8B79-37D633B846F1}"); + mpFS->singleElementNS(XML_asvg, XML_svgBlip, + FSNS(XML_xmlns, XML_asvg), mpFilterBase->getNamespaceURL(OOX_NS(asvg)), + FSNS(XML_r, XML_embed), rSvgRelId); + mpFS->endElementNS(XML_a, XML_ext); + mpFS->endElementNS( XML_a, XML_extLst); +} + void GraphicExport::writeBlip(Graphic const& rGraphic, std::vector<model::BlipEffect> const& rEffects, bool bRelPathToMedia) { OUString sRelId = writeToStorage(rGraphic, bRelPathToMedia); mpFS->startElementNS(XML_a, XML_blip, FSNS(XML_r, XML_embed), sRelId); + auto const& rVectorGraphicDataPtr = rGraphic.getVectorGraphicData(); + + if (rVectorGraphicDataPtr && rVectorGraphicDataPtr->getType() == VectorGraphicDataType::Svg) + { + OUString sSvgRelId = writeToStorage(rGraphic, bRelPathToMedia, TypeHint::SVG); + writeSvgExtension(sSvgRelId); + } + for (auto const& rEffect : rEffects) { switch (rEffect.meType) @@ -1514,19 +1536,72 @@ OUString GraphicExport::writeNewEntryToStorage(const Graphic& rGraphic, bool bRe return sPath; } -OUString GraphicExport::writeToStorage(const Graphic& rGraphic , bool bRelPathToMedia) +namespace +{ +BitmapChecksum makeChecksumUniqueForSVG(BitmapChecksum const& rChecksum) +{ + // need to modify the checksum so we know it's for SVG - just invert it + return ~rChecksum; +} + +} // end anonymous namespace + +OUString GraphicExport::writeNewSvgEntryToStorage(const Graphic& rGraphic, bool bRelPathToMedia) +{ + OUString sMediaType = u"image/svg"_ustr; + OUString aExtension = u"svg"_ustr; + + GfxLink const& rLink = rGraphic.GetGfxLink(); + if (rLink.GetType() != GfxLinkType::NativeSvg) + return OUString(); + + const void* aData = rLink.GetData(); + std::size_t nDataSize = rLink.GetDataSize(); + + GraphicExportCache& rGraphicExportCache = GraphicExportCache::get(); + auto sImageCountString = OUString::number(rGraphicExportCache.nextImageCount()); + + OUString sComponentDir(getComponentDir(meDocumentType)); + + OUString sImagePath = sComponentDir + u"/media/image"_ustr + sImageCountString + u"."_ustr + aExtension; + + Reference<XOutputStream> xOutStream = mpFilterBase->openFragmentStream(sImagePath, sMediaType); + xOutStream->writeBytes(Sequence<sal_Int8>(static_cast<const sal_Int8*>(aData), nDataSize)); + xOutStream->closeOutput(); + + OUString sRelationCompPrefix; + if (bRelPathToMedia) + sRelationCompPrefix = u"../"_ustr; + else + sRelationCompPrefix = getRelationCompPrefix(meDocumentType); + + OUString sPath = sRelationCompPrefix + u"media/image"_ustr + sImageCountString + u"."_ustr + aExtension; + + rGraphicExportCache.addExportGraphics(makeChecksumUniqueForSVG(rGraphic.GetChecksum()), sPath); + + return sPath; +} + +OUString GraphicExport::writeToStorage(const Graphic& rGraphic, bool bRelPathToMedia, TypeHint eHint) { OUString sPath; + auto aChecksum = rGraphic.GetChecksum(); + if (eHint == TypeHint::SVG) + aChecksum = makeChecksumUniqueForSVG(aChecksum); + GraphicExportCache& rGraphicExportCache = GraphicExportCache::get(); - sPath = rGraphicExportCache.findExportGraphics(rGraphic.GetChecksum()); + sPath = rGraphicExportCache.findExportGraphics(aChecksum); if (sPath.isEmpty()) { - sPath = writeNewEntryToStorage(rGraphic, bRelPathToMedia); + if (eHint == TypeHint::SVG) + sPath = writeNewSvgEntryToStorage(rGraphic, bRelPathToMedia); + else + sPath = writeNewEntryToStorage(rGraphic, bRelPathToMedia); if (sPath.isEmpty()) - return OUString(); // couldn't store - just return empty string + return OUString(); // couldn't store } OUString sRelId = mpFilterBase->addRelation(mpFS->getOutputStream(), oox::getRelationship(Relationship::IMAGE), sPath); @@ -1534,10 +1609,15 @@ OUString GraphicExport::writeToStorage(const Graphic& rGraphic , bool bRelPathTo return sRelId; } -OUString DrawingML::writeGraphicToStorage( const Graphic& rGraphic , bool bRelPathToMedia ) +std::shared_ptr<GraphicExport> DrawingML::createGraphicExport() +{ + return std::make_shared<GraphicExport>(mpFS, mpFB, meDocumentType); +} + +OUString DrawingML::writeGraphicToStorage(const Graphic& rGraphic , bool bRelPathToMedia, GraphicExport::TypeHint eHint) { GraphicExport aExporter(mpFS, mpFB, meDocumentType); - return aExporter.writeToStorage(rGraphic, bRelPathToMedia); + return aExporter.writeToStorage(rGraphic, bRelPathToMedia, eHint); } void DrawingML::WriteMediaNonVisualProperties(const css::uno::Reference<css::drawing::XShape>& xShape) @@ -1706,10 +1786,21 @@ void DrawingML::WriteXGraphicBlip(uno::Reference<beans::XPropertySet> const & rX return; Graphic aGraphic(rxGraphic); + sRelId = writeGraphicToStorage(aGraphic, bRelPathToMedia); mpFS->startElementNS(XML_a, XML_blip, FSNS(XML_r, XML_embed), sRelId); + auto pVectorGraphicDataPtr = aGraphic.getVectorGraphicData(); + + if (pVectorGraphicDataPtr && pVectorGraphicDataPtr->getType() == VectorGraphicDataType::Svg) + { + GraphicExport aExporter(mpFS, mpFB, meDocumentType); + OUString sSvgRelId = aExporter.writeToStorage(aGraphic, bRelPathToMedia, GraphicExport::TypeHint::SVG); + if (!sSvgRelId.isEmpty()) + aExporter.writeSvgExtension(sSvgRelId); + } + WriteImageBrightnessContrastTransparence(rXPropSet); WriteArtisticEffect(rXPropSet); diff --git a/oox/source/token/namespaces-strict.txt b/oox/source/token/namespaces-strict.txt index beed3238ae2d..2b6c53807377 100644 --- a/oox/source/token/namespaces-strict.txt +++ b/oox/source/token/namespaces-strict.txt @@ -94,6 +94,7 @@ xr2 http://schemas.microsoft.com/office/spreadsheetml/2015/r # extlst namespaces adec http://schemas.microsoft.com/office/drawing/2017/decorative +asvg http://schemas.microsoft.com/office/drawing/2016/SVG/main # xls14Lst for features introduced by excel 2010 xls14Lst http://schemas.microsoft.com/office/spreadsheetml/2009/9/main diff --git a/oox/source/token/namespaces.txt b/oox/source/token/namespaces.txt index dbe29f19a220..c2e30e0f8421 100644 --- a/oox/source/token/namespaces.txt +++ b/oox/source/token/namespaces.txt @@ -94,6 +94,7 @@ xr2 http://schemas.microsoft.com/office/spreadsheetml/2015/r # extlst namespaces adec http://schemas.microsoft.com/office/drawing/2017/decorative +asvg http://schemas.microsoft.com/office/drawing/2016/SVG/main # xls14Lst for features introduced by excel 2010 xls14Lst http://schemas.microsoft.com/office/spreadsheetml/2009/9/main diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt index 56e17dc35c22..47d6b07f2470 100644 --- a/oox/source/token/tokens.txt +++ b/oox/source/token/tokens.txt @@ -682,6 +682,7 @@ aspectratio assign asst asteriskTotals +asvg atEnd atLeast atMost @@ -5091,6 +5092,7 @@ suppressTopSpacing suppressTopSpacingWP surface3DChart surfaceChart +svgBlip swAng swCell swapBordersFacingPages |