1 /**\r
2 *\r
3 * This is a small experimental class for converting between\r
4 * SVG and OpenDocument .odg files. This code is not intended\r
5 * to be a permanent solution for SVG-to-ODG conversion. Rather,\r
6 * it is a quick-and-easy test bed for ideas which will be later\r
7 * recoded into C++.\r
8 *\r
9 * ---------------------------------------------------------------------\r
10 *\r
11 * SvgOdg - A program to experiment with conversions between SVG and ODG\r
12 * Copyright (C) 2006 Bob Jamison\r
13 *\r
14 * This program is free software; you can redistribute it and/or modify\r
15 * it under the terms of the GNU General Public License as published by\r
16 * the Free Software Foundation; either version 3 of the License, or\r
17 * (at your option) any later version.\r
18 *\r
19 * This program is distributed in the hope that it will be useful,\r
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
22 * GNU General Public License for more details.\r
23 *\r
24 * You should have received a copy of the GNU General Public License\r
25 * along with this program; if not, write to the Free Software Foundation,\r
26 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
27 *\r
28 * For more information, please write to rwjj@earthlink.net\r
29 *\r
30 */\r
31 \r
32 \r
33 /**\r
34 *\r
35 */\r
36 public class SvgOdg\r
37 {\r
38 \r
39 \r
40 \r
41 /**\r
42 * Namespace declarations\r
43 */\r
44 public static final String SVG_NS =\r
45 "http://www.w3.org/2000/svg";\r
46 public static final String XLINK_NS =\r
47 "http://www.w3.org/1999/xlink";\r
48 public static final String ODF_NS =\r
49 "urn:oasis:names:tc:opendocument:xmlns:office:1.0";\r
50 public static final String ODG_NS =\r
51 "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0";\r
52 public static final String ODSVG_NS =\r
53 "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0";\r
54 \r
55 \r
56 DecimalFormat nrfmt;\r
57 //static final double pxToCm = 0.0339;\r
58 static final double pxToCm = 0.0275;\r
59 static final double piToRad = 0.0174532925;\r
60 BufferedWriter out;\r
61 BufferedReader in;\r
62 int imageNr;\r
63 int styleNr;\r
64 \r
65 //########################################################################\r
66 //# M E S S A G E S\r
67 //########################################################################\r
68 \r
69 /**\r
70 *\r
71 */\r
72 void err(String msg)\r
73 {\r
74 System.out.println("SvgOdg ERROR:" + msg);\r
75 }\r
76 \r
77 /**\r
78 *\r
79 */\r
80 void trace(String msg)\r
81 {\r
82 System.out.println("SvgOdg:" + msg);\r
83 }\r
84 \r
85 \r
86 \r
87 \r
88 //########################################################################\r
89 //# I N P U T / O U T P U T\r
90 //########################################################################\r
91 \r
92 boolean po(String s)\r
93 {\r
94 try\r
95 {\r
96 out.write(s);\r
97 }\r
98 catch(IOException e)\r
99 {\r
100 return false;\r
101 }\r
102 return true;\r
103 }\r
104 \r
105 //########################################################################\r
106 //# U T I L I T Y\r
107 //########################################################################\r
108 \r
109 public void dumpDocument(Document doc)\r
110 {\r
111 String s = "";\r
112 try\r
113 {\r
114 TransformerFactory factory = TransformerFactory.newInstance();\r
115 Transformer trans = factory.newTransformer();\r
116 DOMSource source = new DOMSource(doc);\r
117 ByteArrayOutputStream bos = new ByteArrayOutputStream();\r
118 StreamResult result = new StreamResult(bos);\r
119 trans.transform(source, result);\r
120 byte buf[] = bos.toByteArray();\r
121 s = new String(buf);\r
122 }\r
123 catch (javax.xml.transform.TransformerException e)\r
124 {\r
125 }\r
126 trace("doc:" + s);\r
127 }\r
128 \r
129 \r
130 //########################################################################\r
131 //# I N N E R C L A S S ImageInfo\r
132 //########################################################################\r
133 public class ImageInfo\r
134 {\r
135 String name;\r
136 String newName;\r
137 byte buf[];\r
138 \r
139 public String getName()\r
140 {\r
141 return name;\r
142 }\r
143 \r
144 public String getNewName()\r
145 {\r
146 return newName;\r
147 }\r
148 \r
149 \r
150 public byte[] getBuf()\r
151 {\r
152 return buf;\r
153 }\r
154 \r
155 public ImageInfo(String name, String newName, byte buf[])\r
156 {\r
157 this.name = name;\r
158 this.name = newName;\r
159 this.buf = buf;\r
160 }\r
161 \r
162 }\r
163 //########################################################################\r
164 //# I N N E R C L A S S StyleInfo\r
165 //########################################################################\r
166 public class StyleInfo\r
167 {\r
168 \r
169 String name;\r
170 public String getName()\r
171 {\r
172 return name;\r
173 }\r
174 \r
175 String cssStyle;\r
176 public String getCssStyle()\r
177 {\r
178 return cssStyle;\r
179 }\r
180 \r
181 String stroke;\r
182 public String getStroke()\r
183 {\r
184 return stroke;\r
185 }\r
186 \r
187 String strokeColor;\r
188 public String getStrokeColor()\r
189 {\r
190 return strokeColor;\r
191 }\r
192 \r
193 String strokeWidth;\r
194 public String getStrokeWidth()\r
195 {\r
196 return strokeWidth;\r
197 }\r
198 \r
199 String fill;\r
200 public String getFill()\r
201 {\r
202 return fill;\r
203 }\r
204 \r
205 String fillColor;\r
206 public String getFillColor()\r
207 {\r
208 return fillColor;\r
209 }\r
210 \r
211 public StyleInfo(String name, String cssStyle)\r
212 {\r
213 this.name = name;\r
214 this.cssStyle = cssStyle;\r
215 fill = "none";\r
216 stroke = "none";\r
217 }\r
218 \r
219 }\r
220 //########################################################################\r
221 //# E N D I N N E R C L A S S E S\r
222 //########################################################################\r
223 \r
224 \r
225 \r
226 \r
227 //########################################################################\r
228 //# V A R I A B L E S\r
229 //########################################################################\r
230 \r
231 /**\r
232 * ODF content.xml file\r
233 */\r
234 Document content;\r
235 public Document getContent()\r
236 {\r
237 return content;\r
238 }\r
239 \r
240 /**\r
241 * ODF meta.xml file\r
242 */\r
243 Document meta;\r
244 public Document getMeta()\r
245 {\r
246 return meta;\r
247 }\r
248 \r
249 /**\r
250 * SVG file\r
251 */\r
252 Document svg;\r
253 public Document getSvg()\r
254 {\r
255 return svg;\r
256 }\r
257 \r
258 /**\r
259 * Loaded ODF or SVG images\r
260 */\r
261 ArrayList<ImageInfo> images;\r
262 public ArrayList<ImageInfo> getImages()\r
263 {\r
264 return images;\r
265 }\r
266 \r
267 /**\r
268 * CSS styles\r
269 */\r
270 HashMap<String, StyleInfo> styles;\r
271 public HashMap<String, StyleInfo> getStyles()\r
272 {\r
273 return styles;\r
274 }\r
275 \r
276 \r
277 \r
278 \r
279 \r
280 //########################################################################\r
281 //# S V G T O O D F\r
282 //########################################################################\r
283 \r
284 class PathData\r
285 {\r
286 String cmd;\r
287 double nr[];\r
288 PathData(String s, double buf[])\r
289 {\r
290 cmd=s; nr = buf;\r
291 }\r
292 }\r
293 \r
294 double getPathNum(StringTokenizer st)\r
295 {\r
296 if (!st.hasMoreTokens())\r
297 return 0.0;\r
298 String s = st.nextToken();\r
299 double nr = Double.parseDouble(s);\r
300 return nr;\r
301 }\r
302 \r
303 String parsePathData(String pathData, double bounds[])\r
304 {\r
305 double minx = Double.MAX_VALUE;\r
306 double maxx = Double.MIN_VALUE;\r
307 double miny = Double.MAX_VALUE;\r
308 double maxy = Double.MIN_VALUE;\r
309 //trace("#### pathData:" + pathData);\r
310 ArrayList<PathData> data = new ArrayList<PathData>();\r
311 StringTokenizer st = new StringTokenizer(pathData, " ,");\r
312 while (true)\r
313 {\r
314 String s = st.nextToken();\r
315 if ( s.equals("z") || s.equals("Z") )\r
316 {\r
317 PathData pd = new PathData(s, new double[0]);\r
318 data.add(pd);\r
319 break;\r
320 }\r
321 else if ( s.equals("h") || s.equals("H") )\r
322 {\r
323 double d[] = new double[1];\r
324 d[0] = getPathNum(st) * pxToCm;\r
325 if (d[0] < minx) minx = d[0];\r
326 else if (d[0] > maxx) maxx = d[0];\r
327 PathData pd = new PathData(s, d);\r
328 data.add(pd);\r
329 }\r
330 else if ( s.equals("v") || s.equals("V") )\r
331 {\r
332 double d[] = new double[1];\r
333 d[0] = getPathNum(st) * pxToCm;\r
334 if (d[0] < miny) miny = d[0];\r
335 else if (d[0] > maxy) maxy = d[0];\r
336 PathData pd = new PathData(s, d);\r
337 data.add(pd);\r
338 }\r
339 else if ( s.equals("m") || s.equals("M") ||\r
340 s.equals("l") || s.equals("L") ||\r
341 s.equals("t") || s.equals("T") )\r
342 {\r
343 double d[] = new double[2];\r
344 d[0] = getPathNum(st) * pxToCm;\r
345 d[1] = getPathNum(st) * pxToCm;\r
346 if (d[0] < minx) minx = d[0];\r
347 else if (d[0] > maxx) maxx = d[0];\r
348 if (d[1] < miny) miny = d[1];\r
349 else if (d[1] > maxy) maxy = d[1];\r
350 PathData pd = new PathData(s, d);\r
351 data.add(pd);\r
352 }\r
353 else if ( s.equals("q") || s.equals("Q") ||\r
354 s.equals("s") || s.equals("S") )\r
355 {\r
356 double d[] = new double[4];\r
357 d[0] = getPathNum(st) * pxToCm;\r
358 d[1] = getPathNum(st) * pxToCm;\r
359 if (d[0] < minx) minx = d[0];\r
360 else if (d[0] > maxx) maxx = d[0];\r
361 if (d[1] < miny) miny = d[1];\r
362 else if (d[1] > maxy) maxy = d[1];\r
363 d[2] = getPathNum(st) * pxToCm;\r
364 d[3] = getPathNum(st) * pxToCm;\r
365 if (d[2] < minx) minx = d[2];\r
366 else if (d[2] > maxx) maxx = d[2];\r
367 if (d[3] < miny) miny = d[3];\r
368 else if (d[3] > maxy) maxy = d[3];\r
369 PathData pd = new PathData(s, d);\r
370 data.add(pd);\r
371 }\r
372 else if ( s.equals("c") || s.equals("C") )\r
373 {\r
374 double d[] = new double[6];\r
375 d[0] = getPathNum(st) * pxToCm;\r
376 d[1] = getPathNum(st) * pxToCm;\r
377 if (d[0] < minx) minx = d[0];\r
378 else if (d[0] > maxx) maxx = d[0];\r
379 if (d[1] < miny) miny = d[1];\r
380 else if (d[1] > maxy) maxy = d[1];\r
381 d[2] = getPathNum(st) * pxToCm;\r
382 d[3] = getPathNum(st) * pxToCm;\r
383 if (d[2] < minx) minx = d[2];\r
384 else if (d[2] > maxx) maxx = d[2];\r
385 if (d[3] < miny) miny = d[3];\r
386 else if (d[3] > maxy) maxy = d[3];\r
387 d[4] = getPathNum(st) * pxToCm;\r
388 d[5] = getPathNum(st) * pxToCm;\r
389 if (d[4] < minx) minx = d[4];\r
390 else if (d[4] > maxx) maxx = d[4];\r
391 if (d[5] < miny) miny = d[5];\r
392 else if (d[5] > maxy) maxy = d[5];\r
393 PathData pd = new PathData(s, d);\r
394 data.add(pd);\r
395 }\r
396 else if ( s.equals("a") || s.equals("A") )\r
397 {\r
398 double d[] = new double[6];\r
399 d[0] = getPathNum(st) * pxToCm;\r
400 d[1] = getPathNum(st) * pxToCm;\r
401 if (d[0] < minx) minx = d[0];\r
402 else if (d[0] > maxx) maxx = d[0];\r
403 if (d[1] < miny) miny = d[1];\r
404 else if (d[1] > maxy) maxy = d[1];\r
405 d[2] = getPathNum(st) * piToRad;//angle\r
406 d[3] = getPathNum(st) * piToRad;//angle\r
407 d[4] = getPathNum(st) * pxToCm;\r
408 d[5] = getPathNum(st) * pxToCm;\r
409 if (d[4] < minx) minx = d[4];\r
410 else if (d[4] > maxx) maxx = d[4];\r
411 if (d[5] < miny) miny = d[5];\r
412 else if (d[5] > maxy) maxy = d[5];\r
413 PathData pd = new PathData(s, d);\r
414 data.add(pd);\r
415 }\r
416 //trace("x:" + x + " y:" + y);\r
417 }\r
418 \r
419 trace("minx:" + minx + " maxx:" + maxx +\r
420 " miny:" + miny + " maxy:" + maxy);\r
421 \r
422 StringBuffer buf = new StringBuffer();\r
423 for (PathData pd : data)\r
424 {\r
425 buf.append(pd.cmd);\r
426 buf.append(" ");\r
427 for (double d:pd.nr)\r
428 {\r
429 buf.append(nrfmt.format(d * 1000.0));\r
430 buf.append(" ");\r
431 }\r
432 }\r
433 \r
434 bounds[0] = minx;\r
435 bounds[1] = miny;\r
436 bounds[2] = maxx;\r
437 bounds[3] = maxy;\r
438 \r
439 return buf.toString();\r
440 }\r
441 \r
442 \r
443 \r
444 boolean parseTransform(String transStr, AffineTransform trans)\r
445 {\r
446 trace("== transform:"+ transStr);\r
447 StringTokenizer st = new StringTokenizer(transStr, ")");\r
448 while (st.hasMoreTokens())\r
449 {\r
450 String chunk = st.nextToken();\r
451 StringTokenizer st2 = new StringTokenizer(chunk, " ,(");\r
452 if (!st2.hasMoreTokens())\r
453 continue;\r
454 String name = st2.nextToken();\r
455 trace(" ++name:"+ name);\r
456 if (name.equals("matrix"))\r
457 {\r
458 double v[] = new double[6];\r
459 for (int i=0 ; i<6 ; i++)\r
460 {\r
461 if (!st2.hasMoreTokens())\r
462 break;\r
463 v[i] = Double.parseDouble(st2.nextToken()) * pxToCm;\r
464 }\r
465 AffineTransform mat = new AffineTransform(v);\r
466 trans.concatenate(mat);\r
467 }\r
468 else if (name.equals("translate"))\r
469 {\r
470 double dx = 0.0;\r
471 double dy = 0.0;\r
472 if (!st2.hasMoreTokens())\r
473 continue;\r
474 dx = Double.parseDouble(st2.nextToken()) * pxToCm;\r
475 if (st2.hasMoreTokens())\r
476 dy = Double.parseDouble(st2.nextToken()) * pxToCm;\r
477 trans.translate(dx, dy);\r
478 }\r
479 else if (name.equals("scale"))\r
480 {\r
481 double sx = 1.0;\r
482 double sy = 1.0;\r
483 if (!st2.hasMoreTokens())\r
484 continue;\r
485 sx = sy = Double.parseDouble(st2.nextToken());\r
486 if (st2.hasMoreTokens())\r
487 sy = Double.parseDouble(st2.nextToken());\r
488 trans.scale(sx, sy);\r
489 }\r
490 else if (name.equals("rotate"))\r
491 {\r
492 double r = 0.0;\r
493 double cx = 0.0;\r
494 double cy = 0.0;\r
495 if (!st2.hasMoreTokens())\r
496 continue;\r
497 r = Double.parseDouble(st2.nextToken()) * piToRad;\r
498 if (st2.hasMoreTokens())\r
499 {\r
500 cx = Double.parseDouble(st2.nextToken()) * pxToCm;\r
501 if (!st2.hasMoreTokens())\r
502 continue;\r
503 cy = Double.parseDouble(st2.nextToken()) * pxToCm;\r
504 trans.rotate(r, cx, cy);\r
505 }\r
506 else\r
507 {\r
508 trans.rotate(r);\r
509 }\r
510 }\r
511 else if (name.equals("skewX"))\r
512 {\r
513 double angle = 0.0;\r
514 if (!st2.hasMoreTokens())\r
515 continue;\r
516 angle = Double.parseDouble(st2.nextToken());\r
517 trans.shear(angle, 0.0);\r
518 }\r
519 else if (name.equals("skewY"))\r
520 {\r
521 double angle = 0.0;\r
522 if (!st2.hasMoreTokens())\r
523 continue;\r
524 angle = Double.parseDouble(st2.nextToken());\r
525 trans.shear(0.0, angle);\r
526 }\r
527 }\r
528 return true;\r
529 }\r
530 \r
531 \r
532 \r
533 String coordToOdg(String sval)\r
534 {\r
535 double nr = Double.parseDouble(sval);\r
536 nr = nr * pxToCm;\r
537 String s = nrfmt.format(nr) + "cm";\r
538 return s;\r
539 }\r
540 \r
541 \r
542 boolean writeSvgAttributes(Element elem, AffineTransform trans)\r
543 {\r
544 NamedNodeMap attrs = elem.getAttributes();\r
545 String ename = elem.getLocalName();\r
546 for (int i=0 ; i<attrs.getLength() ; i++)\r
547 {\r
548 Attr attr = (Attr)attrs.item(i);\r
549 String aname = attr.getName();\r
550 String aval = attr.getValue();\r
551 if (aname.startsWith("xmlns"))\r
552 continue;\r
553 else if (aname.equals("d"))//already handled\r
554 continue;\r
555 else if (aname.startsWith("transform"))\r
556 {\r
557 parseTransform(aval, trans);\r
558 continue;\r
559 }\r
560 else if (aname.equals("style"))\r
561 {\r
562 StyleInfo style = styles.get(aval);\r
563 if (style != null)\r
564 {\r
565 po(" draw:style-name=\"");\r
566 po(style.getName());\r
567 po("\"");\r
568 }\r
569 continue;\r
570 }\r
571 if (aname.equals("x") || aname.equals("y") ||\r
572 aname.equals("width") || aname.equals("height"))\r
573 {\r
574 aval = coordToOdg(aval);\r
575 }\r
576 if ("id".equals(aname))\r
577 po(" ");\r
578 else if ("transform".equals(aname))\r
579 po(" draw:");\r
580 else\r
581 po(" svg:");\r
582 po(aname);\r
583 po("=\"");\r
584 po(aval);\r
585 po("\"");\r
586 }\r
587 \r
588 //Output the current transform\r
589 if (!trans.isIdentity() &&\r
590 !(\r
591 ename.equals("g") ||\r
592 ename.equals("defs") ||\r
593 ename.equals("metadata")\r
594 )\r
595 )\r
596 {\r
597 double v[] = new double[6];\r
598 trans.getMatrix(v);\r
599 po(" draw:transform=\"matrix(" +\r
600 nrfmt.format(v[0]) + "," +\r
601 nrfmt.format(v[1]) + "," +\r
602 nrfmt.format(v[2]) + "," +\r
603 nrfmt.format(v[3]) + "," +\r
604 nrfmt.format(v[4]) + "," +\r
605 nrfmt.format(v[5]) + ")\"");\r
606 }\r
607 return true;\r
608 }\r
609 \r
610 public boolean writeOdfContent(Element elem, AffineTransform trans)\r
611 {\r
612 String ns = elem.getNamespaceURI();\r
613 String tagName = elem.getLocalName();\r
614 //trace("ns:" + ns + " tagName:" + tagName);\r
615 if (!ns.equals(SVG_NS))\r
616 return true;\r
617 if (tagName.equals("svg"))\r
618 {\r
619 NodeList children = elem.getChildNodes();\r
620 for (int i=0 ; i<children.getLength() ; i++)\r
621 {\r
622 Node n = children.item(i);\r
623 if (n.getNodeType() == Node.ELEMENT_NODE)\r
624 if (!writeOdfContent((Element)n,\r
625 (AffineTransform)trans.clone()))\r
626 return false;\r
627 }\r
628 }\r
629 else if (tagName.equals("g"))\r
630 {\r
631 //String transform = elem.getAttribute("transform");\r
632 po("<draw:g");\r
633 writeSvgAttributes(elem, trans); po(">\n");\r
634 NodeList children = elem.getChildNodes();\r
635 for (int i=0 ; i<children.getLength() ; i++)\r
636 {\r
637 Node n = children.item(i);\r
638 if (n.getNodeType() == Node.ELEMENT_NODE)\r
639 if (!writeOdfContent((Element)n,\r
640 (AffineTransform)trans.clone()))\r
641 return false;\r
642 }\r
643 po("</draw:g>\n");\r
644 }\r
645 else if (tagName.equals("text"))\r
646 {\r
647 String x = coordToOdg(elem.getAttribute("x"));\r
648 String y = coordToOdg(elem.getAttribute("y"));\r
649 String width = "5cm";\r
650 String height = "2cm";\r
651 String txt = elem.getTextContent();\r
652 po("<draw:frame draw:style-name=\"grx1\" draw:layer=\"layout\" ");\r
653 po("svg:x=\"" + x + "\" svg:y=\"" + y + "\" ");\r
654 po("svg:width=\"" + width + "\" svg:height=\"" + height + "\"");\r
655 po(">\n");\r
656 po(" <draw:text-box draw:auto-grow-height=\"true\" draw:auto-grow-width=\"true\">\n");\r
657 po(" <text:p text:style-name=\"P1\"> " + txt + "</text:p>\n");\r
658 po(" </draw:text-box>\n");\r
659 po("</draw:frame>\n");\r
660 return true;\r
661 }\r
662 else if (tagName.equals("image"))\r
663 {\r
664 String x = coordToOdg(elem.getAttribute("x"));\r
665 String y = coordToOdg(elem.getAttribute("y"));\r
666 String width = coordToOdg(elem.getAttribute("width"));\r
667 String height = coordToOdg(elem.getAttribute("height"));\r
668 String imageName = elem.getAttributeNS(XLINK_NS, "href");\r
669 po("<draw:frame draw:style-name=\"grx1\" draw:layer=\"layout\" ");\r
670 po("svg:x=\"" + x + "\" svg:y=\"" + y + "\" ");\r
671 po("svg:width=\"" + width + "\" svg:height=\"" + height + "\">\n");\r
672 po(" <draw:image xlink:href=\"Pictures/" + imageName + "\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"><text:p/></draw:image>\n");\r
673 po("</draw:frame>\n");\r
674 return true;\r
675 }\r
676 else if (tagName.equals("path"))\r
677 {\r
678 double bounds[] = new double[4];\r
679 String d = elem.getAttribute("d");\r
680 String newd = parsePathData(d, bounds);\r
681 double x = bounds[0];\r
682 double y = bounds[1];\r
683 double width = (bounds[2]-bounds[0]);\r
684 double height = (bounds[3]-bounds[1]);\r
685 po("<draw:path draw:layer=\"layout\" \n");\r
686 po(" svg:x=\"" + nrfmt.format(x) + "cm\" ");\r
687 po("svg:y=\"" + nrfmt.format(y) + "cm\" ");\r
688 po("svg:width=\"" + nrfmt.format(width) + "cm\" ");\r
689 po("svg:height=\"" + nrfmt.format(height) + "cm\" ");\r
690 po("svg:viewBox=\"0.0 0.0 " +\r
691 nrfmt.format(bounds[2] * 1000.0) + " " +\r
692 nrfmt.format(bounds[3] * 1000.0) + "\"\n");\r
693 po(" svg:d=\"" + newd + "\"\n ");\r
694 \r
695 writeSvgAttributes(elem, trans); po("/>\n");\r
696 //po(" svg:d=\"" + d + "\"/>\n");\r
697 return true;\r
698 }\r
699 \r
700 else\r
701 {\r
702 //Verbatim tab mapping\r
703 po("<draw:"); po(tagName);\r
704 writeSvgAttributes(elem, trans); po(">\n");\r
705 po("</draw:"); po(tagName); po(">\n");\r
706 }\r
707 \r
708 return true;\r
709 }\r
710 \r
711 \r
712 boolean writeOdfContent(ZipOutputStream outs)\r
713 {\r
714 try\r
715 {\r
716 ZipEntry ze = new ZipEntry("content.xml");\r
717 outs.putNextEntry(ze);\r
718 out = new BufferedWriter(new OutputStreamWriter(outs));\r
719 }\r
720 catch (IOException e)\r
721 {\r
722 return false;\r
723 }\r
724 \r
725 NodeList res = svg.getElementsByTagNameNS(SVG_NS, "svg");\r
726 if (res.getLength() < 1)\r
727 {\r
728 err("saveOdf: no <svg> root in .svg file");\r
729 return false;\r
730 }\r
731 Element root = (Element)res.item(0);\r
732 \r
733 \r
734 po("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");\r
735 po("<office:document-content\n");\r
736 po(" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");\r
737 po(" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");\r
738 po(" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");\r
739 po(" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");\r
740 po(" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");\r
741 po(" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");\r
742 po(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");\r
743 po(" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");\r
744 po(" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");\r
745 po(" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");\r
746 po(" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");\r
747 po(" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");\r
748 po(" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");\r
749 po(" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");\r
750 po(" xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");\r
751 po(" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");\r
752 po(" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");\r
753 po(" xmlns:ooo=\"http://openoffice.org/2004/office\"\n");\r
754 po(" xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");\r
755 po(" xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");\r
756 po(" xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");\r
757 po(" xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");\r
758 po(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");\r
759 po(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");\r
760 po(" xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");\r
761 po(" xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");\r
762 po(" office:version=\"1.0\">\n");\r
763 po("\n");\r
764 po("\n");\r
765 po("<office:scripts/>\n");\r
766 po("<office:automatic-styles>\n");\r
767 po("<style:style style:name=\"dp1\" style:family=\"drawing-page\"/>\n");\r
768 po("<style:style style:name=\"grx1\" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");\r
769 po(" <style:graphic-properties draw:stroke=\"none\" draw:fill=\"solid\" draw:textarea-horizontal-align=\"center\" draw:textarea-vertical-align=\"middle\" draw:color-mode=\"standard\" draw:luminance=\"0%\" draw:contrast=\"0%\" draw:gamma=\"100%\" draw:red=\"0%\" draw:green=\"0%\" draw:blue=\"0%\" fo:clip=\"rect(0cm 0cm 0cm 0cm)\" draw:image-opacity=\"100%\" style:mirror=\"none\"/>\n");\r
770 po("</style:style>\n");\r
771 po("<style:style style:name=\"P1\" style:family=\"paragraph\">\n");\r
772 po(" <style:paragraph-properties fo:text-align=\"center\"/>\n");\r
773 po("</style:style>\n");\r
774 \r
775 //## Dump our style table\r
776 for (StyleInfo s : styles.values())\r
777 {\r
778 po("<style:style style:name=\"" + s.getName() + "\" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");\r
779 po(" <style:graphic-properties");\r
780 po(" draw:fill=\"" + s.getFill() + "\"");\r
781 if (!s.getFill().equals("none"))\r
782 po(" draw:fill-color=\"" + s.getFillColor() + "\"");\r
783 po(" draw:stroke=\"" + s.getStroke() + "\"");\r
784 if (!s.getStroke().equals("none"))\r
785 {\r
786 po(" svg:stroke-width=\"" + s.getStrokeWidth() + "\"");\r
787 po(" svg:stroke-color=\"" + s.getStrokeColor() + "\"");\r
788 }\r
789 po("/>\n");\r
790 po("</style:style>\n");\r
791 }\r
792 po("</office:automatic-styles>\n");\r
793 po("\n");\r
794 po("\n");\r
795 po("<office:body>\n");\r
796 po("<office:drawing>\n");\r
797 po("<draw:page draw:name=\"page1\" draw:style-name=\"dp1\" draw:master-page-name=\"Default\">\n");\r
798 po("\n\n\n");\r
799 AffineTransform trans = new AffineTransform();\r
800 //trans.scale(12.0, 12.0);\r
801 po("<!-- ######### CONVERSION FROM SVG STARTS ######## -->\n");\r
802 writeOdfContent(root, trans);\r
803 po("<!-- ######### CONVERSION FROM SVG ENDS ######## -->\n");\r
804 po("\n\n\n");\r
805 \r
806 po("</draw:page>\n");\r
807 po("</office:drawing>\n");\r
808 po("</office:body>\n");\r
809 po("</office:document-content>\n");\r
810 \r
811 \r
812 try\r
813 {\r
814 out.flush();\r
815 outs.closeEntry();\r
816 }\r
817 catch (IOException e)\r
818 {\r
819 err("writeOdfContent:" + e);\r
820 return false;\r
821 }\r
822 return true;\r
823 }\r
824 \r
825 boolean writeOdfMeta(ZipOutputStream outs)\r
826 {\r
827 try\r
828 {\r
829 ZipEntry ze = new ZipEntry("meta.xml");\r
830 outs.putNextEntry(ze);\r
831 out = new BufferedWriter(new OutputStreamWriter(outs));\r
832 }\r
833 catch (IOException e)\r
834 {\r
835 return false;\r
836 }\r
837 \r
838 po("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");\r
839 po("<office:document-meta\n");\r
840 po(" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");\r
841 po(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");\r
842 po(" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");\r
843 po(" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");\r
844 po(" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");\r
845 po(" xmlns:ooo=\"http://openoffice.org/2004/office\"\n");\r
846 po(" xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");\r
847 po(" xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");\r
848 po(" office:version=\"1.0\">\n");\r
849 po("<office:meta>\n");\r
850 po(" <meta:generator>Inkscape-0.43</meta:generator>\n");\r
851 po(" <meta:initial-creator>clark kent</meta:initial-creator>\n");\r
852 po(" <meta:creation-date>2005-12-10T10:55:13</meta:creation-date>\n");\r
853 po(" <dc:creator>clark kent</dc:creator>\n");\r
854 po(" <dc:date>2005-12-10T10:56:20</dc:date>\n");\r
855 po(" <dc:language>en-US</dc:language>\n");\r
856 po(" <meta:editing-cycles>2</meta:editing-cycles>\n");\r
857 po(" <meta:editing-duration>PT1M13S</meta:editing-duration>\n");\r
858 po(" <meta:user-defined meta:name=\"Info 1\"/>\n");\r
859 po(" <meta:user-defined meta:name=\"Info 2\"/>\n");\r
860 po(" <meta:user-defined meta:name=\"Info 3\"/>\n");\r
861 po(" <meta:user-defined meta:name=\"Info 4\"/>\n");\r
862 po(" <meta:document-statistic meta:object-count=\"2\"/>\n");\r
863 po("</office:meta>\n");\r
864 po("</office:document-meta>\n");\r
865 \r
866 \r
867 try\r
868 {\r
869 out.flush();\r
870 outs.closeEntry();\r
871 }\r
872 catch (IOException e)\r
873 {\r
874 err("writeOdfContent:" + e);\r
875 return false;\r
876 }\r
877 return true;\r
878 }\r
879 \r
880 \r
881 boolean writeOdfManifest(ZipOutputStream outs)\r
882 {\r
883 try\r
884 {\r
885 ZipEntry ze = new ZipEntry("META-INF/manifest.xml");\r
886 outs.putNextEntry(ze);\r
887 out = new BufferedWriter(new OutputStreamWriter(outs));\r
888 }\r
889 catch (IOException e)\r
890 {\r
891 return false;\r
892 }\r
893 \r
894 po("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");\r
895 po("<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">\n");\r
896 po("<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n");\r
897 po(" <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.graphics\" manifest:full-path=\"/\"/>\n");\r
898 po(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>\n");\r
899 po(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>\n");\r
900 po(" <!--List our images here-->\n");\r
901 for (int i=0 ; i<images.size() ; i++)\r
902 {\r
903 ImageInfo ie = images.get(i);\r
904 String fname = ie.getName();\r
905 if (fname.length() < 5)\r
906 {\r
907 err("image file name too short:" + fname);\r
908 return false;\r
909 }\r
910 String ext = fname.substring(fname.length() - 4);\r
911 po(" <manifest:file-entry manifest:media-type=\"");\r
912 if (ext.equals(".gif"))\r
913 po("image/gif");\r
914 else if (ext.equals(".png"))\r
915 po("image/png");\r
916 else if (ext.equals(".jpg") || ext.equals(".jpeg"))\r
917 po("image/jpeg");\r
918 po("\" manifest:full-path=\"");\r
919 po(fname);\r
920 po("\"/>\n");\r
921 }\r
922 po("</manifest:manifest>\n");\r
923 \r
924 try\r
925 {\r
926 out.flush();\r
927 outs.closeEntry();\r
928 }\r
929 catch (IOException e)\r
930 {\r
931 err("writeOdfContent:" + e);\r
932 return false;\r
933 }\r
934 return true;\r
935 }\r
936 \r
937 boolean writeOdfImages(ZipOutputStream outs)\r
938 {\r
939 for (int i=0 ; i<images.size() ; i++)\r
940 {\r
941 ImageInfo ie = images.get(i);\r
942 try\r
943 {\r
944 String iname = "Pictures/" + ie.getName();\r
945 ZipEntry ze = new ZipEntry(iname);\r
946 outs.putNextEntry(ze);\r
947 outs.write(ie.getBuf());\r
948 outs.closeEntry();\r
949 }\r
950 catch (IOException e)\r
951 {\r
952 err("writing images:" + e);\r
953 return false;\r
954 }\r
955 }\r
956 return true;\r
957 }\r
958 \r
959 /**\r
960 *\r
961 */\r
962 public boolean writeOdf(OutputStream outs)\r
963 {\r
964 try\r
965 {\r
966 ZipOutputStream zos = new ZipOutputStream(outs);\r
967 if (!writeOdfContent(zos))\r
968 return false;\r
969 if (!writeOdfManifest(zos))\r
970 return false;\r
971 if (!writeOdfMeta(zos))\r
972 return false;\r
973 if (!writeOdfImages(zos))\r
974 return false;\r
975 //if (!writeOdfStyles(zos))\r
976 // return false;\r
977 zos.close();\r
978 }\r
979 catch (IOException e)\r
980 {\r
981 err("closing ODF zip output stream:" + e);\r
982 return false;\r
983 }\r
984 return true;\r
985 }\r
986 \r
987 \r
988 \r
989 /**\r
990 *\r
991 */\r
992 public boolean saveOdf(String fileName)\r
993 {\r
994 boolean ret = true;\r
995 try\r
996 {\r
997 FileOutputStream fos = new FileOutputStream(fileName);\r
998 ret = writeOdf(fos);\r
999 fos.close();\r
1000 }\r
1001 catch (IOException e)\r
1002 {\r
1003 err("writing odf " + fileName + " : " + e);\r
1004 return false;\r
1005 }\r
1006 return ret;\r
1007 }\r
1008 \r
1009 \r
1010 \r
1011 boolean parseCss(String css)\r
1012 {\r
1013 trace("##### STYLE ### :" + css);\r
1014 String name = "gr" + styleNr;\r
1015 styleNr++;\r
1016 StyleInfo si = new StyleInfo(name, css);\r
1017 StringTokenizer st = new StringTokenizer(css, ";");\r
1018 while (st.hasMoreTokens())\r
1019 {\r
1020 String style = st.nextToken();\r
1021 //trace(" " + style);\r
1022 int pos = style.indexOf(':');\r
1023 if (pos < 1 || pos > style.length()-2)\r
1024 continue;\r
1025 String attrName = style.substring(0, pos);\r
1026 String attrVal = style.substring(pos+1);\r
1027 trace(" =" + attrName + ':' + attrVal);\r
1028 if ("stroke".equals(attrName))\r
1029 {\r
1030 si.stroke = "solid";\r
1031 si.strokeColor = attrVal;\r
1032 }\r
1033 else if ("stroke-width".equals(attrName))\r
1034 {\r
1035 si.strokeWidth = attrVal;\r
1036 }\r
1037 else if ("fill".equals(attrName))\r
1038 {\r
1039 si.fill = "solid";\r
1040 si.fillColor = attrVal;\r
1041 }\r
1042 }\r
1043 styles.put(css, si);\r
1044 return true;\r
1045 }\r
1046 \r
1047 boolean readSvg(InputStream ins)\r
1048 {\r
1049 //### LOAD XML\r
1050 try\r
1051 {\r
1052 DocumentBuilderFactory factory =\r
1053 DocumentBuilderFactory.newInstance();\r
1054 factory.setNamespaceAware(true);\r
1055 DocumentBuilder builder =\r
1056 factory.newDocumentBuilder();\r
1057 builder.setEntityResolver(new EntityResolver()\r
1058 {\r
1059 public InputSource resolveEntity(String publicId, String systemId)\r
1060 {\r
1061 return new InputSource(new ByteArrayInputStream(new byte[0]));\r
1062 }\r
1063 });\r
1064 Document doc = builder.parse(ins);\r
1065 svg = doc;\r
1066 }\r
1067 catch (javax.xml.parsers.ParserConfigurationException e)\r
1068 {\r
1069 err("making DOM parser:"+e);\r
1070 return false;\r
1071 }\r
1072 catch (org.xml.sax.SAXException e)\r
1073 {\r
1074 err("parsing svg document:"+e);\r
1075 return false;\r
1076 }\r
1077 catch (IOException e)\r
1078 {\r
1079 err("parsing svg document:"+e);\r
1080 return false;\r
1081 }\r
1082 //dumpDocument(svg);\r
1083 \r
1084 //### LOAD IMAGES\r
1085 imageNr = 0;\r
1086 images = new ArrayList<ImageInfo>();\r
1087 NodeList res = svg.getElementsByTagNameNS(SVG_NS, "image");\r
1088 for (int i=0 ; i<res.getLength() ; i++)\r
1089 {\r
1090 Element elem = (Element) res.item(i);\r
1091 String fileName = elem.getAttributeNS(XLINK_NS, "href");\r
1092 if (fileName == null)\r
1093 {\r
1094 err("No xlink:href pointer to image data for image");\r
1095 return false;\r
1096 }\r
1097 File f = new File(fileName);\r
1098 if (!f.exists())\r
1099 {\r
1100 err("image '" + fileName + "' does not exist");\r
1101 return false;\r
1102 }\r
1103 int bufSize = (int)f.length();\r
1104 byte buf[] = new byte[bufSize];\r
1105 int pos = 0;\r
1106 try\r
1107 {\r
1108 FileInputStream fis = new FileInputStream(fileName);\r
1109 while (pos < bufSize)\r
1110 {\r
1111 int len = fis.read(buf, pos, bufSize - pos);\r
1112 if (len < 0)\r
1113 break;\r
1114 pos += len;\r
1115 }\r
1116 fis.close();\r
1117 }\r
1118 catch (IOException e)\r
1119 {\r
1120 err("reading image '" + fileName + "' :" + e);\r
1121 return false;\r
1122 }\r
1123 if (pos != bufSize)\r
1124 {\r
1125 err("reading image entry. expected " +\r
1126 bufSize + ", found " + pos + " bytes.");\r
1127 return false;\r
1128 }\r
1129 ImageInfo ie = new ImageInfo(fileName, fileName, buf);\r
1130 images.add(ie);\r
1131 }\r
1132 \r
1133 //### Parse styles\r
1134 styleNr = 0;\r
1135 styles = new HashMap<String, StyleInfo>();\r
1136 res = svg.getElementsByTagName("*");\r
1137 for (int i=0 ; i<res.getLength() ; i++)\r
1138 {\r
1139 Element elem = (Element) res.item(i);\r
1140 trace("elem:"+ elem.getNodeName());\r
1141 String style = elem.getAttribute("style");\r
1142 if (style != null && style.length() > 0)\r
1143 parseCss(style);\r
1144 }\r
1145 \r
1146 return true;\r
1147 }\r
1148 \r
1149 boolean readSvg(String fileName)\r
1150 {\r
1151 try\r
1152 {\r
1153 FileInputStream fis = new FileInputStream(fileName);\r
1154 if (!readSvg(fis))\r
1155 return false;\r
1156 fis.close();\r
1157 }\r
1158 catch (IOException e)\r
1159 {\r
1160 err("opening svg file:"+e);\r
1161 return false;\r
1162 }\r
1163 return true;\r
1164 }\r
1165 \r
1166 \r
1167 //########################################################################\r
1168 //# O D F T O S V G\r
1169 //########################################################################\r
1170 \r
1171 /**\r
1172 *\r
1173 */\r
1174 public boolean readOdfEntry(ZipInputStream zis, ZipEntry ent)\r
1175 {\r
1176 String fileName = ent.getName();\r
1177 trace("fileName:" + fileName);\r
1178 if (fileName.length() < 4)\r
1179 return true;\r
1180 String ext = fileName.substring(fileName.length() - 4);\r
1181 trace("ext:" + ext);\r
1182 ArrayList<Byte> arr = new ArrayList<Byte>();\r
1183 try\r
1184 {\r
1185 while (true)\r
1186 {\r
1187 int inb = zis.read();\r
1188 if (inb < 0)\r
1189 break;\r
1190 arr.add((byte)inb);\r
1191 }\r
1192 }\r
1193 catch (IOException e)\r
1194 {\r
1195 return false;\r
1196 }\r
1197 byte buf[] = new byte[arr.size()];\r
1198 for (int i=0 ; i<buf.length ; i++)\r
1199 buf[i] = arr.get(i);\r
1200 trace("bufsize:" + buf.length);\r
1201 \r
1202 if (ext.equals(".xml"))\r
1203 {\r
1204 try\r
1205 {\r
1206 DocumentBuilderFactory factory =\r
1207 DocumentBuilderFactory.newInstance();\r
1208 factory.setNamespaceAware(true);\r
1209 DocumentBuilder builder =\r
1210 factory.newDocumentBuilder();\r
1211 builder.setEntityResolver(new EntityResolver()\r
1212 {\r
1213 public InputSource resolveEntity(String publicId, String systemId)\r
1214 {\r
1215 return new InputSource(new ByteArrayInputStream(new byte[0]));\r
1216 }\r
1217 });\r
1218 //trace("doc:"+new String(buf));\r
1219 Document doc = builder.parse(new ByteArrayInputStream(buf));\r
1220 if (fileName.equals("content.xml"))\r
1221 content = doc;\r
1222 else if (fileName.equals("meta.xml"))\r
1223 meta = doc;\r
1224 else if (fileName.equals("styles.xml"))\r
1225 {\r
1226 //styles = doc;\r
1227 }\r
1228 }\r
1229 catch (javax.xml.parsers.ParserConfigurationException e)\r
1230 {\r
1231 err("making DOM parser:"+e);\r
1232 return false;\r
1233 }\r
1234 catch (org.xml.sax.SAXException e)\r
1235 {\r
1236 err("parsing document:"+e);\r
1237 return false;\r
1238 }\r
1239 catch (IOException e)\r
1240 {\r
1241 err("parsing document:"+e);\r
1242 return false;\r
1243 }\r
1244 }\r
1245 else if (ext.equals(".png") ||\r
1246 ext.equals(".gif") ||\r
1247 ext.equals(".jpg") ||\r
1248 ext.equals(".jpeg") )\r
1249 {\r
1250 String imageName = "image" + imageNr + ext;\r
1251 imageNr++;\r
1252 ImageInfo ie = new ImageInfo(fileName, imageName, buf);\r
1253 trace("added image '" + imageName + "'. " + buf.length +" bytes.");\r
1254 images.add(ie);\r
1255 \r
1256 }\r
1257 dumpDocument(content);\r
1258 return true;\r
1259 }\r
1260 \r
1261 \r
1262 /**\r
1263 *\r
1264 */\r
1265 public boolean readOdf(InputStream ins)\r
1266 {\r
1267 imageNr = 0;\r
1268 images = new ArrayList<ImageInfo>();\r
1269 styleNr = 0;\r
1270 styles = new HashMap<String, StyleInfo>();\r
1271 ZipInputStream zis = new ZipInputStream(ins);\r
1272 while (true)\r
1273 {\r
1274 try\r
1275 {\r
1276 ZipEntry ent = zis.getNextEntry();\r
1277 if (ent == null)\r
1278 break;\r
1279 if (!readOdfEntry(zis, ent))\r
1280 return false;\r
1281 zis.closeEntry();\r
1282 }\r
1283 catch (IOException e)\r
1284 {\r
1285 err("reading zip entry");\r
1286 return false;\r
1287 }\r
1288 }\r
1289 \r
1290 return true;\r
1291 }\r
1292 \r
1293 \r
1294 /**\r
1295 *\r
1296 */\r
1297 public boolean readOdf(String fileName)\r
1298 {\r
1299 boolean ret = true;\r
1300 try\r
1301 {\r
1302 FileInputStream fis = new FileInputStream(fileName);\r
1303 ret = readOdf(fis);\r
1304 fis.close();\r
1305 }\r
1306 catch (IOException e)\r
1307 {\r
1308 err("reading " + fileName + " : " + e);\r
1309 ret = false;\r
1310 }\r
1311 return true;\r
1312 }\r
1313 \r
1314 \r
1315 \r
1316 \r
1317 public boolean writeSvgElement(Element elem)\r
1318 {\r
1319 String ns = elem.getNamespaceURI();\r
1320 String tagName = elem.getLocalName();\r
1321 trace("tag:" + tagName + " : " + ns);\r
1322 if (ns.equals(ODSVG_NS))\r
1323 {\r
1324 po("<"); po(tagName);\r
1325 NamedNodeMap attrs = elem.getAttributes();\r
1326 for (int i=0 ; i<attrs.getLength() ; i++)\r
1327 {\r
1328 Attr attr = (Attr)attrs.item(i);\r
1329 String aname = attr.getName();\r
1330 String aval = attr.getValue();\r
1331 //Replace image name\r
1332 if ("xlink:href".equals(aname) && "image".equals(tagName))\r
1333 {\r
1334 for (int j=0 ; j<images.size() ; j++)\r
1335 {\r
1336 ImageInfo ie = images.get(i);\r
1337 if (aval.equals(ie.getName()))\r
1338 aval = ie.getNewName();\r
1339 }\r
1340 }\r
1341 po(" ");\r
1342 po(aname);\r
1343 po("=\"");\r
1344 po(aval);\r
1345 po("\"");\r
1346 }\r
1347 po(">\n");\r
1348 }\r
1349 NodeList children = elem.getChildNodes();\r
1350 for (int i=0 ; i<children.getLength() ; i++)\r
1351 {\r
1352 Node n = children.item(i);\r
1353 if (n.getNodeType() == Node.ELEMENT_NODE)\r
1354 if (!writeSvgElement((Element)n))\r
1355 return false;\r
1356 }\r
1357 if (ns.equals(ODSVG_NS))\r
1358 {\r
1359 po("</"); po(tagName); po(">\n");\r
1360 }\r
1361 return true;\r
1362 }\r
1363 \r
1364 \r
1365 public boolean saveSvg(String svgFileName)\r
1366 {\r
1367 trace("====== Saving images ===========");\r
1368 try\r
1369 {\r
1370 for (int i=0 ; i<images.size() ; i++)\r
1371 {\r
1372 ImageInfo entry = images.get(i);\r
1373 trace("saving:" + entry.name);\r
1374 FileOutputStream fos = new FileOutputStream(entry.name);\r
1375 fos.write(entry.buf);\r
1376 fos.close();\r
1377 }\r
1378 }\r
1379 catch (IOException e)\r
1380 {\r
1381 err("saveAsSVG:" + e);\r
1382 return false;\r
1383 }\r
1384 \r
1385 try\r
1386 {\r
1387 out = new BufferedWriter(new FileWriter(svgFileName));\r
1388 }\r
1389 catch (IOException e)\r
1390 {\r
1391 err("save:" + e);\r
1392 return false;\r
1393 }\r
1394 \r
1395 if (content == null)\r
1396 {\r
1397 err("no content in odf");\r
1398 return false;\r
1399 }\r
1400 \r
1401 NodeList res = content.getElementsByTagNameNS(ODF_NS, "drawing");\r
1402 if (res.getLength() < 1)\r
1403 {\r
1404 err("save: no drawing in document");\r
1405 return false;\r
1406 }\r
1407 Element root = (Element)res.item(0);\r
1408 trace("NS:"+root.getNamespaceURI());\r
1409 \r
1410 res = root.getElementsByTagNameNS(ODG_NS, "page");\r
1411 if (res.getLength() < 1)\r
1412 {\r
1413 err("save: no page in drawing");\r
1414 return false;\r
1415 }\r
1416 Element page = (Element)res.item(0);\r
1417 \r
1418 po("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");\r
1419 po("<svg\n");\r
1420 po(" xmlns:svg=\"http://www.w3.org/2000/svg\"\n");\r
1421 po(" xmlns=\"http://www.w3.org/2000/svg\"\n");\r
1422 po(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");\r
1423 po(" version=\"1.0\"\n");\r
1424 po(" >\n");\r
1425 \r
1426 writeSvgElement(page);\r
1427 \r
1428 po("</svg>\n");\r
1429 \r
1430 try\r
1431 {\r
1432 out.close();\r
1433 }\r
1434 catch (IOException e)\r
1435 {\r
1436 err("save:close:" + e);\r
1437 return false;\r
1438 }\r
1439 return true;\r
1440 }\r
1441 \r
1442 \r
1443 \r
1444 //########################################################################\r
1445 //# C O N S T R U C T O R\r
1446 //########################################################################\r
1447 \r
1448 SvgOdg()\r
1449 {\r
1450 //init, if necessary\r
1451 nrfmt = new DecimalFormat("#.####");\r
1452 }\r
1453 \r
1454 \r
1455 //########################################################################\r
1456 //# C O M M A N D L I N E\r
1457 //########################################################################\r
1458 \r
1459 public boolean odfToSvg(String odfName, String svgName)\r
1460 {\r
1461 if (!readOdf(odfName))\r
1462 return false;\r
1463 if (!saveSvg(svgName))\r
1464 return false;\r
1465 return true;\r
1466 }\r
1467 \r
1468 public boolean svgToOdf(String svgName, String odfName)\r
1469 {\r
1470 if (!readSvg(svgName))\r
1471 return false;\r
1472 System.out.println("ok");\r
1473 if (!saveOdf(odfName))\r
1474 return false;\r
1475 return true;\r
1476 }\r
1477 \r
1478 void usage()\r
1479 {\r
1480 System.out.println("usage: SvgOdf input_file.odg output_file.svg");\r
1481 System.out.println(" SvgOdf input_file.svg output_file.odg");\r
1482 }\r
1483 \r
1484 \r
1485 boolean parseArguments(String argv[])\r
1486 {\r
1487 if (argv.length != 2)\r
1488 {\r
1489 usage();\r
1490 return false;\r
1491 }\r
1492 \r
1493 String fileName1 = argv[0];\r
1494 String fileName2 = argv[1];\r
1495 \r
1496 if (fileName1.length()<5 || fileName2.length()<5)\r
1497 {\r
1498 System.out.println("one or more file names is too short");\r
1499 usage();\r
1500 return false;\r
1501 }\r
1502 \r
1503 String ext1 = fileName1.substring(fileName1.length()-4);\r
1504 String ext2 = fileName2.substring(fileName2.length()-4);\r
1505 //System.out.println("ext1:"+ext1+" ext2:"+ext2);\r
1506 \r
1507 //##### ODG -> SVG #####\r
1508 if ((ext1.equals(".odg") || ext1.equals(".odf") || ext1.equals(".zip") ) &&\r
1509 ext2.equals(".svg"))\r
1510 {\r
1511 if (!odfToSvg(argv[0], argv[1]))\r
1512 {\r
1513 System.out.println("Conversion from ODG to SVG failed");\r
1514 return false;\r
1515 }\r
1516 }\r
1517 \r
1518 //##### SVG -> ODG #####\r
1519 else if (ext1.equals(".svg") &&\r
1520 ( ext2.equals(".odg") || ext2.equals(".odf") || ext2.equals(".zip") ) )\r
1521 {\r
1522 if (!svgToOdf(fileName1, fileName2))\r
1523 {\r
1524 System.out.println("Conversion from SVG to ODG failed");\r
1525 return false;\r
1526 }\r
1527 }\r
1528 \r
1529 //##### none of the above #####\r
1530 else\r
1531 {\r
1532 usage();\r
1533 return false;\r
1534 }\r
1535 return true;\r
1536 }\r
1537 \r
1538 \r
1539 public static void main(String argv[])\r
1540 {\r
1541 SvgOdg svgodg = new SvgOdg();\r
1542 svgodg.parseArguments(argv);\r
1543 }\r
1544 \r
1545 \r
1546 }\r
1547 \r
1548 //########################################################################\r
1549 //# E N D O F F I L E\r
1550 //########################################################################\r
1551 \r