Initial svg support.
This commit is contained in:
parent
101bfb4207
commit
65ac927929
22 changed files with 284 additions and 30 deletions
|
@ -9,6 +9,8 @@ list(APPEND publishing_HEADERS
|
||||||
pdf/PdfStream.h
|
pdf/PdfStream.h
|
||||||
pdf/PdfXRefTable.h
|
pdf/PdfXRefTable.h
|
||||||
pdf/PdfWriter.h
|
pdf/PdfWriter.h
|
||||||
|
plotting/GraphPlotter.h
|
||||||
|
plotting/SvgConverter.h
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND publishing_LIB_INCLUDES
|
list(APPEND publishing_LIB_INCLUDES
|
||||||
|
@ -22,6 +24,8 @@ list(APPEND publishing_LIB_INCLUDES
|
||||||
pdf/PdfStream.cpp
|
pdf/PdfStream.cpp
|
||||||
pdf/PdfXRefTable.cpp
|
pdf/PdfXRefTable.cpp
|
||||||
pdf/PdfWriter.cpp
|
pdf/PdfWriter.cpp
|
||||||
|
plotting/GraphPlotter.h
|
||||||
|
plotting/SvgConverter.h
|
||||||
DocumentConverter.cpp
|
DocumentConverter.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,6 +36,6 @@ target_include_directories(publishing PUBLIC
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/pdf"
|
"${CMAKE_CURRENT_SOURCE_DIR}/pdf"
|
||||||
)
|
)
|
||||||
set_target_properties( publishing PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
set_target_properties( publishing PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||||
target_link_libraries( publishing PUBLIC core web)
|
target_link_libraries( publishing PUBLIC core web graphics visual_elements)
|
||||||
|
|
||||||
set_property(TARGET publishing PROPERTY FOLDER src)
|
set_property(TARGET publishing PROPERTY FOLDER src)
|
0
src/publishing/plotting/GraphPlotter.cpp
Normal file
0
src/publishing/plotting/GraphPlotter.cpp
Normal file
0
src/publishing/plotting/GraphPlotter.h
Normal file
0
src/publishing/plotting/GraphPlotter.h
Normal file
0
src/publishing/plotting/SvgConverter.cpp
Normal file
0
src/publishing/plotting/SvgConverter.cpp
Normal file
0
src/publishing/plotting/SvgConverter.h
Normal file
0
src/publishing/plotting/SvgConverter.h
Normal file
|
@ -27,6 +27,11 @@ list(APPEND web_LIB_INCLUDES
|
||||||
html/elements/HtmlHeadElement.cpp
|
html/elements/HtmlHeadElement.cpp
|
||||||
html/elements/HtmlBodyElement.cpp
|
html/elements/HtmlBodyElement.cpp
|
||||||
html/elements/HtmlParagraphElement.cpp
|
html/elements/HtmlParagraphElement.cpp
|
||||||
|
svg/SvgDocument.cpp
|
||||||
|
svg/SvgWriter.cpp
|
||||||
|
svg/SvgShapeElement.cpp
|
||||||
|
svg/SvgElement.cpp
|
||||||
|
svg/elements/SvgShapeElements.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# add the executable
|
# add the executable
|
||||||
|
@ -34,6 +39,8 @@ add_library(${MODULE_NAME} SHARED ${web_LIB_INCLUDES})
|
||||||
|
|
||||||
target_include_directories(web PUBLIC
|
target_include_directories(web PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/svg
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/svg/elements
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/xml
|
${CMAKE_CURRENT_SOURCE_DIR}/xml
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/xml/xml-elements
|
${CMAKE_CURRENT_SOURCE_DIR}/xml/xml-elements
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/html
|
${CMAKE_CURRENT_SOURCE_DIR}/html
|
||||||
|
@ -41,5 +48,5 @@ target_include_directories(web PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/markdown
|
${CMAKE_CURRENT_SOURCE_DIR}/markdown
|
||||||
)
|
)
|
||||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src)
|
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src)
|
||||||
target_link_libraries(${MODULE_NAME} PUBLIC core compiler)
|
target_link_libraries(${MODULE_NAME} PUBLIC core compiler geometry)
|
||||||
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
|
@ -5,9 +5,8 @@ std::string HtmlParagraphElement::toString(unsigned depth, bool keepInline) cons
|
||||||
const auto prefix = std::string(2*depth, ' ');
|
const auto prefix = std::string(2*depth, ' ');
|
||||||
|
|
||||||
auto content = prefix + "<" + getTagName();
|
auto content = prefix + "<" + getTagName();
|
||||||
for (std::size_t idx=0; idx< getNumAttributes(); idx++)
|
for (const auto& [key, attribute] : getAttributes())
|
||||||
{
|
{
|
||||||
auto attribute = getAttribute(idx);
|
|
||||||
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
|
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include "SvgDocument.h"
|
||||||
|
|
||||||
|
#include "XmlAttribute.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
SvgDocument::SvgDocument()
|
||||||
|
: XmlDocument()
|
||||||
|
{
|
||||||
|
auto root = XmlElement::Create("svg");
|
||||||
|
|
||||||
|
auto xmlns = std::make_unique<XmlAttribute>("xmlns");
|
||||||
|
xmlns->setValue("http://www.w3.org/2000/svg");
|
||||||
|
|
||||||
|
root->addAttribute(std::move(xmlns));
|
||||||
|
|
||||||
|
setRoot(std::move(root));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgDocument::setViewBox(unsigned x, unsigned y, unsigned w, unsigned h)
|
||||||
|
{
|
||||||
|
auto viewbox = std::make_unique<XmlAttribute>("viewBox");
|
||||||
|
std::stringstream sstr;
|
||||||
|
sstr << x << " " << y << " " << w << " " << h;
|
||||||
|
viewbox->setValue(sstr.str());
|
||||||
|
|
||||||
|
getRoot()->addAttribute(std::move(viewbox));
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "XmlDocument.h"
|
||||||
|
|
||||||
|
class SvgDocument : public XmlDocument
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SvgDocument();
|
||||||
|
void setViewBox(unsigned x, unsigned y, unsigned w, unsigned h);
|
||||||
|
};
|
7
src/web/svg/SvgElement.cpp
Normal file
7
src/web/svg/SvgElement.cpp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#include "SvgElement.h"
|
||||||
|
|
||||||
|
SvgElement::SvgElement(const std::string& tagName)
|
||||||
|
: XmlElement(tagName)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
9
src/web/svg/SvgElement.h
Normal file
9
src/web/svg/SvgElement.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "XmlElement.h"
|
||||||
|
|
||||||
|
class SvgElement : public XmlElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SvgElement(const std::string& tagName);
|
||||||
|
};
|
41
src/web/svg/SvgShapeElement.cpp
Normal file
41
src/web/svg/SvgShapeElement.cpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include "SvgShapeElement.h"
|
||||||
|
|
||||||
|
#include "XmlAttribute.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
SvgShapeElement::SvgShapeElement(const std::string& tagName)
|
||||||
|
: SvgElement(tagName)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgShapeElement::setFill(const Color& fill)
|
||||||
|
{
|
||||||
|
auto attr = std::make_unique<XmlAttribute>("fill");
|
||||||
|
|
||||||
|
std::stringstream sstr;
|
||||||
|
sstr << "rgb(" << fill.getR() << "," << fill.getG() << "," << fill.getB() << ")";
|
||||||
|
attr->setValue(sstr.str());
|
||||||
|
|
||||||
|
addAttribute(std::move(attr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgShapeElement::setStrokeWidth(unsigned width)
|
||||||
|
{
|
||||||
|
auto attr = std::make_unique<XmlAttribute>("stroke-width");
|
||||||
|
attr->setValue(std::to_string(width));
|
||||||
|
|
||||||
|
addAttribute(std::move(attr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgShapeElement::setStrokeColor(const Color& stroke)
|
||||||
|
{
|
||||||
|
auto attr = std::make_unique<XmlAttribute>("stroke");
|
||||||
|
|
||||||
|
std::stringstream sstr;
|
||||||
|
sstr << "rgb(" << stroke.getR() << "," << stroke.getG() << "," << stroke.getB() << ")";
|
||||||
|
attr->setValue(sstr.str());
|
||||||
|
|
||||||
|
addAttribute(std::move(attr));
|
||||||
|
}
|
17
src/web/svg/SvgShapeElement.h
Normal file
17
src/web/svg/SvgShapeElement.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SvgElement.h"
|
||||||
|
#include "Color.h"
|
||||||
|
|
||||||
|
class SvgShapeElement : public SvgElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SvgShapeElement(const std::string& tagName);
|
||||||
|
|
||||||
|
void setFill(const Color& fill);
|
||||||
|
|
||||||
|
void setStrokeWidth(unsigned width);
|
||||||
|
|
||||||
|
void setStrokeColor(const Color& stroke);
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "SvgWriter.h"
|
||||||
|
|
||||||
|
#include "SvgDocument.h"
|
||||||
|
|
||||||
|
std::string SvgWriter::toString(SvgDocument* document)
|
||||||
|
{
|
||||||
|
std::string content = "";
|
||||||
|
if (auto root = document->getRoot())
|
||||||
|
{
|
||||||
|
content += root->toString();
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class SvgDocument;
|
||||||
|
|
||||||
|
class SvgWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string toString(SvgDocument* document);
|
||||||
|
};
|
62
src/web/svg/elements/SvgShapeElements.cpp
Normal file
62
src/web/svg/elements/SvgShapeElements.cpp
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#include "SvgShapeElements.h"
|
||||||
|
|
||||||
|
SvgCircle::SvgCircle()
|
||||||
|
: SvgShapeElement("circle")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgCircle::setLocation(const DiscretePoint& loc)
|
||||||
|
{
|
||||||
|
auto cx = std::make_unique<XmlAttribute>("cx");
|
||||||
|
auto cy = std::make_unique<XmlAttribute>("cy");
|
||||||
|
|
||||||
|
cx->setValue(std::to_string(loc.GetX()));
|
||||||
|
cy->setValue(std::to_string(loc.GetY()));
|
||||||
|
|
||||||
|
addAttribute(std::move(cx));
|
||||||
|
addAttribute(std::move(cy));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgCircle::setRadius(unsigned rad)
|
||||||
|
{
|
||||||
|
auto r = std::make_unique<XmlAttribute>("r");
|
||||||
|
r->setValue(std::to_string(rad));
|
||||||
|
addAttribute(std::move(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
SvgRectangle::SvgRectangle()
|
||||||
|
: SvgShapeElement("rect")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgRectangle::setLocation(const DiscretePoint& loc)
|
||||||
|
{
|
||||||
|
auto x = std::make_unique<XmlAttribute>("x");
|
||||||
|
auto y = std::make_unique<XmlAttribute>("y");
|
||||||
|
|
||||||
|
x->setValue(std::to_string(loc.GetX()));
|
||||||
|
y->setValue(std::to_string(loc.GetY()));
|
||||||
|
|
||||||
|
addAttribute(std::move(x));
|
||||||
|
addAttribute(std::move(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgRectangle::setWidth(unsigned w)
|
||||||
|
{
|
||||||
|
auto width = std::make_unique<XmlAttribute>("width");
|
||||||
|
|
||||||
|
width->setValue(std::to_string(w));
|
||||||
|
|
||||||
|
addAttribute(std::move(width));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgRectangle::setHeight(unsigned h)
|
||||||
|
{
|
||||||
|
auto height = std::make_unique<XmlAttribute>("height");
|
||||||
|
|
||||||
|
height->setValue(std::to_string(h));
|
||||||
|
|
||||||
|
addAttribute(std::move(height));
|
||||||
|
}
|
28
src/web/svg/elements/SvgShapeElements.h
Normal file
28
src/web/svg/elements/SvgShapeElements.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SvgShapeElement.h"
|
||||||
|
#include "DiscretePoint.h"
|
||||||
|
|
||||||
|
#include "XmlAttribute.h"
|
||||||
|
|
||||||
|
class SvgCircle : public SvgShapeElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SvgCircle();
|
||||||
|
|
||||||
|
void setLocation(const DiscretePoint& loc);
|
||||||
|
|
||||||
|
void setRadius(unsigned rad);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SvgRectangle : public SvgShapeElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SvgRectangle();
|
||||||
|
|
||||||
|
void setLocation(const DiscretePoint& loc);
|
||||||
|
|
||||||
|
void setWidth(unsigned width);
|
||||||
|
|
||||||
|
void setHeight(unsigned height);
|
||||||
|
};
|
|
@ -9,9 +9,8 @@ std::string XmlWriter::toString(XmlDocument* document)
|
||||||
if (auto prolog = document->getProlog())
|
if (auto prolog = document->getProlog())
|
||||||
{
|
{
|
||||||
content += "<?xml";
|
content += "<?xml";
|
||||||
for (std::size_t idx=0; idx< prolog->getNumAttributes(); idx++)
|
for (const auto& [key, attribute] : prolog->getAttributes())
|
||||||
{
|
{
|
||||||
auto attribute = prolog->getAttribute(idx);
|
|
||||||
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
|
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
|
||||||
}
|
}
|
||||||
content += "?>\n";
|
content += "?>\n";
|
||||||
|
|
|
@ -31,7 +31,7 @@ void XmlElement::addChild(XmlElementPtr child)
|
||||||
|
|
||||||
void XmlElement::addAttribute(XmlAttributePtr attribute)
|
void XmlElement::addAttribute(XmlAttributePtr attribute)
|
||||||
{
|
{
|
||||||
mAttributes.push_back(std::move(attribute));
|
mAttributes[attribute->getName()] = std::move(attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& XmlElement::getTagName() const
|
const std::string& XmlElement::getTagName() const
|
||||||
|
@ -64,28 +64,16 @@ XmlElement* XmlElement::getFirstChildWithTagName(const std::string& tag)
|
||||||
|
|
||||||
XmlAttribute* XmlElement::getAttribute(const std::string& attributeName) const
|
XmlAttribute* XmlElement::getAttribute(const std::string& attributeName) const
|
||||||
{
|
{
|
||||||
for(const auto& attribute : mAttributes)
|
if (auto iter = mAttributes.find(attributeName); iter != mAttributes.end())
|
||||||
{
|
{
|
||||||
if(attribute->getName() == attributeName)
|
return iter->second.get();
|
||||||
{
|
|
||||||
return attribute.get();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlAttribute* XmlElement::getAttribute(std::size_t index) const
|
const std::unordered_map<std::string, XmlAttributePtr>& XmlElement::getAttributes() const
|
||||||
{
|
{
|
||||||
if(index < mAttributes.size())
|
return mAttributes;
|
||||||
{
|
|
||||||
return mAttributes[index].get();
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t XmlElement::getNumAttributes() const
|
|
||||||
{
|
|
||||||
return mAttributes.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t XmlElement::getNumChildren() const
|
std::size_t XmlElement::getNumChildren() const
|
||||||
|
@ -105,9 +93,8 @@ std::string XmlElement::toString(unsigned depth, bool keepInline) const
|
||||||
std::string line_ending = keepInline ? "" : "\n";
|
std::string line_ending = keepInline ? "" : "\n";
|
||||||
|
|
||||||
auto content = prefix + "<" + getTagName();
|
auto content = prefix + "<" + getTagName();
|
||||||
for (std::size_t idx=0; idx< getNumAttributes(); idx++)
|
for (const auto& [key, attribute] : getAttributes())
|
||||||
{
|
{
|
||||||
auto attribute = getAttribute(idx);
|
|
||||||
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
|
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
class XmlAttribute;
|
class XmlAttribute;
|
||||||
using XmlAttributePtr = std::unique_ptr<XmlAttribute>;
|
using XmlAttributePtr = std::unique_ptr<XmlAttribute>;
|
||||||
|
@ -23,8 +22,7 @@ public:
|
||||||
const std::string& getTagName() const;
|
const std::string& getTagName() const;
|
||||||
const std::string& getText() const;
|
const std::string& getText() const;
|
||||||
XmlAttribute* getAttribute(const std::string& attribute) const;
|
XmlAttribute* getAttribute(const std::string& attribute) const;
|
||||||
XmlAttribute* getAttribute(std::size_t index) const;
|
const std::unordered_map<std::string, XmlAttributePtr>& getAttributes() const;
|
||||||
std::size_t getNumAttributes() const;
|
|
||||||
|
|
||||||
std::size_t getNumChildren() const;
|
std::size_t getNumChildren() const;
|
||||||
XmlElement* getChild(std::size_t index) const;
|
XmlElement* getChild(std::size_t index) const;
|
||||||
|
@ -40,7 +38,7 @@ protected:
|
||||||
std::string mTagName;
|
std::string mTagName;
|
||||||
std::string mText;
|
std::string mText;
|
||||||
|
|
||||||
std::vector<XmlAttributePtr> mAttributes;
|
std::unordered_map<std::string, XmlAttributePtr> mAttributes;
|
||||||
std::vector<std::unique_ptr<XmlElement> > mChildren;
|
std::vector<std::unique_ptr<XmlElement> > mChildren;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
set(WEB_UNIT_TEST_FILES
|
set(WEB_UNIT_TEST_FILES
|
||||||
web/TestMarkdownParser.cpp
|
web/TestMarkdownParser.cpp
|
||||||
web/TestXmlParser.cpp
|
web/TestXmlParser.cpp
|
||||||
|
web/TestSvgWriter.cpp
|
||||||
PARENT_SCOPE
|
PARENT_SCOPE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
33
test/web/TestSvgWriter.cpp
Normal file
33
test/web/TestSvgWriter.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include "SvgWriter.h"
|
||||||
|
#include "SvgDocument.h"
|
||||||
|
#include "SvgShapeElements.h"
|
||||||
|
|
||||||
|
#include "File.h"
|
||||||
|
|
||||||
|
#include "TestFramework.h"
|
||||||
|
#include "TestUtils.h"
|
||||||
|
|
||||||
|
TEST_CASE(TestSvgWriter, "web")
|
||||||
|
{
|
||||||
|
auto document = std::make_unique<SvgDocument>();
|
||||||
|
document->setViewBox(0, 0, 100, 100);
|
||||||
|
|
||||||
|
auto circle = std::make_unique<SvgCircle>();
|
||||||
|
circle->setRadius(20);
|
||||||
|
circle->setLocation({10, 30});
|
||||||
|
circle->setFill({255, 0, 0});
|
||||||
|
document->getRoot()->addChild(std::move(circle));
|
||||||
|
|
||||||
|
auto rectangle = std::make_unique<SvgRectangle>();
|
||||||
|
rectangle->setLocation({50, 70});
|
||||||
|
rectangle->setWidth(5);
|
||||||
|
rectangle->setHeight(10);
|
||||||
|
rectangle->setFill({0, 0, 255});
|
||||||
|
document->getRoot()->addChild(std::move(rectangle));
|
||||||
|
|
||||||
|
SvgWriter writer;
|
||||||
|
auto content = writer.toString(document.get());
|
||||||
|
|
||||||
|
auto outFile = std::make_unique<File>(TestUtils::getTestOutputDir(__FILE__) / "test_out.svg");
|
||||||
|
outFile->writeText(content);
|
||||||
|
}
|
Loading…
Reference in a new issue