Skip to content

Commit 5b97c6e

Browse files
OnetchouDSCaskey
authored andcommitted
feat: custom SVG generator able to create a single SVG from multiple scenes, each scene being in a different group in the svg
1 parent 6528274 commit 5b97c6e

File tree

5 files changed

+248
-16
lines changed

5 files changed

+248
-16
lines changed

‎src/app/seamly2d/mainwindowsnogui.cpp‎

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
#include "../vpatterndb/measurements_def.h"
6868
#include "../vtools/tools/vabstracttool.h"
6969
#include "../vtools/tools/pattern_piece_tool.h"
70+
#include "../../libs/vformat/svg_generator.h"
7071

7172
#include <QFileDialog>
7273
#include <QFileInfo>
@@ -888,21 +889,9 @@ QList<QGraphicsScene *> MainWindowsNoGUI::CreateScenes(const QList<QGraphicsItem
888889
*/
889890
void MainWindowsNoGUI::exportSVG(const QString &name, QGraphicsRectItem *paper, QGraphicsScene *scene) const
890891
{
891-
QSvgGenerator generator;
892-
generator.setFileName(name);
893-
generator.setSize(paper->rect().size().toSize());
894-
generator.setViewBox(paper->rect());
895-
generator.setTitle(tr("Pattern"));
896-
generator.setDescription(doc->GetDescription());
897-
generator.setResolution(static_cast<int>(PrintDPI));
898-
QPainter painter;
899-
painter.begin(&generator);
900-
painter.setFont( QFont( "Arial", 8, QFont::Normal ) );
901-
painter.setRenderHint(QPainter::Antialiasing, true);
902-
//painter.setPen(QPen(Qt::black, widthHairLine, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
903-
painter.setBrush ( QBrush ( Qt::NoBrush ) );
904-
scene->render(&painter, paper->rect(), paper->rect(), Qt::IgnoreAspectRatio);
905-
painter.end();
892+
SvgGenerator svgGenerator(paper, name, doc->GetDescription(), static_cast<int>(PrintDPI));
893+
svgGenerator.addSvgFromScene(scene);
894+
svgGenerator.generate();
906895
}
907896

908897
//---------------------------------------------------------------------------------------------------------------------

‎src/libs/vformat/svg_generator.cpp‎

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/******************************************************************************
2+
** @file svg_generator.cpp
3+
** @author Evans PERRET
4+
** @date September 21, 2024
5+
**
6+
** @brief
7+
** @copyright
8+
** This source code is part of the Seamly2D project, a pattern making
9+
** program, whose allow create and modeling patterns of clothing.
10+
** Copyright (C) 2013-2022 Seamly2D project
11+
** <https://github.com/fashionfreedom/seamly2d> All Rights Reserved.
12+
**
13+
** Seamly2D is free software: you can redistribute it and/or modify
14+
** it under the terms of the GNU General Public License as published by
15+
** the Free Software Foundation, either version 3 of the License, or
16+
** (at your option) any later version.
17+
**
18+
** Seamly2D is distributed in the hope that it will be useful,
19+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
20+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+
** GNU General Public License for more details.
22+
**
23+
** You should have received a copy of the GNU General Public License
24+
** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
25+
**
26+
*****************************************************************************/
27+
28+
#include "svg_generator.h"
29+
#include <QFile>
30+
#include <QDir>
31+
#include <QDebug>
32+
#include <QSvgGenerator>
33+
#include <QGraphicsItem>
34+
#include <QPainter>
35+
#include <QFileInfo>
36+
37+
SvgGenerator::SvgGenerator(QGraphicsRectItem *paper, QString name, QString description, int resolution):
38+
m_svgCounter(0),
39+
m_paper(paper),
40+
m_filepath(name),
41+
m_description(description),
42+
m_resolution(resolution),
43+
m_tempSvgPrefix("tempSvg")
44+
{
45+
QFileInfo fileInfo(m_filepath);
46+
m_folderPath = fileInfo.absolutePath();
47+
m_name = fileInfo.baseName();
48+
m_tempSvgFolderName = m_tempSvgPrefix + "_" + m_name;
49+
}
50+
51+
52+
bool SvgGenerator::loadSvgIntoDom(QDomDocument &domDocument, const QString &filePath)
53+
{
54+
QFile file(filePath);
55+
if (!file.open(QIODevice::ReadOnly)) {
56+
qDebug() << "Error : Impossible to open the SVG file :" << filePath;
57+
return false;
58+
}
59+
if (!domDocument.setContent(&file)) {
60+
qDebug() << "Error : Impossible to load the SVG content in the QDomDocument.";
61+
file.close();
62+
return false;
63+
}
64+
file.close();
65+
return true;
66+
}
67+
68+
QDomDocument SvgGenerator::mergeSvgDoms(const QList<QDomDocument> &domList)
69+
{
70+
/*domList contains DOM representations of multiple SVG
71+
Assuming each svg contains a main group containing every graphical item of the svg,
72+
this function adds to the first svg of the list all the main groups of the other svgs,
73+
thus creating a single svg with each svg of the list in it, every svg being in its own group.
74+
This function is used in order to create svgs containing groups*/
75+
76+
if (domList.isEmpty()) {
77+
qDebug() << "Error : the SVG list is empty";
78+
return QDomDocument();
79+
}
80+
81+
QDomDocument mergedSvg = domList.at(0);
82+
83+
QDomElement mergedSvgRoot = mergedSvg.documentElement();
84+
if (mergedSvgRoot.tagName() != "svg") {
85+
qDebug() << "Error : the first SVG does not contain a <svg> tag.";
86+
return QDomDocument();
87+
}
88+
89+
for (int i = 1; i < domList.size(); ++i) {
90+
QDomDocument domSvg = domList.at(i);
91+
QDomElement svgRoot = domSvg.documentElement();
92+
if (svgRoot.tagName() != "svg") {
93+
qDebug() << "Error : the SVG does not contain a <svg> tag.";
94+
return QDomDocument();
95+
}
96+
QDomNodeList svgGroups = svgRoot.elementsByTagName("g");
97+
if (svgGroups.isEmpty()) {
98+
qDebug() << "Error : the SVG does not contain a <g> tag.";
99+
return QDomDocument();
100+
}
101+
QDomElement mainGroup = svgGroups.at(0).toElement();
102+
mergedSvgRoot.appendChild(mainGroup);
103+
}
104+
105+
return mergedSvg;
106+
}
107+
108+
void SvgGenerator::addSvgFromScene(QGraphicsScene *scene)
109+
{
110+
m_svgCounter++;
111+
112+
QSvgGenerator svgGenerator;
113+
svgGenerator.setFileName(getTempFilePath(m_svgCounter));
114+
svgGenerator.setSize(m_paper->rect().size().toSize());
115+
svgGenerator.setViewBox(m_paper->rect());
116+
svgGenerator.setTitle(QObject::tr("Pattern"));
117+
svgGenerator.setDescription(m_description);
118+
svgGenerator.setResolution(m_resolution);
119+
120+
QPainter painter;
121+
painter.begin(&svgGenerator);
122+
painter.setFont( QFont( "Arial", 8, QFont::Normal ) );
123+
painter.setRenderHint(QPainter::Antialiasing, true);
124+
painter.setBrush ( QBrush ( Qt::NoBrush ) );
125+
scene->render(&painter, m_paper->rect(), m_paper->rect(), Qt::IgnoreAspectRatio);
126+
painter.end();
127+
}
128+
129+
130+
void SvgGenerator::generate()
131+
{
132+
QList<QDomDocument> domList;
133+
134+
for(int i = 1; i <= m_svgCounter; i++)
135+
{
136+
QDomDocument domDoc;
137+
QString path = getTempFilePath(i);
138+
QFile file(path);
139+
if (!file.exists()) {
140+
qDebug() << "Error : the SVG file does not exist.";
141+
continue;
142+
}
143+
loadSvgIntoDom(domDoc, path);
144+
domList.append(domDoc);
145+
146+
if (!file.remove()) {
147+
qDebug() << "Error : unable to remove " << path;
148+
}
149+
}
150+
151+
QDomDocument mergedSvg = mergeSvgDoms(domList);
152+
153+
QFile outputFile(m_filepath);
154+
if (!outputFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
155+
qDebug() << "Error : Couldn't write the output file.";
156+
}
157+
158+
QTextStream stream(&outputFile);
159+
stream << mergedSvg.toString();
160+
outputFile.close();
161+
162+
QDir dir(m_folderPath);
163+
if(!dir.rmdir(m_tempSvgFolderName))
164+
{
165+
qDebug() << "Error : Couldn't remove the temp SVG folder.";
166+
}
167+
168+
qDebug() << "Merged SVG Generated!";
169+
}
170+
171+
172+
QString SvgGenerator::getTempFilePath(int id)
173+
{
174+
QDir dir(m_folderPath);
175+
if (!dir.cd(m_tempSvgFolderName))
176+
{
177+
dir.mkdir(m_tempSvgFolderName);
178+
dir.cd(m_tempSvgFolderName);
179+
}
180+
181+
return dir.path() + "/" + m_tempSvgPrefix + "_" + m_name + "_" + QString::number(id) + ".svg";
182+
}

‎src/libs/vformat/svg_generator.h‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/******************************************************************************
2+
** @file svg_generator.h
3+
** @author Evans PERRET
4+
** @date September 21, 2024
5+
**
6+
** @brief
7+
** @copyright
8+
** This source code is part of the Seamly2D project, a pattern making
9+
** program, whose allow create and modeling patterns of clothing.
10+
** Copyright (C) 2013-2022 Seamly2D project
11+
** <https://github.com/fashionfreedom/seamly2d> All Rights Reserved.
12+
**
13+
** Seamly2D is free software: you can redistribute it and/or modify
14+
** it under the terms of the GNU General Public License as published by
15+
** the Free Software Foundation, either version 3 of the License, or
16+
** (at your option) any later version.
17+
**
18+
** Seamly2D is distributed in the hope that it will be useful,
19+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
20+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+
** GNU General Public License for more details.
22+
**
23+
** You should have received a copy of the GNU General Public License
24+
** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
25+
**
26+
*****************************************************************************/
27+
28+
#ifndef SVG_GENERATOR_H
29+
#define SVG_GENERATOR_H
30+
31+
#include <QDomDocument>
32+
#include <QGraphicsScene>
33+
34+
35+
class SvgGenerator
36+
{
37+
public:
38+
SvgGenerator(QGraphicsRectItem *paper, QString name, QString description, int resolution);
39+
void addSvgFromScene(QGraphicsScene *scene);
40+
void generate();
41+
42+
43+
private:
44+
bool loadSvgIntoDom(QDomDocument &domDocument, const QString &filePath);
45+
QDomDocument mergeSvgDoms(const QList<QDomDocument> &domList);
46+
QString getTempFilePath(int id);
47+
48+
int m_svgCounter;
49+
QGraphicsRectItem *m_paper;
50+
QString m_filepath;
51+
QString m_folderPath;
52+
QString m_name;
53+
QString m_description;
54+
int m_resolution;
55+
QString m_tempSvgFolderName;
56+
QString m_tempSvgPrefix;
57+
};
58+
59+
#endif // SVG_GENERATOR_H

‎src/libs/vformat/vformat.pri‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33

44
SOURCES += \
55
$$PWD/measurements.cpp \
6+
$$PWD/svg_generator.cpp \
67
$$PWD/vlabeltemplate.cpp
78

89
*msvc*:SOURCES += $$PWD/stable.cpp
910

1011
HEADERS += \
1112
$$PWD/measurements.h \
1213
$$PWD/stable.h \
14+
$$PWD/svg_generator.h \
1315
$$PWD/vlabeltemplate.h

‎src/libs/vformat/vformat.pro‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ message("Entering vformat.pro")
99
include(../../../common.pri)
1010

1111
# Library work with xml.
12-
QT += xml xmlpatterns printsupport
12+
QT += xml xmlpatterns printsupport svg
1313

1414
# We don't need gui library.
1515
QT -= gui

0 commit comments

Comments
 (0)