Code

remove duplicate styles, add placeholders for opacities
[inkscape.git] / src / extension / internal / odf.cpp
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;
107 static std::string getExtension(const std::string &fname)
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;
124 static std::string formatTransform(NR::Matrix &tf)
126     std::string str;
127     if (!tf.test_identity())
128         {
129         char buf[128];
130         snprintf(buf, 127, "matrix(%.3f %.3f %.3f %.3f %.3f %.3f)",
131                 tf[0], tf[1], tf[2], tf[3], tf[4], tf[5]);
132         str = buf;
133         }
134     return str;
138 /**
139  * Method descends into the repr tree, converting image and style info
140  * into forms compatible in ODF.
141  */
142 void
143 OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node)
146     std::string nodeName = node->name();
147     std::string id       = getAttribute(node, "id");
149     if (nodeName == "image" || nodeName == "svg:image")
150         {
151         //g_message("image");
152         std::string href = getAttribute(node, "xlink:href");
153         if (href.size() > 0)
154             {
155             std::string oldName = href;
156             std::string ext = getExtension(oldName);
157             if (ext == ".jpeg")
158                 ext = ".jpg";
159             if (imageTable.find(oldName) == imageTable.end())
160                 {
161                 char buf[64];
162                 snprintf(buf, 63, "Pictures/image%d%s",
163                     imageTable.size(), ext.c_str());
164                 std::string newName = buf;
165                 imageTable[oldName] = newName;
166                 std::string comment = "old name was: ";
167                 comment.append(oldName);
168                 ZipEntry *ze = zf.addFile(oldName, comment);
169                 if (ze)
170                     {
171                     ze->setFileName(newName);
172                     }
173                 else
174                     {
175                     g_warning("Could not load image file '%s'", oldName.c_str());
176                     }
177                 }
178             }
179         }
183     SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node);
184     if (!reprobj)
185         return;
186     if (!SP_IS_ITEM(reprobj))
187         {
188         return;
189         }
190     SPItem *item = SP_ITEM(reprobj);
191     SPStyle *style = SP_OBJECT_STYLE(item);
192     if (style && id.size()>0)
193         {
194         StyleInfo si;
195         if (style->fill.type == SP_PAINT_TYPE_COLOR)
196             {
197             guint32 fillCol =
198                 sp_color_get_rgba32_ualpha(&style->fill.value.color, 0);
199             char buf[16];
200             int r = (fillCol >> 24) & 0xff;
201             int g = (fillCol >> 16) & 0xff;
202             int b = (fillCol >>  8) & 0xff;
203             //g_message("## %s %lx", id.c_str(), (unsigned int)fillCol);
204             snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
205             si.fillColor = buf;
206             si.fill      = "solid";
207             double opacityPercent = 100.0;
208             snprintf(buf, 15, "%.2f%%", opacityPercent);
209             si.fillOpacity = buf;
210             }
211         if (style->stroke.type == SP_PAINT_TYPE_COLOR)
212             {
213             guint32 strokeCol =
214                 sp_color_get_rgba32_ualpha(&style->stroke.value.color, 0);
215             char buf[16];
216             int r = (strokeCol >> 24) & 0xff;
217             int g = (strokeCol >> 16) & 0xff;
218             int b = (strokeCol >>  8) & 0xff;
219             snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
220             si.strokeColor = buf;
221             snprintf(buf, 15, "%.2fpt", style->stroke_width.value);
222             si.strokeWidth = buf;
223             si.stroke      = "solid";
224             double opacityPercent = 100.0;
225             snprintf(buf, 15, "%.2f%%", opacityPercent);
226             si.strokeOpacity = buf;
227             }
229         //Look for existing identical style;
230         bool styleMatch = false;
231         std::map<std::string, StyleInfo>::iterator iter;
232         for (iter=styleTable.begin() ; iter!=styleTable.end() ; iter++)
233             {
234             if (si.equals(iter->second))
235                 {
236                 //map to existing styleTable entry
237                 std::string styleName = iter->first;
238                 //g_message("found duplicate style:%s", styleName.c_str());
239                 styleLookupTable[id] = styleName;
240                 styleMatch = true;
241                 break;
242                 }
243             }
244         //None found, make a new pair or entries
245         if (!styleMatch)
246             {
247             char buf[16];
248             snprintf(buf, 15, "style%d", styleTable.size());
249             std::string styleName = buf;
250             styleTable[styleName] = si;
251             styleLookupTable[id] = styleName;
252             }
253         }
255     /*
256     //Look for style values in the svg element
257     Inkscape::Util::List<Inkscape::XML::AttributeRecord const> attr =
258         node->attributeList();
259     for ( ; attr ; ++attr)
260         {
261         if (!attr->key || !attr->value)
262             {
263             g_warning("null key or value in attribute");
264             continue;
265             }
266         //g_message("key:%s value:%s", g_quark_to_string(attr->key),
267         //                             g_quark_to_string(attr->value)  );
269         std::string attrName  = (const char *)g_quark_to_string(attr->key);
270         std::string attrValue = (const char *)attr->value;
271         //g_message("tag:'%s'    key:'%s'    value:'%s'",
272         //    nodeName.c_str(), attrName.c_str(), attrValue.c_str()  );
273         if (attrName == "style")
274             {
275             StyleInfo si(attrName, attrValue);
276             if (styleTable.find(attrValue) != styleTable.end())
277                 {
278                 //g_message("duplicate style");
279                 }
280             else
281                 {
282                 char buf[16];
283                 snprintf(buf, 15, "style%d", styleTable.size());
284                 std::string attrName  = buf;
285                 //Map from value-->name .   Looks backwards, i know
286                 styleTable[attrValue] = si;
287                 //g_message("mapping '%s' to '%s'",
288                 //    attrValue.c_str(), attrName.c_str());
289                 }
290             }
291         }
292     */
295     for (Inkscape::XML::Node *child = node->firstChild() ;
296             child ; child = child->next())
297         preprocess(zf, child);
302 bool OdfOutput::writeManifest(ZipFile &zf)
304     BufferOutputStream bouts;
305     OutputStreamWriter outs(bouts);
307     time_t tim;
308     time(&tim);
310     outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
311     outs.printf("<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">\n");
312     outs.printf("\n");
313     outs.printf("\n");
314     outs.printf("<!--\n");
315     outs.printf("*************************************************************************\n");
316     outs.printf("  file:  manifest.xml\n");
317     outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
318     outs.printf("  http://www.inkscape.org\n");
319     outs.printf("*************************************************************************\n");
320     outs.printf("-->\n");
321     outs.printf("\n");
322     outs.printf("\n");
323     outs.printf("<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n");
324     outs.printf("    <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.graphics\" manifest:full-path=\"/\"/>\n");
325     outs.printf("    <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>\n");
326     outs.printf("    <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>\n");
327     outs.printf("    <!--List our images here-->\n");
328     std::map<std::string, std::string>::iterator iter;
329     for (iter = imageTable.begin() ; iter!=imageTable.end() ; iter++)
330         {
331         std::string oldName = iter->first;
332         std::string newName = iter->second;
334         std::string ext = getExtension(oldName);
335         if (ext == ".jpeg")
336             ext = ".jpg";
337         outs.printf("    <manifest:file-entry manifest:media-type=\"");
338         if (ext == ".gif")
339             outs.printf("image/gif");
340         else if (ext == ".png")
341             outs.printf("image/png");
342         else if (ext == ".jpg")
343             outs.printf("image/jpeg");
344         outs.printf("\" manifest:full-path=\"");
345         outs.printf((char *)newName.c_str());
346         outs.printf("\"/>\n");
347         }
348     outs.printf("</manifest:manifest>\n");
350     outs.close();
352     //Make our entry
353     ZipEntry *ze = zf.newEntry("META-INF/manifest.xml", "ODF file manifest");
354     ze->setUncompressedData(bouts.getBuffer());
355     ze->finish();
357     return true;
361 bool OdfOutput::writeMeta(ZipFile &zf)
363     BufferOutputStream bouts;
364     OutputStreamWriter outs(bouts);
366     time_t tim;
367     time(&tim);
369     outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
370     outs.printf("\n");
371     outs.printf("\n");
372     outs.printf("<!--\n");
373     outs.printf("*************************************************************************\n");
374     outs.printf("  file:  meta.xml\n");
375     outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
376     outs.printf("  http://www.inkscape.org\n");
377     outs.printf("*************************************************************************\n");
378     outs.printf("-->\n");
379     outs.printf("\n");
380     outs.printf("\n");
381     outs.printf("<office:document-meta\n");
382     outs.printf("xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
383     outs.printf("xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
384     outs.printf("xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
385     outs.printf("xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
386     outs.printf("xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
387     outs.printf("xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
388     outs.printf("xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
389     outs.printf("xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
390     outs.printf("office:version=\"1.0\">\n");
391     outs.printf("<office:meta>\n");
392     outs.printf("    <meta:generator>Inkscape.org - 0.44</meta:generator>\n");
393     outs.printf("    <meta:initial-creator>clark kent</meta:initial-creator>\n");
394     outs.printf("    <meta:creation-date>2006-04-13T17:12:29</meta:creation-date>\n");
395     outs.printf("    <dc:creator>clark kent</dc:creator>\n");
396     outs.printf("    <dc:date>2006-04-13T17:13:20</dc:date>\n");
397     outs.printf("    <dc:language>en-US</dc:language>\n");
398     outs.printf("    <meta:editing-cycles>2</meta:editing-cycles>\n");
399     outs.printf("    <meta:editing-duration>PT56S</meta:editing-duration>\n");
400     outs.printf("    <meta:user-defined meta:name=\"Info 1\"/>\n");
401     outs.printf("    <meta:user-defined meta:name=\"Info 2\"/>\n");
402     outs.printf("    <meta:user-defined meta:name=\"Info 3\"/>\n");
403     outs.printf("    <meta:user-defined meta:name=\"Info 4\"/>\n");
404     outs.printf("    <meta:document-statistic meta:object-count=\"2\"/>\n");
405     outs.printf("</office:meta>\n");
406     outs.printf("</office:document-meta>\n");
407     outs.printf("\n");
408     outs.printf("\n");
411     outs.close();
413     //Make our entry
414     ZipEntry *ze = zf.newEntry("meta.xml", "ODF info file");
415     ze->setUncompressedData(bouts.getBuffer());
416     ze->finish();
418     return true;
422 bool OdfOutput::writeStyle(Writer &outs)
424     outs.printf("<office:automatic-styles>\n");
425     outs.printf("<style:style style:name=\"dp1\" style:family=\"drawing-page\"/>\n");
426     outs.printf("<style:style style:name=\"gr1\" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
427     outs.printf("  <style:graphic-properties draw:stroke=\"none\" draw:fill=\"none\"\n");
428     outs.printf("       draw:textarea-horizontal-align=\"center\"\n");
429     outs.printf("       draw:textarea-vertical-align=\"middle\" draw:color-mode=\"standard\"\n");
430     outs.printf("       draw:luminance=\"0%\" draw:contrast=\"0%\" draw:gamma=\"100%\" draw:red=\"0%\"\n");
431     outs.printf("       draw:green=\"0%\" draw:blue=\"0%\" fo:clip=\"rect(0cm 0cm 0cm 0cm)\"\n");
432     outs.printf("       draw:image-opacity=\"100%\" style:mirror=\"none\"/>\n");
433     outs.printf("</style:style>\n");
434     outs.printf("<style:style style:name=\"P1\" style:family=\"paragraph\">\n");
435     outs.printf("  <style:paragraph-properties fo:text-align=\"center\"/>\n");
436     outs.printf("</style:style>\n");
438     //##  Dump our style table
439     std::map<std::string, StyleInfo>::iterator iter;
440     for (iter = styleTable.begin() ; iter != styleTable.end() ; iter++)
441         {
442         outs.printf("<style:style style:name=\"%s\"", iter->first.c_str());
443         StyleInfo s(iter->second);
444         outs.printf(" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
445         outs.printf("  <style:graphic-properties");
446         outs.printf(" draw:fill=\"%s\" ", s.fill.c_str());
447         if (s.fill != "none")
448             {
449             outs.printf(" draw:fill-color=\"%s\" ", s.fillColor.c_str());
450             outs.printf(" draw:fill-opacity=\"%s\" ", s.fillOpacity.c_str());
451             }
452         outs.printf(" draw:stroke=\"%s\" ", s.stroke.c_str());
453         if (s.stroke != "none")
454             {
455             outs.printf(" svg:stroke-width=\"%s\" ", s.strokeWidth.c_str());
456             outs.printf(" svg:stroke-color=\"%s\" ", s.strokeColor.c_str());
457             outs.printf(" svg:stroke-opacity=\"%s\" ", s.strokeOpacity.c_str());
458             }
459         outs.printf("/>\n");
460         outs.printf("</style:style>\n");
461         }
463     outs.printf("</office:automatic-styles>\n");
464     outs.printf("\n");
466     return true;
470 static void
471 writePath(Writer &outs, NArtBpath const *bpath,
472           NR::Matrix &tf, double xoff, double yoff)
474     bool closed = false;
475     NArtBpath *bp = (NArtBpath *)bpath;
476     for (  ; bp->code != NR_END; bp++)
477         {
478         NR::Point const p1(bp->c(1) * tf);
479         NR::Point const p2(bp->c(2) * tf);
480         NR::Point const p3(bp->c(3) * tf);
481         double x1 = (p1[NR::X] * pxToCm - xoff) * 1000.0;
482         double y1 = (p1[NR::Y] * pxToCm - yoff) * 1000.0;
483         double x2 = (p2[NR::X] * pxToCm - xoff) * 1000.0;
484         double y2 = (p2[NR::Y] * pxToCm - yoff) * 1000.0;
485         double x3 = (p3[NR::X] * pxToCm - xoff) * 1000.0;
486         double y3 = (p3[NR::Y] * pxToCm - yoff) * 1000.0;
488         switch (bp->code)
489             {
490             case NR_LINETO:
491                 outs.printf("L %.3f,%.3f ",  x3 , y3);
492                 break;
494             case NR_CURVETO:
495                 outs.printf("C %.3f,%.3f %.3f,%.3f %.3f,%.3f ",
496                               x1, y1, x2, y2, x3, y3);
497                 break;
499             case NR_MOVETO_OPEN:
500             case NR_MOVETO:
501                 if (closed)
502                     outs.printf("z ");
503                 closed = ( bp->code == NR_MOVETO );
504                 outs.printf("M %.3f,%.3f ",  x3 , y3);
505                 break;
507             default:
508                 break;
510             }
512         }
514     if (closed)
515         outs.printf("z");;
521 bool OdfOutput::writeTree(Writer &outs, Inkscape::XML::Node *node)
523     //# Get the SPItem, if applicable
524     SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node);
525     if (!reprobj)
526         return true;
527     if (!SP_IS_ITEM(reprobj))
528         {
529         return true;
530         }
531     SPItem *item = SP_ITEM(reprobj);
534     std::string nodeName = node->name();
535     std::string id       = getAttribute(node, "id");
537     NR::Matrix tf  = sp_item_i2d_affine(item);
538     NR::Rect bbox = sp_item_bbox_desktop(item);
540     //Flip Y into document coordinates
541     double doc_height = sp_document_height(SP_ACTIVE_DOCUMENT);
542     NR::Matrix doc2dt_tf = NR::Matrix(NR::scale(1, -1));
543     doc2dt_tf = doc2dt_tf * NR::Matrix(NR::translate(0, doc_height));
544     //tf            = tf   * doc2dt_tf;
545     //bbox          = bbox * doc2dt_tf;
547     double x      = pxToCm * bbox.min()[NR::X];
548     double y      = pxToCm * bbox.min()[NR::Y];
549     double width  = pxToCm * ( bbox.max()[NR::X] - bbox.min()[NR::X] );
550     double height = pxToCm * ( bbox.max()[NR::Y] - bbox.min()[NR::Y] );
553     //# Do our stuff
554     SPCurve *curve = NULL;
556     //g_message("##### %s #####", nodeName.c_str());
558     if (nodeName == "svg" || nodeName == "svg:svg")
559         {
560         //# Iterate through the children
561         for (Inkscape::XML::Node *child = node->firstChild() ; child ; child = child->next())
562             {
563             if (!writeTree(outs, child))
564                 return false;
565             }
566         return true;
567         }
568     else if (nodeName == "g" || nodeName == "svg:g")
569         {
570         if (id.size() > 0)
571             outs.printf("<draw:g id=\"%s\">", id.c_str());
572         else
573             outs.printf("<draw:g>\n");
574         //# Iterate through the children
575         for (Inkscape::XML::Node *child = node->firstChild() ; child ; child = child->next())
576             {
577             if (!writeTree(outs, child))
578                 return false;
579             }
580         outs.printf("</draw:g>\n");
581         return true;
582         }
583     else if (nodeName == "image" || nodeName == "svg:image")
584         {
585         if (!SP_IS_IMAGE(item))
586             {
587             g_warning("<image> is not an SPImage.  Why?  ;-)");
588             return false;
589             }
591         SPImage *img   = SP_IMAGE(item);
592         double ix      = img->x.computed;
593         double iy      = img->y.computed;
594         double iwidth  = img->width.computed;
595         double iheight = img->height.computed;
597         NR::Rect ibbox(NR::Point(ix, iy), NR::Point(iwidth, iheight));
598         ix      = pxToCm * ibbox.min()[NR::X];
599         iy      = pxToCm * ibbox.min()[NR::Y];
600         iwidth  = pxToCm * ( ibbox.max()[NR::X] - ibbox.min()[NR::X] );
601         iheight = pxToCm * ( ibbox.max()[NR::Y] - ibbox.min()[NR::Y] );
604         std::string itemTransformString = formatTransform(item->transform);
606         std::string href = getAttribute(node, "xlink:href");
607         std::map<std::string, std::string>::iterator iter = imageTable.find(href);
608         if (iter == imageTable.end())
609             {
610             g_warning("image '%s' not in table", href.c_str());
611             return false;
612             }
613         std::string newName = iter->second;
616         outs.printf("<draw:frame ");
617         if (id.size() > 0)
618             outs.printf("id=\"%s\" ", id.c_str());
619         outs.printf("draw:style-name=\"gr1\" draw:text-style-name=\"P1\" draw:layer=\"layout\" ");
620         outs.printf("svg:x=\"%.3fcm\" svg:y=\"%.3fcm\" ",
621                                   ix, iy);
622         outs.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
623                                   iwidth, iheight);
624         if (itemTransformString.size() > 0)
625             outs.printf("draw:transform=\"%s\" ", itemTransformString.c_str());
627         outs.printf(">\n");
628         outs.printf("    <draw:image xlink:href=\"%s\" xlink:type=\"simple\"\n",
629                               newName.c_str());
630         outs.printf("        xlink:show=\"embed\" xlink:actuate=\"onLoad\">\n");
631         outs.printf("        <text:p/>\n");
632         outs.printf("    </draw:image>\n");
633         outs.printf("</draw:frame>\n");
634         return true;
635         }
636     else if (SP_IS_SHAPE(item))
637         {
638         //g_message("### %s is a shape", nodeName.c_str());
639         curve = sp_shape_get_curve(SP_SHAPE(item));
640         }
641     else if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))
642         {
643         curve = te_get_layout(item)->convertToCurves();
644         }
646     if (curve)
647         {
648         //Inkscape::XML::Node *repr = sp_repr_new("svg:path");
649         /* Transformation */
650         //repr->setAttribute("transform", SP_OBJECT_REPR(item)->attribute("transform"));
652         /* Rotation center */
653         //sp_repr_set_attr(repr, "inkscape:transform-center-x", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-x"));
654         //sp_repr_set_attr(repr, "inkscape:transform-center-y", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-y"));
656         /* Definition */
658         outs.printf("<draw:path ");
659         if (id.size()>0)
660             outs.printf("id=\"%s\" ", id.c_str());
662         std::map<std::string, std::string>::iterator iter;
663         iter = styleLookupTable.find(id);
664         if (iter != styleLookupTable.end())
665             {
666             std::string styleName = iter->second;
667             outs.printf("draw:style-name=\"%s\" ", styleName.c_str());
668             }
670         outs.printf("draw:layer=\"layout\" svg:x=\"%.3fcm\" svg:y=\"%.3fcm\" ",
671                        x, y);
672         outs.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
673                        width, height);
674         outs.printf("svg:viewBox=\"0.0 0.0 %.3f %.3f\"\n",
675                        width * 1000.0, height * 1000.0);
677         outs.printf("    svg:d=\"");
678         writePath(outs, curve->bpath, tf, x, y);
679         outs.printf("\"");
681         outs.printf(">\n");
682         outs.printf("</draw:path>\n");
685         sp_curve_unref(curve);
686         }
688     return true;
694 bool OdfOutput::writeContent(ZipFile &zf, Inkscape::XML::Node *node)
696     BufferOutputStream bouts;
697     OutputStreamWriter outs(bouts);
699     time_t tim;
700     time(&tim);
702     outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
703     outs.printf("\n");
704     outs.printf("\n");
705     outs.printf("<!--\n");
706     outs.printf("*************************************************************************\n");
707     outs.printf("  file:  content.xml\n");
708     outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
709     outs.printf("  http://www.inkscape.org\n");
710     outs.printf("*************************************************************************\n");
711     outs.printf("-->\n");
712     outs.printf("\n");
713     outs.printf("\n");
714     outs.printf("<office:document-content\n");
715     outs.printf("    xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
716     outs.printf("    xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");
717     outs.printf("    xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");
718     outs.printf("    xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");
719     outs.printf("    xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");
720     outs.printf("    xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");
721     outs.printf("    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
722     outs.printf("    xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
723     outs.printf("    xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
724     outs.printf("    xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");
725     outs.printf("    xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
726     outs.printf("    xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");
727     outs.printf("    xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");
728     outs.printf("    xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");
729     outs.printf("    xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");
730     outs.printf("    xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");
731     outs.printf("    xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");
732     outs.printf("    xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
733     outs.printf("    xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");
734     outs.printf("    xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");
735     outs.printf("    xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");
736     outs.printf("    xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");
737     outs.printf("    xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
738     outs.printf("    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
739     outs.printf("    xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
740     outs.printf("    xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
741     outs.printf("    office:version=\"1.0\">\n");
742     outs.printf("\n");
743     outs.printf("\n");
744     outs.printf("<office:scripts/>\n");
745     outs.printf("\n");
746     outs.printf("\n");
747     //AffineTransform trans = new AffineTransform();
748     //trans.scale(12.0, 12.0);
749     outs.printf("<!-- ######### CONVERSION FROM SVG STARTS ######## -->\n");
750     outs.printf("<!--\n");
751     outs.printf("*************************************************************************\n");
752     outs.printf("  S T Y L E S\n");
753     outs.printf("  Style entries have been pulled from the svg style and\n");
754     outs.printf("  representation attributes in the SVG tree.  The tree elements\n");
755     outs.printf("  then refer to them by name, in the ODF manner\n");
756     outs.printf("*************************************************************************\n");
757     outs.printf("-->\n");
758     outs.printf("\n");
759     outs.printf("\n");
761     if (!writeStyle(outs))
762         {
763         g_warning("Failed to write styles");
764         return false;
765         }
767     outs.printf("\n");
768     outs.printf("\n");
769     outs.printf("\n");
770     outs.printf("\n");
771     outs.printf("<!--\n");
772     outs.printf("*************************************************************************\n");
773     outs.printf("  D R A W I N G\n");
774     outs.printf("  This section is the heart of SVG-ODF conversion.  We are\n");
775     outs.printf("  starting with simple conversions, and will slowly evolve\n");
776     outs.printf("  into a 'smarter' translation as time progresses.  Any help\n");
777     outs.printf("  in improving .odg export is welcome.\n");
778     outs.printf("*************************************************************************\n");
779     outs.printf("-->\n");
780     outs.printf("\n");
781     outs.printf("\n");
782     outs.printf("<office:body>\n");
783     outs.printf("<office:drawing>\n");
784     outs.printf("<draw:page draw:name=\"page1\" draw:style-name=\"dp1\"\n");
785     outs.printf("        draw:master-page-name=\"Default\">\n");
786     outs.printf("\n");
787     outs.printf("<draw:g draw:transform=\"scale(1,-1)\">\n");
788     outs.printf("\n");
790     if (!writeTree(outs, node))
791         {
792         g_warning("Failed to convert SVG tree");
793         return false;
794         }
796     outs.printf("\n");
797     outs.printf("</draw:g>\n");
798     outs.printf("\n");
800     outs.printf("</draw:page>\n");
801     outs.printf("</office:drawing>\n");
803     outs.printf("\n");
804     outs.printf("\n");
805     outs.printf("<!-- ######### CONVERSION FROM SVG ENDS ######## -->\n");
806     outs.printf("\n");
807     outs.printf("\n");
809     outs.printf("</office:body>\n");
810     outs.printf("</office:document-content>\n");
811     outs.printf("\n");
812     outs.printf("\n");
813     outs.printf("\n");
814     outs.printf("<!--\n");
815     outs.printf("*************************************************************************\n");
816     outs.printf("  E N D    O F    F I L E\n");
817     outs.printf("  Have a nice day  - ishmal\n");
818     outs.printf("*************************************************************************\n");
819     outs.printf("-->\n");
820     outs.printf("\n");
821     outs.printf("\n");
825     //Make our entry
826     ZipEntry *ze = zf.newEntry("content.xml", "ODF master content file");
827     ze->setUncompressedData(bouts.getBuffer());
828     ze->finish();
830     return true;
836 /**
837  * Descends into the SVG tree, mapping things to ODF when appropriate
838  */
839 void
840 OdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *uri)
842     ZipFile zf;
843     styleTable.clear();
844     styleLookupTable.clear();
845     imageTable.clear();
846     preprocess(zf, doc->rroot);
848     if (!writeManifest(zf))
849         {
850         g_warning("Failed to write manifest");
851         return;
852         }
854     if (!writeMeta(zf))
855         {
856         g_warning("Failed to write metafile");
857         return;
858         }
860     if (!writeContent(zf, doc->rroot))
861         {
862         g_warning("Failed to write content");
863         return;
864         }
866     if (!zf.writeFile(uri))
867         {
868         return;
869         }
873 /**
874  * This is the definition of PovRay output.  This function just
875  * calls the extension system with the memory allocated XML that
876  * describes the data.
877 */
878 void
879 OdfOutput::init()
881     Inkscape::Extension::build_from_mem(
882         "<inkscape-extension>\n"
883             "<name>" N_("OpenDocument Drawing Output") "</name>\n"
884             "<id>org.inkscape.output.odf</id>\n"
885             "<output>\n"
886                 "<extension>.odg</extension>\n"
887                 "<mimetype>text/x-povray-script</mimetype>\n"
888                 "<filetypename>" N_("OpenDocument drawing (*.odg)") "</filetypename>\n"
889                 "<filetypetooltip>" N_("OpenDocument drawing file") "</filetypetooltip>\n"
890             "</output>\n"
891         "</inkscape-extension>",
892         new OdfOutput());
895 /**
896  * Make sure that we are in the database
897  */
898 bool
899 OdfOutput::check (Inkscape::Extension::Extension *module)
901     /* We don't need a Key
902     if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_POV))
903         return FALSE;
904     */
906     return TRUE;
911 //########################################################################
912 //# I N P U T
913 //########################################################################
917 //#######################
918 //# L A T E R  !!!  :-)
919 //#######################
933 }  //namespace Internal
934 }  //namespace Extension
935 }  //namespace Inkscape
938 //########################################################################
939 //# E N D    O F    F I L E
940 //########################################################################
942 /*
943   Local Variables:
944   mode:c++
945   c-file-style:"stroustrup"
946   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
947   indent-tabs-mode:nil
948   fill-column:99
949   End:
950 */
951 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :