1 /*
2 * description: converter from xml to png files for new file format
3 * date: 8 may 2009
4 *
5 * Copyright (C) 2010 Thomas Braun <thomas.braun@virtuell-zuhause.de>
6 * Copyright (C) 2013 Jan Sundermeyer <jsundermeyer@sf.net>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23 #include <QDomDocument>
24 #include <QFile>
25 #include <QTextStream>
26 #include <QDebug>
27 #include <QList>
28 #include <QStringList>
29 #include <QTemporaryFile>
30 #include <QImage>
31 #include <QCoreApplication>
32
33 #include <iostream>
34 #include <stdlib.h>
35
36 #include "symbolviewclasses.h"
37
38 /* TODO
39 - more error checking when parsing xml file
40 */
41
readImageComments(const QString & fileName)42 void readImageComments(const QString &fileName)
43 {
44 QImage image;
45 QString output;
46
47 if(image.load(fileName)) {
48 qDebug() << QString("Image %1 has Command _%2_").arg(fileName).arg(image.text("Command"));
49 qDebug() << QString("Image %1 has Comment _%2_").arg(fileName).arg(image.text("Comment"));
50 qDebug() << QString("image %1 has Package _%2_").arg(fileName).arg(image.text("Packages"));
51 qDebug() << QString("Image %1 has CommandUnicode _%2_").arg(fileName).arg(image.text("CommandUnicode"));
52 qDebug() << QString("Image %1 has UnicodePackages _%2_").arg(fileName).arg(image.text("UnicodePackages"));
53 }
54 else {
55 qDebug() << "===readComment=== ERROR " << fileName << " could not be loaded";
56 }
57 }
58
convertUTF8toLatin1String(const QString & string)59 QString convertUTF8toLatin1String(const QString &string){
60
61 QVector<uint> stringAsInt;
62 QString stringAsLatin1;
63
64 stringAsInt = string.toUcs4();
65 QVector<uint>::const_iterator it;
66 for(it = stringAsInt.begin(); it != stringAsInt.end(); it++) {
67 stringAsLatin1 += QString("U+%1,").arg(*it);
68 }
69 return stringAsLatin1;
70 }
71
pkgListToString(const QList<Package> & packages)72 QString pkgListToString(const QList<Package> &packages){
73
74 QString packagesArg, packagesName;
75 int i=0;
76 for(; i < packages.count()-1 ; i++){
77 packagesArg += packages[i].arguments + ',';
78 packagesName += packages[i].name + ',';
79 }
80 if(i<packages.count()){
81 packagesArg += packages[i].arguments;
82 packagesName += packages[i].name;
83 }
84 QString result = ( packagesArg.isEmpty() ? "" : '[' + packagesArg + ']' ) + ( packagesName.isEmpty() ? "" : '{' + packagesName + '}' );
85 return result;
86 }
87
writeSVGComments(const Command & cmd,const QString & fileName)88 void writeSVGComments(const Command &cmd, const QString &fileName)
89 {
90 QString unicodeCommandAsLatin1, commentAsLatin1;
91 QString packagesarg, packages;
92
93 if(!cmd.unicodeCommand.isEmpty()) {
94 unicodeCommandAsLatin1 = convertUTF8toLatin1String(cmd.unicodeCommand);
95 }
96 if(!cmd.comment.isEmpty()) {
97 commentAsLatin1 = convertUTF8toLatin1String(cmd.comment);
98 }
99
100 qDebug() << "fileName is " << fileName;
101 qDebug() << "Command is " << cmd.latexCommand;
102 qDebug() << "unicodeCommandAsLatin1 is " << unicodeCommandAsLatin1;
103 qDebug() << "commentAsLatin1 is " << commentAsLatin1;
104 qDebug() << "comment is " << cmd.comment;
105
106 QFile file( fileName );
107
108 if( !file.open( QIODevice::ReadOnly ) ){
109 qDebug() << "could not open file";
110 return;
111 }
112
113 QStringList fileContent;
114 QTextStream stream(&file);
115 QString line;
116 do {
117 line = stream.readLine();
118 if(!line.isNull())
119 fileContent<<line;
120 } while (!line.isNull());
121
122 file.close();
123
124
125 //QFile file( fn );
126 if( !file.open( QIODevice::WriteOnly ) )
127 return;
128
129 QTextStream ts( &file );
130 for(int i=0;i<fileContent.size();i++){
131 line=fileContent.at(i);
132 if(line.startsWith("<defs>")){
133 QString Command=cmd.latexCommand;
134 Command.replace("<","<");
135 ts<<"<title>"<<Command<<"</title>"<<"\n";
136 QString additional;
137 if (!commentAsLatin1.isEmpty() ) {
138 additional="Comment=\""+commentAsLatin1+"\" ";
139 }
140 if( !unicodeCommandAsLatin1.isEmpty() ) {
141 additional+="CommandUnicode=\""+unicodeCommandAsLatin1+"\" ";
142 additional+="UnicodePackages=\""+pkgListToString(cmd.unicodePackages)+"\" ";
143 }
144 ts<<"<desc "<<"Packages=\""<<pkgListToString(cmd.packages)<<"\" />\n";
145 ts<<"<additionalInfo "<<additional<<" />\n";
146 }
147 ts<<line<<"\n";
148 }
149
150 file.close();
151
152 }
153
readSVG(QString fn)154 int readSVG(QString fn){
155 QFile file( fn );
156
157 if( !file.open( QIODevice::ReadOnly ) ){
158 qDebug() << "could not open file";
159 return -1;
160 }
161
162 QString errorMsg;
163 int errorLine,errorColumn;
164 QDomDocument doc( "svg" );
165
166 if( !doc.setContent( &file,false, &errorMsg, &errorLine, &errorColumn) )
167 {
168 qDebug() << "could not find xml content";
169 qDebug() << errorMsg;
170 qDebug() << "line is " << errorLine;
171 qDebug() << "column is " << errorColumn;
172 file.close();
173 return -2;
174 }
175 file.close();
176
177 // check root element
178 QDomElement root = doc.documentElement();
179 if( root.tagName() != "svg" ) {
180 qDebug() << "wrong format";
181 return -3;
182 }
183 QDomNode n=doc.createElement("title");
184 QDomNode cont=doc.createTextNode("title");
185 n.appendChild(cont);
186 //n.setNodeValue("test a");
187 root.appendChild(n);
188
189 //QFile file( fn );
190 if( !file.open( QIODevice::WriteOnly ) )
191 return -1;
192
193 QTextStream ts( &file );
194 ts << doc.toString();
195
196 file.close();
197 /*
198 QDomNode n = root.firstChild();
199 while( !n.isNull() ) {
200 QDomElement e = n.toElement();
201
202 if( e.isNull() ) {
203 n = n.nextSibling();
204 continue;
205 }
206 qDebug() << "element name is " << e.tagName();
207 //QString tagName = e.tagName();
208 n = n.nextSibling();
209 }*/
210 return 0;
211 }
212
generateSVG(QString latexFile,int index,QString symbolGroupName)213 QString generateSVG(QString latexFile, int index, QString symbolGroupName) {
214
215 QString texfile, texfileWithoutSuffix,svgfile;
216 int latexret, dvipngret;
217
218 QTemporaryFile file("XXXXXX.tex");
219 file.setAutoRemove(false);
220 if (file.open()) {
221 QTextStream t(&file);
222 t.setCodec("UTF-8");
223 t << latexFile;
224
225 texfile = file.fileName();
226 texfileWithoutSuffix = texfile.left(texfile.length() - 4);
227 if(index>0)
228 svgfile = QString("img%1%2.svg").arg(index,3,10,QChar('0')).arg(symbolGroupName);
229 else
230 svgfile=symbolGroupName+".svg";
231 qDebug() << texfile;
232 qDebug() << texfileWithoutSuffix;
233 qDebug() << svgfile;
234
235 file.close();
236 }
237
238 QString texcommand=QString("latex -interaction=batchmode %1").arg(texfile);
239 QString dvipngcommand=QString("dvisvgm -e -o %1 %2.dvi").arg(svgfile).arg(texfileWithoutSuffix);
240
241 qDebug() << texcommand;
242 qDebug() << dvipngcommand;
243
244 latexret = system(texcommand.toLatin1());
245 dvipngret= system(dvipngcommand.toLatin1());
246
247 if (latexret) {
248 qDebug() << "Error compiling the latex file";
249 return QString();
250 }
251
252 if(dvipngret) {
253 qDebug() << "Error producing the pngs";
254 return QString();
255 }
256
257 return svgfile;
258 }
259
writeImageComments(const Command & cmd,const QString & fileName)260 void writeImageComments(const Command &cmd, const QString &fileName)
261 {
262
263 QImage image;
264 QString unicodeCommandAsLatin1, commentAsLatin1;
265 QString packagesarg, packages;
266
267 if(!cmd.unicodeCommand.isEmpty()) {
268 unicodeCommandAsLatin1 = convertUTF8toLatin1String(cmd.unicodeCommand);
269 }
270 if(!cmd.comment.isEmpty()) {
271 commentAsLatin1 = convertUTF8toLatin1String(cmd.comment);
272 }
273
274 qDebug() << "fileName is " << fileName;
275 qDebug() << "Command is " << cmd.latexCommand;
276 qDebug() << "unicodeCommandAsLatin1 is " << unicodeCommandAsLatin1;
277 qDebug() << "commentAsLatin1 is " << commentAsLatin1;
278 qDebug() << "comment is " << cmd.comment;
279
280 if(image.load(fileName)) {
281
282 image.setText("Command",cmd.latexCommand);
283 if( !unicodeCommandAsLatin1.isEmpty() ) {
284 image.setText("CommandUnicode",unicodeCommandAsLatin1);
285 image.setText("UnicodePackages",pkgListToString(cmd.unicodePackages));
286 }
287 if (!commentAsLatin1.isEmpty() ) {
288 image.setText("Comment",commentAsLatin1);
289 }
290
291 image.setText("Packages",pkgListToString(cmd.packages));
292 if(!image.save(fileName,"PNG")) {
293 qDebug() << "Image " << fileName << " could not be saved";
294 exit(1);
295 }
296 }
297 else {
298 qDebug() << "===writeComment=== ERROR " << fileName << "could not be loaded";
299 }
300
301 }
302
generatePNG(QString latexFile,int index,QString symbolGroupName,QString batikConvert)303 QString generatePNG(QString latexFile, int index, QString symbolGroupName,QString batikConvert) {
304
305 QString texfile, texfileWithoutSuffix,pngfile;
306 int latexret, dvipngret,convertret,rmret;
307
308 QTemporaryFile file("XXXXXX.tex");
309 file.setAutoRemove(false);
310 if (file.open()) {
311 QTextStream t(&file);
312 t.setCodec("UTF-8");
313 t << latexFile;
314
315 texfile = file.fileName();
316 texfileWithoutSuffix = texfile.left(texfile.length() - 4);
317 if(index>0)
318 pngfile = QString("img%1%2.png").arg(index,3,10,QChar('0')).arg(symbolGroupName);
319 else
320 pngfile=symbolGroupName+".png";
321 qDebug() << texfile;
322 qDebug() << texfileWithoutSuffix;
323 qDebug() << pngfile;
324
325 file.close();
326 }
327
328 QString texcommand=QString("latex -interaction=batchmode %1").arg(texfile);
329 QString dvipngcommand=QString("dvisvgm -e -o %1.svg %2.dvi").arg(texfileWithoutSuffix).arg(texfileWithoutSuffix);
330 QString convertCommand=QString("%1 %2.svg %3").arg(batikConvert).arg(texfileWithoutSuffix).arg(pngfile);
331 QString removeCommand=QString("rm %1.svg").arg(texfileWithoutSuffix);
332 //QString dvipngcommand=QString("dvipng --strict --picky --freetype -x 1440 -bg Transparent -D 600 -O -1.2in,-1.2in -T bbox -z 6 -o %1 %2.dvi").arg(pngfile).arg(texfileWithoutSuffix);
333
334 qDebug() << texcommand;
335 qDebug() << dvipngcommand;
336 qDebug() << convertCommand;
337
338 latexret = system(texcommand.toLatin1());
339 dvipngret= system(dvipngcommand.toLatin1());
340 convertret= system(convertCommand.toLatin1());
341 rmret=system(removeCommand.toLatin1());
342
343 if (latexret) {
344 qDebug() << "Error compiling the latex file";
345 return QString();
346 }
347
348 if(dvipngret) {
349 qDebug() << "Error producing the svg";
350 return QString();
351 }
352
353 if(convertret) {
354 qDebug() << "Error converting svg to png";
355 return QString();
356 }
357 if(rmret) {
358 qDebug() << "Error removing svg";
359 return QString();
360 }
361
362 return pngfile;
363 }
364
generateLatexFile(const Preamble & preamble,const Command & cmd)365 QString generateLatexFile(const Preamble &preamble, const Command &cmd)
366 {
367 QString output;
368 Package pkg;
369 QString cmdString;
370
371 output += QString("\\documentclass[%1]{%2}\n").arg(preamble.classArguments).arg(preamble.className);
372 output += '\n';
373 output += preamble.additional;
374 output += '\n';
375
376 for(int i=0; i < cmd.packages.count(); i++){
377 pkg = cmd.packages[i];
378 if(pkg.arguments.isEmpty()) {
379 output += QString("\\usepackage{%1}\n").arg(pkg.name);
380 }
381 else{
382 output += QString("\\usepackage[%1]{%2}\n").arg(pkg.arguments).arg(pkg.name);
383 }
384 }
385
386 output += "\\begin{document}\n";
387 output += '\n';
388 if(!cmd.iconMode)
389 output += "\\special{dvisvgm:bbox 0 0}\n";
390 cmdString = !cmd.ImageCommand.isEmpty() ? cmd.ImageCommand : cmd.latexCommand;
391 output += cmd.mathMode ? QString("\\ensuremath{%1}\n").arg(cmdString) : QString("%1\n").arg(cmdString);
392 output += '\n';
393 output += "\\end{document}\n";
394
395 return output;
396 }
397
getAllPackages(const QDomElement & e)398 QList<Package> getAllPackages(const QDomElement &e){
399
400 QList<Package> packages;
401 Package pkg;
402 QDomElement element;
403
404 if(e.isNull()){
405 return packages;
406 }
407
408 QDomNodeList cmdNodes = e.childNodes();
409
410 for(int i=0; i < cmdNodes.count();i++) {
411 element = cmdNodes.item(i).toElement();
412 if( element.tagName()== "package") {
413 pkg.name = element.firstChildElement("name").text();
414 pkg.arguments = element.firstChildElement("arguments").text();
415 packages.append(pkg);
416 qDebug() << "pkg.name is " << pkg.name;
417 qDebug() << "pkg.arguments is " << pkg.arguments;
418 }
419 }
420 return packages;
421 }
422
getCommandDefinition(const QDomElement & e,QList<Package> unicodePackages)423 Command getCommandDefinition(const QDomElement &e, QList<Package> unicodePackages)
424 {
425 if(e.isNull()) {
426 return Command();
427 }
428
429 Package pkg;
430 Command cmd;
431
432 cmd.unicodePackages = unicodePackages;
433 cmd.packages = getAllPackages(e);
434 cmd.mathMode = e.firstChildElement("mathMode").text() == "true" ? true : false;
435 cmd.forcePNG = e.firstChildElement("forcePNG").text() == "true" ? true : false;
436 cmd.iconMode = e.firstChildElement("iconMode").text() == "true" ? true : false;
437 cmd.name = e.firstChildElement("name").text();
438 qDebug()<<cmd.iconMode;
439 cmd.comment = e.firstChildElement("comment").text();
440 cmd.latexCommand = e.firstChildElement("latexCommand").text();
441 cmd.unicodeCommand = e.firstChildElement("unicodeCommand").text();
442 cmd.ImageCommand = e.firstChildElement("imageCommand").text();
443
444 qDebug() << QString("cmd: latexCommand=%1, unicodeCommand=%2, imageCommand=%3, comment=%4, mathmode=%5").arg(cmd.latexCommand).arg(cmd.unicodeCommand).arg(cmd.ImageCommand).arg(cmd.comment).arg(cmd.mathMode);
445
446 if(cmd.packages.count() > 0 ){
447 qDebug() << "packages are";
448 for(int i=0; i < cmd.packages.count(); i++){
449 qDebug() << QString("name=%1, arguments=%2").arg(cmd.packages[i].name).arg(cmd.packages[i].arguments);
450 }
451 }
452 else{
453 qDebug() << "no packages to include";
454 }
455
456 return cmd;
457 }
458
usage()459 void usage(){
460
461 qDebug() << QString("usage: gesymb-ng mySymbols.xml path/to/batikConvert");
462 exit(1);
463 }
464
main(int argc,char ** argv)465 int main(int argc, char** argv)
466 {
467 Preamble preamble;
468 Version version;
469 QList<Command> commands;
470 QString symbolGroupName;
471 QList<Package> unicodePkgList;
472
473 if(argc < 3){
474 usage();
475 }
476 QFile file( argv[1] );
477 QString batik=argv[2];
478
479 if( !file.open( QIODevice::ReadOnly ) ){
480 qDebug() << "could not open file";
481 return -1;
482 }
483
484 QString errorMsg;
485 int errorLine,errorColumn;
486 QDomDocument doc( "KileSymbolSources" );
487
488 if( !doc.setContent( &file,false, &errorMsg, &errorLine, &errorColumn) )
489 {
490 qDebug() << "could not find xml content";
491 qDebug() << errorMsg;
492 qDebug() << "line is " << errorLine;
493 qDebug() << "column is " << errorColumn;
494 file.close();
495 return -2;
496 }
497 file.close();
498
499 // check root element
500 QDomElement root = doc.documentElement();
501 if( root.tagName() != "symbols" ) {
502 qDebug() << "wrong format";
503 return -3;
504 }
505
506 QDomNode n = root.firstChild();
507 while( !n.isNull() ) {
508 QDomElement e = n.toElement();
509
510 if( e.isNull() ) {
511 n = n.nextSibling();
512 continue;
513 }
514 qDebug() << "element name is " << e.tagName();
515 QString tagName = e.tagName();
516
517 if( tagName == "formatVersion" ){
518 version.major = e.attribute("major");
519 version.minor = e.attribute("minor");
520 }
521 else if( tagName == "symbolGroupName" ){
522 symbolGroupName = e.text();
523 }
524 else if(tagName == "preamble"){
525 preamble.className = e.firstChildElement("class").text();
526 preamble.classArguments = e.firstChildElement("arguments").text();
527 preamble.additional= e.firstChildElement("additional").text();
528
529 qDebug() << "class is " << preamble.className;
530 qDebug() << "arguments is " << preamble.classArguments;
531 qDebug() << "additional is " << preamble.additional;
532
533 }
534 else if( tagName == "unicodeCommandPackages") {
535 unicodePkgList = getAllPackages(e);
536 }
537 else if( tagName == "commandDefinition" ){
538 commands.append(getCommandDefinition(e,unicodePkgList));
539 }
540 else{
541 qDebug() << "unexpected node: " << tagName;
542 }
543 n = n.nextSibling();
544 }
545
546 QString content,pngfile;
547 for(int i=0; i < commands.count();i++) {
548 content = generateLatexFile(preamble,commands[i]);
549 qDebug() << content;
550 if(commands[i].forcePNG){
551 if(commands[i].name.isEmpty())
552 pngfile = generatePNG(content,i+1,symbolGroupName,batik);
553 else
554 pngfile = generatePNG(content,-1,commands[i].name,batik);
555 writeImageComments(commands[i],pngfile);
556 }else{
557 if(commands[i].name.isEmpty())
558 pngfile = generateSVG(content,i+1,symbolGroupName);
559 else
560 pngfile = generateSVG(content,-1,commands[i].name);
561 writeSVGComments(commands[i],pngfile);
562 }
563 //readImageComments(pngfile);
564 }
565
566 }
567