1 /**
2 * OpenDocument <drawing> input and output
3 *
4 * This is an an entry in the extensions mechanism to begin to enable
5 * the inputting and outputting of OpenDocument Format (ODF) files from
6 * within Inkscape. Although the initial implementations will be very lossy
7 * do to the differences in the models of SVG and ODF, they will hopefully
8 * improve greatly with time.
9 *
10 * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
11 *
12 * Authors:
13 * Bob Jamison
14 *
15 * Copyright (C) 2006 Bob Jamison
16 *
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public
19 * License as published by the Free Software Foundation; either
20 * version 2.1 of the License, or (at your option) any later version.
21 *
22 * This library is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with this library; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 */
34 #ifdef HAVE_CONFIG_H
35 # include <config.h>
36 #endif
38 #include "odf.h"
40 //# System includes
41 #include <stdio.h>
42 #include <time.h>
43 #include <vector>
46 //# Inkscape includes
47 #include "clear-n_.h"
48 #include "inkscape.h"
49 #include <style.h>
50 #include "display/curve.h"
51 #include "libnr/n-art-bpath.h"
52 #include "extension/system.h"
54 #include "xml/repr.h"
55 #include "xml/attribute-record.h"
56 #include "sp-image.h"
57 #include "sp-path.h"
58 #include "sp-text.h"
59 #include "sp-flowtext.h"
60 #include "svg/svg.h"
61 #include "text-editing.h"
64 //# DOM-specific includes
65 #include "dom/dom.h"
66 #include "dom/util/ziptool.h"
67 #include "dom/io/domstream.h"
68 #include "dom/io/bufferstream.h"
71 //# Shorthand notation
72 typedef org::w3c::dom::DOMString DOMString;
73 typedef org::w3c::dom::io::OutputStreamWriter OutputStreamWriter;
74 typedef org::w3c::dom::io::BufferOutputStream BufferOutputStream;
79 namespace Inkscape
80 {
81 namespace Extension
82 {
83 namespace Internal
84 {
87 //#define pxToCm 0.0275
88 #define pxToCm 0.04
89 #define piToRad 0.0174532925
90 #define docHeightCm 22.86
93 //########################################################################
94 //# O U T P U T
95 //########################################################################
97 static std::string getAttribute( Inkscape::XML::Node *node, char *attrName)
98 {
99 std::string val;
100 char *valstr = (char *)node->attribute(attrName);
101 if (valstr)
102 val = (const char *)valstr;
103 return val;
104 }
107 static std::string getExtension(const std::string &fname)
108 {
109 std::string ext;
111 unsigned int pos = fname.rfind('.');
112 if (pos == fname.npos)
113 {
114 ext = "";
115 }
116 else
117 {
118 ext = fname.substr(pos);
119 }
120 return ext;
121 }
123 /**
124 * Method descends into the repr tree, converting image and style info
125 * into forms compatible in ODF.
126 */
127 void
128 OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node)
129 {
131 std::string nodeName = node->name();
132 std::string id = getAttribute(node, "id");
134 if (nodeName == "image" || nodeName == "svg:image")
135 {
136 //g_message("image");
137 std::string href = getAttribute(node, "xlink:href");
138 if (href.size() > 0)
139 {
140 std::string oldName = href;
141 std::string ext = getExtension(oldName);
142 if (ext == ".jpeg")
143 ext = ".jpg";
144 if (imageTable.find(oldName) == imageTable.end())
145 {
146 char buf[64];
147 snprintf(buf, 63, "Pictures/image%d%s",
148 imageTable.size(), ext.c_str());
149 std::string newName = buf;
150 imageTable[oldName] = newName;
151 std::string comment = "old name was: ";
152 comment.append(oldName);
153 ZipEntry *ze = zf.addFile(oldName, comment);
154 if (ze)
155 {
156 ze->setFileName(newName);
157 }
158 else
159 {
160 g_warning("Could not load image file '%s'", oldName.c_str());
161 }
162 }
163 }
164 }
168 SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node);
169 if (!reprobj)
170 return;
171 if (!SP_IS_ITEM(reprobj))
172 {
173 return;
174 }
175 SPItem *item = SP_ITEM(reprobj);
176 SPStyle *style = SP_OBJECT_STYLE(item);
177 if (style && id.size()>0)
178 {
179 StyleInfo si;
180 if (style->fill.type == SP_PAINT_TYPE_COLOR)
181 {
182 guint32 fillCol =
183 sp_color_get_rgba32_ualpha(&style->fill.value.color, 0);
184 char buf[16];
185 int r = (fillCol >> 24) & 0xff;
186 int g = (fillCol >> 16) & 0xff;
187 int b = (fillCol >> 8) & 0xff;
188 //g_message("## %s %lx", id.c_str(), (unsigned int)fillCol);
189 snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
190 si.fillColor = buf;
191 si.fill = "solid";
192 }
193 if (style->stroke.type == SP_PAINT_TYPE_COLOR)
194 {
195 guint32 strokeCol =
196 sp_color_get_rgba32_ualpha(&style->stroke.value.color, 0);
197 char buf[16];
198 int r = (strokeCol >> 24) & 0xff;
199 int g = (strokeCol >> 16) & 0xff;
200 int b = (strokeCol >> 8) & 0xff;
201 snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
202 si.strokeColor = buf;
203 snprintf(buf, 15, "%.2fpt", style->stroke_width.value);
204 si.strokeWidth = buf;
205 si.stroke = "solid";
206 }
208 styleTable[id] = si;
209 }
211 /*
212 //Look for style values in the svg element
213 Inkscape::Util::List<Inkscape::XML::AttributeRecord const> attr =
214 node->attributeList();
215 for ( ; attr ; ++attr)
216 {
217 if (!attr->key || !attr->value)
218 {
219 g_warning("null key or value in attribute");
220 continue;
221 }
222 //g_message("key:%s value:%s", g_quark_to_string(attr->key),
223 // g_quark_to_string(attr->value) );
225 std::string attrName = (const char *)g_quark_to_string(attr->key);
226 std::string attrValue = (const char *)attr->value;
227 //g_message("tag:'%s' key:'%s' value:'%s'",
228 // nodeName.c_str(), attrName.c_str(), attrValue.c_str() );
229 if (attrName == "style")
230 {
231 StyleInfo si(attrName, attrValue);
232 if (styleTable.find(attrValue) != styleTable.end())
233 {
234 //g_message("duplicate style");
235 }
236 else
237 {
238 char buf[16];
239 snprintf(buf, 15, "style%d", styleTable.size());
240 std::string attrName = buf;
241 //Map from value-->name . Looks backwards, i know
242 styleTable[attrValue] = si;
243 //g_message("mapping '%s' to '%s'",
244 // attrValue.c_str(), attrName.c_str());
245 }
246 }
247 }
248 */
251 for (Inkscape::XML::Node *child = node->firstChild() ;
252 child ; child = child->next())
253 preprocess(zf, child);
254 }
258 bool OdfOutput::writeManifest(ZipFile &zf)
259 {
260 BufferOutputStream bouts;
261 OutputStreamWriter outs(bouts);
263 time_t tim;
264 time(&tim);
266 outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
267 outs.printf("<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">\n");
268 outs.printf("\n");
269 outs.printf("\n");
270 outs.printf("<!--\n");
271 outs.printf("*************************************************************************\n");
272 outs.printf(" file: manifest.xml\n");
273 outs.printf(" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
274 outs.printf(" http://www.inkscape.org\n");
275 outs.printf("*************************************************************************\n");
276 outs.printf("-->\n");
277 outs.printf("\n");
278 outs.printf("\n");
279 outs.printf("<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n");
280 outs.printf(" <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.graphics\" manifest:full-path=\"/\"/>\n");
281 outs.printf(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>\n");
282 outs.printf(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>\n");
283 outs.printf(" <!--List our images here-->\n");
284 std::map<std::string, std::string>::iterator iter;
285 for (iter = imageTable.begin() ; iter!=imageTable.end() ; iter++)
286 {
287 std::string oldName = iter->first;
288 std::string newName = iter->second;
290 std::string ext = getExtension(oldName);
291 if (ext == ".jpeg")
292 ext = ".jpg";
293 outs.printf(" <manifest:file-entry manifest:media-type=\"");
294 if (ext == ".gif")
295 outs.printf("image/gif");
296 else if (ext == ".png")
297 outs.printf("image/png");
298 else if (ext == ".jpg")
299 outs.printf("image/jpeg");
300 outs.printf("\" manifest:full-path=\"");
301 outs.printf((char *)newName.c_str());
302 outs.printf("\"/>\n");
303 }
304 outs.printf("</manifest:manifest>\n");
306 outs.close();
308 //Make our entry
309 ZipEntry *ze = zf.newEntry("META-INF/manifest.xml", "ODF file manifest");
310 ze->setUncompressedData(bouts.getBuffer());
311 ze->finish();
313 return true;
314 }
317 bool OdfOutput::writeMeta(ZipFile &zf)
318 {
319 BufferOutputStream bouts;
320 OutputStreamWriter outs(bouts);
322 time_t tim;
323 time(&tim);
325 outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
326 outs.printf("\n");
327 outs.printf("\n");
328 outs.printf("<!--\n");
329 outs.printf("*************************************************************************\n");
330 outs.printf(" file: meta.xml\n");
331 outs.printf(" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
332 outs.printf(" http://www.inkscape.org\n");
333 outs.printf("*************************************************************************\n");
334 outs.printf("-->\n");
335 outs.printf("\n");
336 outs.printf("\n");
337 outs.printf("<office:document-meta\n");
338 outs.printf("xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
339 outs.printf("xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
340 outs.printf("xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
341 outs.printf("xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
342 outs.printf("xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
343 outs.printf("xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
344 outs.printf("xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
345 outs.printf("xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
346 outs.printf("office:version=\"1.0\">\n");
347 outs.printf("<office:meta>\n");
348 outs.printf(" <meta:generator>Inkscape.org - 0.44</meta:generator>\n");
349 outs.printf(" <meta:initial-creator>clark kent</meta:initial-creator>\n");
350 outs.printf(" <meta:creation-date>2006-04-13T17:12:29</meta:creation-date>\n");
351 outs.printf(" <dc:creator>clark kent</dc:creator>\n");
352 outs.printf(" <dc:date>2006-04-13T17:13:20</dc:date>\n");
353 outs.printf(" <dc:language>en-US</dc:language>\n");
354 outs.printf(" <meta:editing-cycles>2</meta:editing-cycles>\n");
355 outs.printf(" <meta:editing-duration>PT56S</meta:editing-duration>\n");
356 outs.printf(" <meta:user-defined meta:name=\"Info 1\"/>\n");
357 outs.printf(" <meta:user-defined meta:name=\"Info 2\"/>\n");
358 outs.printf(" <meta:user-defined meta:name=\"Info 3\"/>\n");
359 outs.printf(" <meta:user-defined meta:name=\"Info 4\"/>\n");
360 outs.printf(" <meta:document-statistic meta:object-count=\"2\"/>\n");
361 outs.printf("</office:meta>\n");
362 outs.printf("</office:document-meta>\n");
363 outs.printf("\n");
364 outs.printf("\n");
367 outs.close();
369 //Make our entry
370 ZipEntry *ze = zf.newEntry("meta.xml", "ODF info file");
371 ze->setUncompressedData(bouts.getBuffer());
372 ze->finish();
374 return true;
375 }
378 bool OdfOutput::writeStyle(Writer &outs)
379 {
380 outs.printf("<office:automatic-styles>\n");
381 outs.printf("<style:style style:name=\"dp1\" style:family=\"drawing-page\"/>\n");
382 outs.printf("<style:style style:name=\"gr1\" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
383 outs.printf(" <style:graphic-properties draw:stroke=\"none\" draw:fill=\"none\"\n");
384 outs.printf(" draw:textarea-horizontal-align=\"center\"\n");
385 outs.printf(" draw:textarea-vertical-align=\"middle\" draw:color-mode=\"standard\"\n");
386 outs.printf(" draw:luminance=\"0%\" draw:contrast=\"0%\" draw:gamma=\"100%\" draw:red=\"0%\"\n");
387 outs.printf(" draw:green=\"0%\" draw:blue=\"0%\" fo:clip=\"rect(0cm 0cm 0cm 0cm)\"\n");
388 outs.printf(" draw:image-opacity=\"100%\" style:mirror=\"none\"/>\n");
389 outs.printf("</style:style>\n");
390 outs.printf("<style:style style:name=\"P1\" style:family=\"paragraph\">\n");
391 outs.printf(" <style:paragraph-properties fo:text-align=\"center\"/>\n");
392 outs.printf("</style:style>\n");
394 //## Dump our style table
395 std::map<std::string, StyleInfo>::iterator iter;
396 for (iter = styleTable.begin() ; iter != styleTable.end() ; iter++)
397 {
398 outs.printf("<style:style style:name=\"%s\"", iter->first.c_str());
399 StyleInfo s(iter->second);
400 outs.printf(" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
401 outs.printf(" <style:graphic-properties");
402 outs.printf(" draw:fill=\"%s\" ", s.getFill().c_str());
403 if (s.getFill() != "none")
404 outs.printf(" draw:fill-color=\"%s\" ", s.getFillColor().c_str());
405 outs.printf(" draw:stroke=\"%s\" ", s.getStroke().c_str());
406 if (s.getStroke() != "none")
407 {
408 outs.printf(" svg:stroke-width=\"%s\" ", s.getStrokeWidth().c_str());
409 outs.printf(" svg:stroke-color=\"%s\" ", s.getStrokeColor().c_str());
410 }
411 outs.printf("/>\n");
412 outs.printf("</style:style>\n");
413 }
415 outs.printf("</office:automatic-styles>\n");
416 outs.printf("\n");
418 return true;
419 }
422 static void
423 writePath(Writer &outs, NArtBpath const *bpath,
424 NR::Matrix &tf, double xoff, double yoff)
425 {
426 bool closed = false;
427 NArtBpath *bp = (NArtBpath *)bpath;
428 for ( ; bp->code != NR_END; bp++)
429 {
430 NR::Point const p1(bp->c(1) * tf);
431 NR::Point const p2(bp->c(2) * tf);
432 NR::Point const p3(bp->c(3) * tf);
433 double x1 = (p1[NR::X] * pxToCm - xoff) * 1000.0;
434 double y1 = (p1[NR::Y] * pxToCm - yoff) * 1000.0;
435 double x2 = (p2[NR::X] * pxToCm - xoff) * 1000.0;
436 double y2 = (p2[NR::Y] * pxToCm - yoff) * 1000.0;
437 double x3 = (p3[NR::X] * pxToCm - xoff) * 1000.0;
438 double y3 = (p3[NR::Y] * pxToCm - yoff) * 1000.0;
440 switch (bp->code)
441 {
442 case NR_LINETO:
443 outs.printf("L %.3f,%.3f ", x3 , y3);
444 break;
446 case NR_CURVETO:
447 outs.printf("C %.3f,%.3f %.3f,%.3f %.3f,%.3f ",
448 x1, y1, x2, y2, x3, y3);
449 break;
451 case NR_MOVETO_OPEN:
452 case NR_MOVETO:
453 if (closed)
454 outs.printf("z ");
455 closed = ( bp->code == NR_MOVETO );
456 outs.printf("M %.3f,%.3f ", x3 , y3);
457 break;
459 default:
460 break;
462 }
464 }
466 if (closed)
467 outs.printf("z");;
469 }
473 bool OdfOutput::writeTree(Writer &outs, Inkscape::XML::Node *node)
474 {
475 //# Get the SPItem, if applicable
476 SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node);
477 if (!reprobj)
478 return true;
479 if (!SP_IS_ITEM(reprobj))
480 {
481 return true;
482 }
483 SPItem *item = SP_ITEM(reprobj);
485 std::string nodeName = node->name();
486 std::string id = getAttribute(node, "id");
488 NR::Matrix tf = sp_item_i2d_affine(item);
489 NR::Rect bbox = sp_item_bbox_desktop(item);
491 //Flip Y into document coordinates
492 double svgHeight = sp_document_height(SP_ACTIVE_DOCUMENT);
493 double doc_height = svgHeight; // * pxToCm;
494 NR::Matrix doc2dt_tf = NR::Matrix(NR::scale(1, -1));
495 doc2dt_tf = doc2dt_tf * NR::Matrix(NR::translate(0, doc_height));
496 tf = tf * doc2dt_tf;
497 bbox = bbox * doc2dt_tf;
499 double x = pxToCm * bbox.min()[NR::X];
500 double y = pxToCm * bbox.min()[NR::Y];
501 double width = pxToCm * ( bbox.max()[NR::X] - bbox.min()[NR::X] );
502 double height = pxToCm * ( bbox.max()[NR::Y] - bbox.min()[NR::Y] );
505 //# Do our stuff
506 SPCurve *curve = NULL;
508 //g_message("##### %s #####", nodeName.c_str());
510 if (nodeName == "svg" || nodeName == "svg:svg")
511 {
512 //# Iterate through the children
513 for (Inkscape::XML::Node *child = node->firstChild() ; child ; child = child->next())
514 {
515 if (!writeTree(outs, child))
516 return false;
517 }
518 return true;
519 }
520 else if (nodeName == "g" || nodeName == "svg:g")
521 {
522 if (id.size() > 0)
523 outs.printf("<draw:g id=\"%s\">", id.c_str());
524 else
525 outs.printf("<draw:g>\n");
526 //# Iterate through the children
527 for (Inkscape::XML::Node *child = node->firstChild() ; child ; child = child->next())
528 {
529 if (!writeTree(outs, child))
530 return false;
531 }
532 outs.printf("</draw:g>\n");
533 return true;
534 }
535 else if (nodeName == "image" || nodeName == "svg:image")
536 {
537 std::string href = getAttribute(node, "xlink:href");
538 std::map<std::string, std::string>::iterator iter = imageTable.find(href);
539 if (iter == imageTable.end())
540 {
541 g_warning("image '%s' not in table", href.c_str());
542 return false;
543 }
544 std::string newName = iter->second;
546 outs.printf("<draw:frame ");
547 if (id.size() > 0)
548 outs.printf("id=\"%s\" ", id.c_str());
549 outs.printf("draw:style-name=\"gr1\" draw:text-style-name=\"P1\" draw:layer=\"layout\" ");
550 outs.printf("svg:x=\"%.3fcm\" svg:y=\"%.3fcm\" ",
551 x, y, width);
552 outs.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\">\n",
553 width, height);
555 outs.printf(" <draw:image xlink:href=\"%s\" xlink:type=\"simple\"\n",
556 newName.c_str());
557 outs.printf(" xlink:show=\"embed\" xlink:actuate=\"onLoad\">\n");
558 outs.printf(" <text:p/>\n");
559 outs.printf(" </draw:image>\n");
560 outs.printf("</draw:frame>\n");
561 return true;
562 }
563 else if (SP_IS_SHAPE(item))
564 {
565 //g_message("### %s is a shape", nodeName.c_str());
566 curve = sp_shape_get_curve(SP_SHAPE(item));
567 }
568 else if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))
569 {
570 curve = te_get_layout(item)->convertToCurves();
571 }
573 if (curve)
574 {
575 //Inkscape::XML::Node *repr = sp_repr_new("svg:path");
576 /* Transformation */
577 //repr->setAttribute("transform", SP_OBJECT_REPR(item)->attribute("transform"));
579 /* Rotation center */
580 //sp_repr_set_attr(repr, "inkscape:transform-center-x", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-x"));
581 //sp_repr_set_attr(repr, "inkscape:transform-center-y", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-y"));
583 /* Definition */
585 outs.printf("<draw:path ");
586 if (id.size()>0)
587 outs.printf("id=\"%s\" ", id.c_str());
589 std::map<std::string, StyleInfo>::iterator iter;
590 iter = styleTable.find(id);
591 if (iter != styleTable.end())
592 outs.printf("draw:style-name=\"%s\" ", id.c_str());
594 outs.printf("draw:layer=\"layout\" svg:x=\"%.3fcm\" svg:y=\"%.3fcm\" ",
595 x, y);
596 outs.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
597 width, height);
598 outs.printf("svg:viewBox=\"0.0 0.0 %.3f %.3f\"\n",
599 width * 1000.0, height * 1000.0);
601 outs.printf(" svg:d=\"");
602 writePath(outs, curve->bpath, tf, x, y);
603 outs.printf("\"");
605 outs.printf(">\n");
606 outs.printf("</draw:path>\n");
609 sp_curve_unref(curve);
610 }
612 return true;
613 }
618 bool OdfOutput::writeContent(ZipFile &zf, Inkscape::XML::Node *node)
619 {
620 BufferOutputStream bouts;
621 OutputStreamWriter outs(bouts);
623 time_t tim;
624 time(&tim);
626 outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
627 outs.printf("\n");
628 outs.printf("\n");
629 outs.printf("<!--\n");
630 outs.printf("*************************************************************************\n");
631 outs.printf(" file: content.xml\n");
632 outs.printf(" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
633 outs.printf(" http://www.inkscape.org\n");
634 outs.printf("*************************************************************************\n");
635 outs.printf("-->\n");
636 outs.printf("\n");
637 outs.printf("\n");
638 outs.printf("<office:document-content\n");
639 outs.printf(" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
640 outs.printf(" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");
641 outs.printf(" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");
642 outs.printf(" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");
643 outs.printf(" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");
644 outs.printf(" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");
645 outs.printf(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
646 outs.printf(" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
647 outs.printf(" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
648 outs.printf(" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");
649 outs.printf(" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
650 outs.printf(" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");
651 outs.printf(" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");
652 outs.printf(" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");
653 outs.printf(" xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");
654 outs.printf(" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");
655 outs.printf(" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");
656 outs.printf(" xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
657 outs.printf(" xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");
658 outs.printf(" xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");
659 outs.printf(" xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");
660 outs.printf(" xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");
661 outs.printf(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
662 outs.printf(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
663 outs.printf(" xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
664 outs.printf(" xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
665 outs.printf(" office:version=\"1.0\">\n");
666 outs.printf("\n");
667 outs.printf("\n");
668 outs.printf("<office:scripts/>\n");
669 outs.printf("\n");
670 outs.printf("\n");
671 //AffineTransform trans = new AffineTransform();
672 //trans.scale(12.0, 12.0);
673 outs.printf("<!-- ######### CONVERSION FROM SVG STARTS ######## -->\n");
674 outs.printf("<!--\n");
675 outs.printf("*************************************************************************\n");
676 outs.printf(" S T Y L E S\n");
677 outs.printf(" Style entries have been pulled from the svg style and\n");
678 outs.printf(" representation attributes in the SVG tree. The tree elements\n");
679 outs.printf(" then refer to them by name, in the ODF manner\n");
680 outs.printf("*************************************************************************\n");
681 outs.printf("-->\n");
682 outs.printf("\n");
683 outs.printf("\n");
685 if (!writeStyle(outs))
686 {
687 g_warning("Failed to write styles");
688 return false;
689 }
691 outs.printf("\n");
692 outs.printf("\n");
693 outs.printf("\n");
694 outs.printf("\n");
695 outs.printf("<!--\n");
696 outs.printf("*************************************************************************\n");
697 outs.printf(" D R A W I N G\n");
698 outs.printf(" This section is the heart of SVG-ODF conversion. We are\n");
699 outs.printf(" starting with simple conversions, and will slowly evolve\n");
700 outs.printf(" into a 'smarter' translation as time progresses. Any help\n");
701 outs.printf(" in improving .odg export is welcome.\n");
702 outs.printf("*************************************************************************\n");
703 outs.printf("-->\n");
704 outs.printf("\n");
705 outs.printf("\n");
706 outs.printf("<office:body>\n");
707 outs.printf("<office:drawing>\n");
708 outs.printf("<draw:page draw:name=\"page1\" draw:style-name=\"dp1\"\n");
709 outs.printf(" draw:master-page-name=\"Default\">\n");
710 outs.printf("\n");
711 outs.printf("\n");
713 if (!writeTree(outs, node))
714 {
715 g_warning("Failed to convert SVG tree");
716 return false;
717 }
719 outs.printf("\n");
720 outs.printf("\n");
722 outs.printf("</draw:page>\n");
723 outs.printf("</office:drawing>\n");
725 outs.printf("\n");
726 outs.printf("\n");
727 outs.printf("<!-- ######### CONVERSION FROM SVG ENDS ######## -->\n");
728 outs.printf("\n");
729 outs.printf("\n");
731 outs.printf("</office:body>\n");
732 outs.printf("</office:document-content>\n");
733 outs.printf("\n");
734 outs.printf("\n");
735 outs.printf("\n");
736 outs.printf("<!--\n");
737 outs.printf("*************************************************************************\n");
738 outs.printf(" E N D O F F I L E\n");
739 outs.printf(" Have a nice day - ishmal\n");
740 outs.printf("*************************************************************************\n");
741 outs.printf("-->\n");
742 outs.printf("\n");
743 outs.printf("\n");
747 //Make our entry
748 ZipEntry *ze = zf.newEntry("content.xml", "ODF master content file");
749 ze->setUncompressedData(bouts.getBuffer());
750 ze->finish();
752 return true;
753 }
758 /**
759 * Descends into the SVG tree, mapping things to ODF when appropriate
760 */
761 void
762 OdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *uri)
763 {
764 ZipFile zf;
765 styleTable.clear();
766 imageTable.clear();
767 preprocess(zf, doc->rroot);
769 if (!writeManifest(zf))
770 {
771 g_warning("Failed to write manifest");
772 return;
773 }
775 if (!writeMeta(zf))
776 {
777 g_warning("Failed to write metafile");
778 return;
779 }
781 if (!writeContent(zf, doc->rroot))
782 {
783 g_warning("Failed to write content");
784 return;
785 }
787 if (!zf.writeFile(uri))
788 {
789 return;
790 }
791 }
794 /**
795 * This is the definition of PovRay output. This function just
796 * calls the extension system with the memory allocated XML that
797 * describes the data.
798 */
799 void
800 OdfOutput::init()
801 {
802 Inkscape::Extension::build_from_mem(
803 "<inkscape-extension>\n"
804 "<name>" N_("OpenDocument Drawing Output") "</name>\n"
805 "<id>org.inkscape.output.odf</id>\n"
806 "<output>\n"
807 "<extension>.odg</extension>\n"
808 "<mimetype>text/x-povray-script</mimetype>\n"
809 "<filetypename>" N_("OpenDocument drawing (*.odg)") "</filetypename>\n"
810 "<filetypetooltip>" N_("OpenDocument drawing file") "</filetypetooltip>\n"
811 "</output>\n"
812 "</inkscape-extension>",
813 new OdfOutput());
814 }
816 /**
817 * Make sure that we are in the database
818 */
819 bool
820 OdfOutput::check (Inkscape::Extension::Extension *module)
821 {
822 /* We don't need a Key
823 if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_POV))
824 return FALSE;
825 */
827 return TRUE;
828 }
832 //########################################################################
833 //# I N P U T
834 //########################################################################
838 //#######################
839 //# L A T E R !!! :-)
840 //#######################
854 } //namespace Internal
855 } //namespace Extension
856 } //namespace Inkscape
859 //########################################################################
860 //# E N D O F F I L E
861 //########################################################################
863 /*
864 Local Variables:
865 mode:c++
866 c-file-style:"stroustrup"
867 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
868 indent-tabs-mode:nil
869 fill-column:99
870 End:
871 */
872 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :