summaryrefslogtreecommitdiff
path: root/oox
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2023-12-03 13:21:35 +0900
committerTomaž Vajngerl <quikee@gmail.com>2023-12-04 10:33:34 +0100
commitbfbbf06bcea4d58117c14fd3f3b8743a3714f97e (patch)
treea2f14a18ead422a6ea4ae0afb283c1ea38c42861 /oox
parent09200875ce643e66f293d39bb27630a3fdbb984d (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.cxx103
-rw-r--r--oox/source/token/namespaces-strict.txt1
-rw-r--r--oox/source/token/namespaces.txt1
-rw-r--r--oox/source/token/tokens.txt2
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