Code

f5511470174532435c4b0c5d808cdd7e6791e616
[inkscape.git] / src / dom / odf / SvgOdg.cpp
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