summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/oox/export/drawingml.hxx14
-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
-rw-r--r--sw/qa/extras/ooxmlexport/data/SvgImageTest.odtbin0 -> 13608 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport20.cxx27
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx16
-rw-r--r--test/source/xmltesttools.cxx2
9 files changed, 157 insertions, 9 deletions
diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx
index 9028cfdc0f9f..dcbb1b544390 100644
--- a/include/oox/export/drawingml.hxx
+++ b/include/oox/export/drawingml.hxx
@@ -259,16 +259,25 @@ private:
DocumentType meDocumentType;
OUString writeNewEntryToStorage(const Graphic& rGraphic, bool bRelPathToMedia);
+ OUString writeNewSvgEntryToStorage(const Graphic& rGraphic, bool bRelPathToMedia);
public:
+ enum class TypeHint
+ {
+ Detect,
+ SVG
+ };
+
GraphicExport(sax_fastparser::FSHelperPtr pFS, ::oox::core::XmlFilterBase* pFilterBase, DocumentType eDocumentType)
: mpFS(pFS)
, mpFilterBase(pFilterBase)
, meDocumentType(eDocumentType)
{}
- OUString writeToStorage(Graphic const& rGraphic, bool bRelPathToMedia = false);
+ OUString writeToStorage(Graphic const& rGraphic, bool bRelPathToMedia = false, TypeHint eHint = TypeHint::Detect);
+
void writeBlip(Graphic const& rGraphic, std::vector<model::BlipEffect> const& rEffects, bool bRelPathToMedia = false);
+ void writeSvgExtension(OUString const& rSvgRelId);
};
class OOX_DLLPUBLIC DrawingML
@@ -353,7 +362,7 @@ public:
void SetBackgroundDark(bool bIsDark) { mbIsBackgroundDark = bIsDark; }
/// If bRelPathToMedia is true add "../" to image folder path while adding the image relationship
- OUString writeGraphicToStorage(const Graphic &rGraphic , bool bRelPathToMedia = false);
+ OUString writeGraphicToStorage(const Graphic &rGraphic , bool bRelPathToMedia = false, GraphicExport::TypeHint eHint = GraphicExport::TypeHint::Detect);
void WriteColor( ::Color nColor, sal_Int32 nAlpha = MAX_PERCENT );
void WriteColor( const OUString& sColorSchemeName, const css::uno::Sequence< css::beans::PropertyValue >& aTransformations, sal_Int32 nAlpha = MAX_PERCENT );
@@ -516,6 +525,7 @@ public:
const OUString& sRelationshipType,
OUString* pRelationshipId );
+ std::shared_ptr<GraphicExport> createGraphicExport();
};
}
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
diff --git a/sw/qa/extras/ooxmlexport/data/SvgImageTest.odt b/sw/qa/extras/ooxmlexport/data/SvgImageTest.odt
new file mode 100644
index 000000000000..3b37fe7998ef
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/SvgImageTest.odt
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx
index 8b5f6cab824b..263e769297d7 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx
@@ -961,6 +961,33 @@ CPPUNIT_TEST_FIXTURE(Test, testZOrderInHeader)
CPPUNIT_ASSERT(nBackground < nFrontShape);
}
+CPPUNIT_TEST_FIXTURE(Test, testSvgExtensionsSupport)
+{
+ loadAndSave("SvgImageTest.odt");
+
+ xmlDocUniquePtr pXmlDocRels = parseExport("word/_rels/document.xml.rels");
+
+ // Check we have 2 relationships - one for PNG and one for SVG files
+ assertXPath(pXmlDocRels,
+ "/rels:Relationships/rels:Relationship[@Target='media/image1.png']"_ostr, "Id"_ostr,
+ "rId2");
+
+ assertXPath(pXmlDocRels,
+ "/rels:Relationships/rels:Relationship[@Target='media/image2.svg']"_ostr, "Id"_ostr,
+ "rId3");
+
+ // Check there is the extension present
+ xmlDocUniquePtr pXmlDocContent = parseExport("word/document.xml");
+
+ OString aPath(
+ "/w:document/w:body/w:p/w:r/w:drawing/wp:anchor/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip"_ostr);
+ assertXPath(pXmlDocContent, aPath, "embed"_ostr, "rId2");
+
+ assertXPath(pXmlDocContent, aPath + "/a:extLst/a:ext"_ostr, "uri"_ostr,
+ "{96DAC541-7B7A-43D3-8B79-37D633B846F1}");
+ assertXPath(pXmlDocContent, aPath + "/a:extLst/a:ext/asvg:svgBlip"_ostr, "embed"_ostr, "rId3");
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index bf6380b12ccd..8949ffe58a77 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -52,6 +52,7 @@
#include <oox/token/relationship.hxx>
#include <oox/export/vmlexport.hxx>
#include <oox/ole/olehelper.hxx>
+#include <oox/export/drawingml.hxx>
#include <editeng/autokernitem.hxx>
#include <editeng/unoprnms.hxx>
@@ -5181,6 +5182,7 @@ void DocxAttributeOutput::FlyFrameGraphic( const SwGrfNode* pGrfNode, const Size
const SwFrameFormat* pFrameFormat = pGrfNode ? pGrfNode->GetFlyFormat() : pOLEFrameFormat;
// create the relation ID
OString aRelId;
+ OUString sSvgRelId;
sal_Int32 nImageType;
if ( pGrfNode && pGrfNode->IsLinkedFile() )
{
@@ -5216,9 +5218,14 @@ void DocxAttributeOutput::FlyFrameGraphic( const SwGrfNode* pGrfNode, const Size
aGraphic = *pOLENode->GetGraphic();
m_rDrawingML.SetFS(m_pSerializer); // to be sure that we write to the right stream
- OUString aImageId = m_rDrawingML.writeGraphicToStorage(aGraphic, false);
+ auto pGraphicExport = m_rDrawingML.createGraphicExport();
+ OUString aImageId = pGraphicExport->writeToStorage(aGraphic, false);
aRelId = OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8);
+ if (aGraphic.getVectorGraphicData() && aGraphic.getVectorGraphicData()->getType() == VectorGraphicDataType::Svg)
+ {
+ sSvgRelId = pGraphicExport->writeToStorage(aGraphic, false, drawingml::GraphicExport::TypeHint::SVG);
+ }
nImageType = XML_embed;
}
@@ -5354,6 +5361,13 @@ void DocxAttributeOutput::FlyFrameGraphic( const SwGrfNode* pGrfNode, const Size
else if (nMode == GraphicDrawMode::Watermark) //watermark has a brightness/luminance of 0,5 and contrast of -0.7 in LibreOffice
m_pSerializer->singleElementNS( XML_a, XML_lum, XML_bright, OString::number(70000), XML_contrast, OString::number(-70000) );
}
+
+ if (!sSvgRelId.isEmpty())
+ {
+ auto pGraphicExport = m_rDrawingML.createGraphicExport();
+ pGraphicExport->writeSvgExtension(sSvgRelId);
+ }
+
m_pSerializer->endElementNS( XML_a, XML_blip );
if (xShapePropSet)
diff --git a/test/source/xmltesttools.cxx b/test/source/xmltesttools.cxx
index 8f96a399caff..14f953557f5f 100644
--- a/test/source/xmltesttools.cxx
+++ b/test/source/xmltesttools.cxx
@@ -455,6 +455,8 @@ void XmlTestTools::registerOOXMLNamespaces(xmlXPathContextPtr& pXmlXpathCtx)
BAD_CAST("http://schemas.microsoft.com/office/drawing/2012/chart"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xr2"),
BAD_CAST("http://schemas.microsoft.com/office/spreadsheetml/2015/revision2"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("asvg"),
+ BAD_CAST("http://schemas.microsoft.com/office/drawing/2016/SVG/main"));
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */