Code

svd hacks
[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"
75 namespace Inkscape
76 {
77 namespace Extension
78 {
79 namespace Internal
80 {
82 //# Shorthand notation
83 typedef org::w3c::dom::DOMString DOMString;
84 typedef org::w3c::dom::io::OutputStreamWriter OutputStreamWriter;
85 typedef org::w3c::dom::io::BufferOutputStream BufferOutputStream;
88 //########################################################################
89 //# C L A S S    SingularValueDecomposition
90 //########################################################################
91 #include <math.h>
93 /**
94  *
95  * ====================================================
96  *
97  * NOTE:
98  * This class is ported almost verbatim from the public domain
99  * JAMA Matrix package.  It is modified to handle only 3x3 matrices
100  * and our NR::Matrix affine transform class.  We give full
101  * attribution to them, along with many thanks.  JAMA can be found at:
102  *     http://math.nist.gov/javanumerics/jama
103  *
104  * ====================================================
105  *
106  * Singular Value Decomposition.
107  * <P>
108  * For an m-by-n matrix A with m >= n, the singular value decomposition is
109  * an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
110  * an n-by-n orthogonal matrix V so that A = U*S*V'.
111  * <P>
112  * The singular values, sigma[k] = S[k][k], are ordered so that
113  * sigma[0] >= sigma[1] >= ... >= sigma[n-1].
114  * <P>
115  * The singular value decompostion always exists, so the constructor will
116  * never fail.  The matrix condition number and the effective numerical
117  * rank can be computed from this decomposition.
118  */
119 class SingularValueDecomposition
121 public:
123    /** Construct the singular value decomposition
124    @param A    Rectangular matrix
125    @return     Structure to access U, S and V.
126    */
128     SingularValueDecomposition (const NR::Matrix &matrixArg)
129         {
130         matrix = matrixArg;
131         calculate();
132         }
134     virtual ~SingularValueDecomposition()
135         {}
137     /**
138      * Return the left singular vectors
139      * @return     U
140      */
141     NR::Matrix getU();
143     /**
144      * Return the right singular vectors
145      * @return     V
146      */
147     NR::Matrix getV();
149     /**
150      * Return the right singular vectors
151      * @return  U x Vtransposed
152      */
153     NR::Matrix getUVt();
155     /**
156      *  Return the s[0] value
157      */
158     double getS0();
160     /**
161      *  Return the s[1] value
162      */
163     double getS1();
165     /**
166      *  Return the s[2] value
167      */
168     double getS2();
170     /**
171      * Two norm
172      * @return max(S)
173      */
174     double norm2();
176     /**
177      * Two norm condition number
178      *  @return max(S)/min(S)
179      */
180     double cond();
182     /**
183      *  Effective numerical matrix rank
184      *  @return     Number of nonnegligible singular values.
185      */
186     int rank();
188 private:
190       void calculate();
192       NR::Matrix matrix;
193       double A[3][3];
194       double U[3][3];
195       double s[3];
196       double V[3][3];
198 };
201 static double svd_hypot(double a, double b)
203     double r;
205     if (fabs(a) > fabs(b))
206         {
207         r = b/a;
208         r = fabs(a) * sqrt(1+r*r);
209         }
210     else if (b != 0)
211         {
212         r = a/b;
213         r = fabs(b) * sqrt(1+r*r);
214         }
215     else
216         {
217         r = 0.0;
218         }
219     return r;
224 void SingularValueDecomposition::calculate()
226       // Initialize.
227       A[0][0] = matrix[0];
228       A[0][1] = matrix[2];
229       A[0][2] = matrix[4];
230       A[1][0] = matrix[1];
231       A[1][1] = matrix[3];
232       A[1][2] = matrix[5];
233       A[2][0] = 0.0;
234       A[2][1] = 0.0;
235       A[2][2] = 1.0;
237       double e[3];
238       double work[3];
239       bool wantu = true;
240       bool wantv = true;
241       int m  = 3;
242       int n  = 3;
243       int nu = 3;
245       // Reduce A to bidiagonal form, storing the diagonal elements
246       // in s and the super-diagonal elements in e.
248       int nct = 2;
249       int nrt = 1;
250       for (int k = 0; k < 2; k++) {
251          if (k < nct) {
253             // Compute the transformation for the k-th column and
254             // place the k-th diagonal in s[k].
255             // Compute 2-norm of k-th column without under/overflow.
256             s[k] = 0;
257             for (int i = k; i < m; i++) {
258                s[k] = svd_hypot(s[k],A[i][k]);
259             }
260             if (s[k] != 0.0) {
261                if (A[k][k] < 0.0) {
262                   s[k] = -s[k];
263                }
264                for (int i = k; i < m; i++) {
265                   A[i][k] /= s[k];
266                }
267                A[k][k] += 1.0;
268             }
269             s[k] = -s[k];
270          }
271          for (int j = k+1; j < n; j++) {
272             if ((k < nct) & (s[k] != 0.0))  {
274             // Apply the transformation.
276                double t = 0;
277                for (int i = k; i < m; i++) {
278                   t += A[i][k]*A[i][j];
279                }
280                t = -t/A[k][k];
281                for (int i = k; i < m; i++) {
282                   A[i][j] += t*A[i][k];
283                }
284             }
286             // Place the k-th row of A into e for the
287             // subsequent calculation of the row transformation.
289             e[j] = A[k][j];
290          }
291          if (wantu & (k < nct)) {
293             // Place the transformation in U for subsequent back
294             // multiplication.
296             for (int i = k; i < m; i++) {
297                U[i][k] = A[i][k];
298             }
299          }
300          if (k < nrt) {
302             // Compute the k-th row transformation and place the
303             // k-th super-diagonal in e[k].
304             // Compute 2-norm without under/overflow.
305             e[k] = 0;
306             for (int i = k+1; i < n; i++) {
307                e[k] = svd_hypot(e[k],e[i]);
308             }
309             if (e[k] != 0.0) {
310                if (e[k+1] < 0.0) {
311                   e[k] = -e[k];
312                }
313                for (int i = k+1; i < n; i++) {
314                   e[i] /= e[k];
315                }
316                e[k+1] += 1.0;
317             }
318             e[k] = -e[k];
319             if ((k+1 < m) & (e[k] != 0.0)) {
321             // Apply the transformation.
323                for (int i = k+1; i < m; i++) {
324                   work[i] = 0.0;
325                }
326                for (int j = k+1; j < n; j++) {
327                   for (int i = k+1; i < m; i++) {
328                      work[i] += e[j]*A[i][j];
329                   }
330                }
331                for (int j = k+1; j < n; j++) {
332                   double t = -e[j]/e[k+1];
333                   for (int i = k+1; i < m; i++) {
334                      A[i][j] += t*work[i];
335                   }
336                }
337             }
338             if (wantv) {
340             // Place the transformation in V for subsequent
341             // back multiplication.
343                for (int i = k+1; i < n; i++) {
344                   V[i][k] = e[i];
345                }
346             }
347          }
348       }
350       // Set up the final bidiagonal matrix or order p.
352       int p = 3;
353       if (nct < n) {
354          s[nct] = A[nct][nct];
355       }
356       if (m < p) {
357          s[p-1] = 0.0;
358       }
359       if (nrt+1 < p) {
360          e[nrt] = A[nrt][p-1];
361       }
362       e[p-1] = 0.0;
364       // If required, generate U.
366       if (wantu) {
367          for (int j = nct; j < nu; j++) {
368             for (int i = 0; i < m; i++) {
369                U[i][j] = 0.0;
370             }
371             U[j][j] = 1.0;
372          }
373          for (int k = nct-1; k >= 0; k--) {
374             if (s[k] != 0.0) {
375                for (int j = k+1; j < nu; j++) {
376                   double t = 0;
377                   for (int i = k; i < m; i++) {
378                      t += U[i][k]*U[i][j];
379                   }
380                   t = -t/U[k][k];
381                   for (int i = k; i < m; i++) {
382                      U[i][j] += t*U[i][k];
383                   }
384                }
385                for (int i = k; i < m; i++ ) {
386                   U[i][k] = -U[i][k];
387                }
388                U[k][k] = 1.0 + U[k][k];
389                for (int i = 0; i < k-1; i++) {
390                   U[i][k] = 0.0;
391                }
392             } else {
393                for (int i = 0; i < m; i++) {
394                   U[i][k] = 0.0;
395                }
396                U[k][k] = 1.0;
397             }
398          }
399       }
401       // If required, generate V.
403       if (wantv) {
404          for (int k = n-1; k >= 0; k--) {
405             if ((k < nrt) & (e[k] != 0.0)) {
406                for (int j = k+1; j < nu; j++) {
407                   double t = 0;
408                   for (int i = k+1; i < n; i++) {
409                      t += V[i][k]*V[i][j];
410                   }
411                   t = -t/V[k+1][k];
412                   for (int i = k+1; i < n; i++) {
413                      V[i][j] += t*V[i][k];
414                   }
415                }
416             }
417             for (int i = 0; i < n; i++) {
418                V[i][k] = 0.0;
419             }
420             V[k][k] = 1.0;
421          }
422       }
424       // Main iteration loop for the singular values.
426       int pp = p-1;
427       int iter = 0;
428       //double eps = pow(2.0,-52.0);
429       //double tiny = pow(2.0,-966.0);
430       //let's just calculate these now
431       //a double can be e Â± 308.25, so this is safe
432       double eps = 2.22e-16;
433       double tiny = 1.6e-291;
434       while (p > 0) {
435          int k,kase;
437          // Here is where a test for too many iterations would go.
439          // This section of the program inspects for
440          // negligible elements in the s and e arrays.  On
441          // completion the variables kase and k are set as follows.
443          // kase = 1     if s(p) and e[k-1] are negligible and k<p
444          // kase = 2     if s(k) is negligible and k<p
445          // kase = 3     if e[k-1] is negligible, k<p, and
446          //              s(k), ..., s(p) are not negligible (qr step).
447          // kase = 4     if e(p-1) is negligible (convergence).
449          for (k = p-2; k >= -1; k--) {
450             if (k == -1) {
451                break;
452             }
453             if (fabs(e[k]) <=
454                   tiny + eps*(fabs(s[k]) + fabs(s[k+1]))) {
455                e[k] = 0.0;
456                break;
457             }
458          }
459          if (k == p-2) {
460             kase = 4;
461          } else {
462             int ks;
463             for (ks = p-1; ks >= k; ks--) {
464                if (ks == k) {
465                   break;
466                }
467                double t = (ks != p ? fabs(e[ks]) : 0.) +
468                           (ks != k+1 ? fabs(e[ks-1]) : 0.);
469                if (fabs(s[ks]) <= tiny + eps*t)  {
470                   s[ks] = 0.0;
471                   break;
472                }
473             }
474             if (ks == k) {
475                kase = 3;
476             } else if (ks == p-1) {
477                kase = 1;
478             } else {
479                kase = 2;
480                k = ks;
481             }
482          }
483          k++;
485          // Perform the task indicated by kase.
487          switch (kase) {
489             // Deflate negligible s(p).
491             case 1: {
492                double f = e[p-2];
493                e[p-2] = 0.0;
494                for (int j = p-2; j >= k; j--) {
495                   double t = svd_hypot(s[j],f);
496                   double cs = s[j]/t;
497                   double sn = f/t;
498                   s[j] = t;
499                   if (j != k) {
500                      f = -sn*e[j-1];
501                      e[j-1] = cs*e[j-1];
502                   }
503                   if (wantv) {
504                      for (int i = 0; i < n; i++) {
505                         t = cs*V[i][j] + sn*V[i][p-1];
506                         V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1];
507                         V[i][j] = t;
508                      }
509                   }
510                }
511             }
512             break;
514             // Split at negligible s(k).
516             case 2: {
517                double f = e[k-1];
518                e[k-1] = 0.0;
519                for (int j = k; j < p; j++) {
520                   double t = svd_hypot(s[j],f);
521                   double cs = s[j]/t;
522                   double sn = f/t;
523                   s[j] = t;
524                   f = -sn*e[j];
525                   e[j] = cs*e[j];
526                   if (wantu) {
527                      for (int i = 0; i < m; i++) {
528                         t = cs*U[i][j] + sn*U[i][k-1];
529                         U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1];
530                         U[i][j] = t;
531                      }
532                   }
533                }
534             }
535             break;
537             // Perform one qr step.
539             case 3: {
541                // Calculate the shift.
543                double scale = fabs(s[p-1]);
544                double d = fabs(s[p-2]);
545                if (d>scale) scale=d;
546                d = fabs(e[p-2]);
547                if (d>scale) scale=d;
548                d = fabs(s[k]);
549                if (d>scale) scale=d;
550                d = fabs(e[k]);
551                if (d>scale) scale=d;
552                double sp = s[p-1]/scale;
553                double spm1 = s[p-2]/scale;
554                double epm1 = e[p-2]/scale;
555                double sk = s[k]/scale;
556                double ek = e[k]/scale;
557                double b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
558                double c = (sp*epm1)*(sp*epm1);
559                double shift = 0.0;
560                if ((b != 0.0) | (c != 0.0)) {
561                   shift = sqrt(b*b + c);
562                   if (b < 0.0) {
563                      shift = -shift;
564                   }
565                   shift = c/(b + shift);
566                }
567                double f = (sk + sp)*(sk - sp) + shift;
568                double g = sk*ek;
570                // Chase zeros.
572                for (int j = k; j < p-1; j++) {
573                   double t = svd_hypot(f,g);
574                   double cs = f/t;
575                   double sn = g/t;
576                   if (j != k) {
577                      e[j-1] = t;
578                   }
579                   f = cs*s[j] + sn*e[j];
580                   e[j] = cs*e[j] - sn*s[j];
581                   g = sn*s[j+1];
582                   s[j+1] = cs*s[j+1];
583                   if (wantv) {
584                      for (int i = 0; i < n; i++) {
585                         t = cs*V[i][j] + sn*V[i][j+1];
586                         V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1];
587                         V[i][j] = t;
588                      }
589                   }
590                   t = svd_hypot(f,g);
591                   cs = f/t;
592                   sn = g/t;
593                   s[j] = t;
594                   f = cs*e[j] + sn*s[j+1];
595                   s[j+1] = -sn*e[j] + cs*s[j+1];
596                   g = sn*e[j+1];
597                   e[j+1] = cs*e[j+1];
598                   if (wantu && (j < m-1)) {
599                      for (int i = 0; i < m; i++) {
600                         t = cs*U[i][j] + sn*U[i][j+1];
601                         U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1];
602                         U[i][j] = t;
603                      }
604                   }
605                }
606                e[p-2] = f;
607                iter = iter + 1;
608             }
609             break;
611             // Convergence.
613             case 4: {
615                // Make the singular values positive.
617                if (s[k] <= 0.0) {
618                   s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
619                   if (wantv) {
620                      for (int i = 0; i <= pp; i++) {
621                         V[i][k] = -V[i][k];
622                      }
623                   }
624                }
626                // Order the singular values.
628                while (k < pp) {
629                   if (s[k] >= s[k+1]) {
630                      break;
631                   }
632                   double t = s[k];
633                   s[k] = s[k+1];
634                   s[k+1] = t;
635                   if (wantv && (k < n-1)) {
636                      for (int i = 0; i < n; i++) {
637                         t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t;
638                      }
639                   }
640                   if (wantu && (k < m-1)) {
641                      for (int i = 0; i < m; i++) {
642                         t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t;
643                      }
644                   }
645                   k++;
646                }
647                iter = 0;
648                p--;
649             }
650             break;
651          }
652       }
659 /**
660  * Return the left singular vectors
661  * @return     U
662  */
663 NR::Matrix SingularValueDecomposition::getU()
665     NR::Matrix mat(U[0][0], U[1][0], U[0][1],
666                    U[1][1], U[0][2], U[1][2]);
667     return mat;
670 /**
671  * Return the right singular vectors
672  * @return     V
673  */
675 NR::Matrix SingularValueDecomposition::getV()
677     NR::Matrix mat(V[0][0], V[1][0], V[0][1],
678                    V[1][1], V[0][2], V[1][2]);
679     return mat;
682 /**
683  * Return the right singular vectors
684  * @return  U x Vtransposed
685  */
687 NR::Matrix SingularValueDecomposition::getUVt()
689     //instead of sum(row*column),  sum(column, column)
690     double a = U[0][0] * V[0][0] + U[1][0] * V[1][0];
691     double b = U[0][0] * V[0][1] + U[1][0] * V[1][1];
692     double c = U[0][1] * V[0][0] + U[1][1] * V[1][0];
693     double d = U[0][1] * V[0][1] + U[1][1] * V[1][1];
694     double e = U[0][2] * V[0][0] + U[1][2] * V[1][0];
695     double f = U[0][2] * V[0][1] + U[1][2] * V[1][1];
697     NR::Matrix mat(a, b, c, d, e, f);
698     return mat;
701 /**
702  *  Return the s[0] value
703  */
704 double SingularValueDecomposition::getS0()
706     return s[0];
709 /**
710  *  Return the s[1] value
711  */
712 double SingularValueDecomposition::getS1()
714     return s[1];
717 /**
718  *  Return the s[2] value
719  */
720 double SingularValueDecomposition::getS2()
722     return s[2];
725 /**
726  * Two norm
727  * @return     max(S)
728  */
729 double SingularValueDecomposition::norm2()
731     return s[0];
734 /**
735  * Two norm condition number
736  *  @return     max(S)/min(S)
737  */
739 double SingularValueDecomposition::cond()
741     return s[0]/s[2];
744 /**
745  *  Effective numerical matrix rank
746  *  @return     Number of nonnegligible singular values.
747  */
748 int SingularValueDecomposition::rank()
750     double eps = pow(2.0,-52.0);
751     double tol = 3.0*s[0]*eps;
752     int r = 0;
753     for (int i = 0; i < 3; i++)
754         {
755         if (s[i] > tol)
756             r++;
757         }
758     return r;
761 //########################################################################
762 //# E N D    C L A S S    SingularValueDecomposition
763 //########################################################################
768 //#define pxToCm  0.0275
769 #define pxToCm  0.04
770 #define piToRad 0.0174532925
771 #define docHeightCm 22.86
774 //########################################################################
775 //# O U T P U T
776 //########################################################################
778 static std::string getAttribute( Inkscape::XML::Node *node, char *attrName)
780     std::string val;
781     char *valstr = (char *)node->attribute(attrName);
782     if (valstr)
783         val = (const char *)valstr;
784     return val;
788 static std::string getExtension(const std::string &fname)
790     std::string ext;
792     unsigned int pos = fname.rfind('.');
793     if (pos == fname.npos)
794         {
795         ext = "";
796         }
797     else
798         {
799         ext = fname.substr(pos);
800         }
801     return ext;
805 static std::string formatTransform(NR::Matrix &tf)
807     std::string str;
808     if (!tf.test_identity())
809         {
810         char buf[128];
811         snprintf(buf, 127, "matrix(%.3f %.3f %.3f %.3f %.3f %.3f)",
812                 tf[0], tf[1], tf[2], tf[3], tf[4], tf[5]);
813         str = buf;
814         }
815     return str;
819 /**
820  * An affine transformation Q may be decomposed via
821  * singular value decomposition into
822  *
823  * T = UDVt
824  *   = (UDUt)UVt
825  * ('t' means transposed)
826  * where U and V are orthonormal matrices and D is a diagonal
827  * matrix. The decomposition may be interpreted as such:
828  * the image is firstly rotated by UVt. The image is then
829  * rotated by Ut, stretched in the coordinate directions
830  * by D then rotated back by U. The net effect is a slant operation in
831  * some tilt direction followed by an isotropic scale. If rot(x)
832  * is a matrix that rotates by x we can rewrite this as
833  * T = rot(-tau)( k 0, 0 1) rot(tau) rot(theta) S
834  * where S is a scaling matrix, k is a multiplying (contraction)
835  * factor related to slant, tau is the tilt direction and theta
836  * is the initial rotation angle.
837  */
838 static void analyzeTransform(NR::Matrix &tf)
840     SingularValueDecomposition svd(tf);
841     double scale1 = svd.getS0();
842     double rotate = svd.getS1();
843     double scale2 = svd.getS2();
844     NR::Matrix u   = svd.getU();
845     NR::Matrix v   = svd.getV();
846     NR::Matrix uvt = svd.getUVt();
847     g_message("s1:%f  rot:%f  s2:%f", scale1, rotate, scale2);
848     std::string us = formatTransform(u);
849     g_message("u:%s", us.c_str());
850     std::string vs = formatTransform(v);
851     g_message("v:%s", vs.c_str());
852     std::string uvts = formatTransform(uvt);
853     g_message("uvt:%s", uvts.c_str());
859 /**
860  * Method descends into the repr tree, converting image and style info
861  * into forms compatible in ODF.
862  */
863 void
864 OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node)
867     std::string nodeName = node->name();
868     std::string id       = getAttribute(node, "id");
870     if (nodeName == "image" || nodeName == "svg:image")
871         {
872         //g_message("image");
873         std::string href = getAttribute(node, "xlink:href");
874         if (href.size() > 0)
875             {
876             std::string oldName = href;
877             std::string ext = getExtension(oldName);
878             if (ext == ".jpeg")
879                 ext = ".jpg";
880             if (imageTable.find(oldName) == imageTable.end())
881                 {
882                 char buf[64];
883                 snprintf(buf, 63, "Pictures/image%d%s",
884                     imageTable.size(), ext.c_str());
885                 std::string newName = buf;
886                 imageTable[oldName] = newName;
887                 std::string comment = "old name was: ";
888                 comment.append(oldName);
889                 URI oldUri(oldName);
890                 //g_message("oldpath:%s", oldUri.getNativePath().c_str());
891                 //# if relative to the documentURI, get proper path
892                 URI resUri = documentUri.resolve(oldUri);
893                 DOMString pathName = resUri.getNativePath();
894                 //g_message("native path:%s", pathName.c_str());
895                 ZipEntry *ze = zf.addFile(pathName, comment);
896                 if (ze)
897                     {
898                     ze->setFileName(newName);
899                     }
900                 else
901                     {
902                     g_warning("Could not load image file '%s'", pathName.c_str());
903                     }
904                 }
905             }
906         }
910     SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node);
911     if (!reprobj)
912         return;
913     if (!SP_IS_ITEM(reprobj))
914         {
915         return;
916         }
917     SPItem *item = SP_ITEM(reprobj);
918     SPStyle *style = SP_OBJECT_STYLE(item);
919     if (style && id.size()>0)
920         {
921         StyleInfo si;
922         if (style->fill.type == SP_PAINT_TYPE_COLOR)
923             {
924             guint32 fillCol =
925                 sp_color_get_rgba32_ualpha(&style->fill.value.color, 0);
926             char buf[16];
927             int r = (fillCol >> 24) & 0xff;
928             int g = (fillCol >> 16) & 0xff;
929             int b = (fillCol >>  8) & 0xff;
930             //g_message("## %s %lx", id.c_str(), (unsigned int)fillCol);
931             snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
932             si.fillColor = buf;
933             si.fill      = "solid";
934             double opacityPercent = 100.0 *
935                  (SP_SCALE24_TO_FLOAT(style->fill_opacity.value));
936             snprintf(buf, 15, "%.2f%%", opacityPercent);
937             si.fillOpacity = buf;
938             }
939         if (style->stroke.type == SP_PAINT_TYPE_COLOR)
940             {
941             guint32 strokeCol =
942                 sp_color_get_rgba32_ualpha(&style->stroke.value.color, 0);
943             char buf[16];
944             int r = (strokeCol >> 24) & 0xff;
945             int g = (strokeCol >> 16) & 0xff;
946             int b = (strokeCol >>  8) & 0xff;
947             snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
948             si.strokeColor = buf;
949             snprintf(buf, 15, "%.2fpt", style->stroke_width.value);
950             si.strokeWidth = buf;
951             si.stroke      = "solid";
952             double opacityPercent = 100.0 *
953                  (SP_SCALE24_TO_FLOAT(style->stroke_opacity.value));
954             snprintf(buf, 15, "%.2f%%", opacityPercent);
955             si.strokeOpacity = buf;
956             }
958         //Look for existing identical style;
959         bool styleMatch = false;
960         std::vector<StyleInfo>::iterator iter;
961         for (iter=styleTable.begin() ; iter!=styleTable.end() ; iter++)
962             {
963             if (si.equals(*iter))
964                 {
965                 //map to existing styleTable entry
966                 std::string styleName = iter->name;
967                 //g_message("found duplicate style:%s", styleName.c_str());
968                 styleLookupTable[id] = styleName;
969                 styleMatch = true;
970                 break;
971                 }
972             }
973         //None found, make a new pair or entries
974         if (!styleMatch)
975             {
976             char buf[16];
977             snprintf(buf, 15, "style%d", styleTable.size());
978             std::string styleName = buf;
979             si.name = styleName;
980             styleTable.push_back(si);
981             styleLookupTable[id] = styleName;
982             }
983         }
986     for (Inkscape::XML::Node *child = node->firstChild() ;
987             child ; child = child->next())
988         preprocess(zf, child);
993 bool OdfOutput::writeManifest(ZipFile &zf)
995     BufferOutputStream bouts;
996     OutputStreamWriter outs(bouts);
998     time_t tim;
999     time(&tim);
1001     outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1002     outs.printf("<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">\n");
1003     outs.printf("\n");
1004     outs.printf("\n");
1005     outs.printf("<!--\n");
1006     outs.printf("*************************************************************************\n");
1007     outs.printf("  file:  manifest.xml\n");
1008     outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
1009     outs.printf("  http://www.inkscape.org\n");
1010     outs.printf("*************************************************************************\n");
1011     outs.printf("-->\n");
1012     outs.printf("\n");
1013     outs.printf("\n");
1014     outs.printf("<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n");
1015     outs.printf("    <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.graphics\" manifest:full-path=\"/\"/>\n");
1016     outs.printf("    <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>\n");
1017     outs.printf("    <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>\n");
1018     outs.printf("    <!--List our images here-->\n");
1019     std::map<std::string, std::string>::iterator iter;
1020     for (iter = imageTable.begin() ; iter!=imageTable.end() ; iter++)
1021         {
1022         std::string oldName = iter->first;
1023         std::string newName = iter->second;
1025         std::string ext = getExtension(oldName);
1026         if (ext == ".jpeg")
1027             ext = ".jpg";
1028         outs.printf("    <manifest:file-entry manifest:media-type=\"");
1029         if (ext == ".gif")
1030             outs.printf("image/gif");
1031         else if (ext == ".png")
1032             outs.printf("image/png");
1033         else if (ext == ".jpg")
1034             outs.printf("image/jpeg");
1035         outs.printf("\" manifest:full-path=\"");
1036         outs.printf((char *)newName.c_str());
1037         outs.printf("\"/>\n");
1038         }
1039     outs.printf("</manifest:manifest>\n");
1041     outs.close();
1043     //Make our entry
1044     ZipEntry *ze = zf.newEntry("META-INF/manifest.xml", "ODF file manifest");
1045     ze->setUncompressedData(bouts.getBuffer());
1046     ze->finish();
1048     return true;
1052 bool OdfOutput::writeMeta(ZipFile &zf)
1054     BufferOutputStream bouts;
1055     OutputStreamWriter outs(bouts);
1057     time_t tim;
1058     time(&tim);
1060     outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1061     outs.printf("\n");
1062     outs.printf("\n");
1063     outs.printf("<!--\n");
1064     outs.printf("*************************************************************************\n");
1065     outs.printf("  file:  meta.xml\n");
1066     outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
1067     outs.printf("  http://www.inkscape.org\n");
1068     outs.printf("*************************************************************************\n");
1069     outs.printf("-->\n");
1070     outs.printf("\n");
1071     outs.printf("\n");
1072     outs.printf("<office:document-meta\n");
1073     outs.printf("xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
1074     outs.printf("xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
1075     outs.printf("xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
1076     outs.printf("xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
1077     outs.printf("xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
1078     outs.printf("xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
1079     outs.printf("xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
1080     outs.printf("xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
1081     outs.printf("office:version=\"1.0\">\n");
1082     outs.printf("<office:meta>\n");
1083     outs.printf("    <meta:generator>Inkscape.org - 0.44</meta:generator>\n");
1084     outs.printf("    <meta:initial-creator>clark kent</meta:initial-creator>\n");
1085     outs.printf("    <meta:creation-date>2006-04-13T17:12:29</meta:creation-date>\n");
1086     outs.printf("    <dc:creator>clark kent</dc:creator>\n");
1087     outs.printf("    <dc:date>2006-04-13T17:13:20</dc:date>\n");
1088     outs.printf("    <dc:language>en-US</dc:language>\n");
1089     outs.printf("    <meta:editing-cycles>2</meta:editing-cycles>\n");
1090     outs.printf("    <meta:editing-duration>PT56S</meta:editing-duration>\n");
1091     outs.printf("    <meta:user-defined meta:name=\"Info 1\"/>\n");
1092     outs.printf("    <meta:user-defined meta:name=\"Info 2\"/>\n");
1093     outs.printf("    <meta:user-defined meta:name=\"Info 3\"/>\n");
1094     outs.printf("    <meta:user-defined meta:name=\"Info 4\"/>\n");
1095     outs.printf("    <meta:document-statistic meta:object-count=\"2\"/>\n");
1096     outs.printf("</office:meta>\n");
1097     outs.printf("</office:document-meta>\n");
1098     outs.printf("\n");
1099     outs.printf("\n");
1102     outs.close();
1104     //Make our entry
1105     ZipEntry *ze = zf.newEntry("meta.xml", "ODF info file");
1106     ze->setUncompressedData(bouts.getBuffer());
1107     ze->finish();
1109     return true;
1113 bool OdfOutput::writeStyle(Writer &outs)
1115     outs.printf("<office:automatic-styles>\n");
1116     outs.printf("<!-- ####### 'Standard' styles ####### -->\n");
1117     outs.printf("<style:style style:name=\"dp1\" style:family=\"drawing-page\"/>\n");
1118     outs.printf("<style:style style:name=\"gr1\" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
1119     outs.printf("  <style:graphic-properties draw:stroke=\"none\" draw:fill=\"none\"\n");
1120     outs.printf("       draw:textarea-horizontal-align=\"center\"\n");
1121     outs.printf("       draw:textarea-vertical-align=\"middle\" draw:color-mode=\"standard\"\n");
1122     outs.printf("       draw:luminance=\"0%\" draw:contrast=\"0%\" draw:gamma=\"100%\" draw:red=\"0%\"\n");
1123     outs.printf("       draw:green=\"0%\" draw:blue=\"0%\" fo:clip=\"rect(0cm 0cm 0cm 0cm)\"\n");
1124     outs.printf("       draw:image-opacity=\"100%\" style:mirror=\"none\"/>\n");
1125     outs.printf("</style:style>\n");
1126     outs.printf("<style:style style:name=\"P1\" style:family=\"paragraph\">\n");
1127     outs.printf("  <style:paragraph-properties fo:text-align=\"center\"/>\n");
1128     outs.printf("</style:style>\n");
1130     //##  Dump our style table
1131     outs.printf("<!-- ####### Styles from Inkscape document ####### -->\n");
1132     std::vector<StyleInfo>::iterator iter;
1133     for (iter = styleTable.begin() ; iter != styleTable.end() ; iter++)
1134         {
1135         outs.printf("<style:style style:name=\"%s\"", iter->name.c_str());
1136         StyleInfo s(*iter);
1137         outs.printf(" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
1138         outs.printf("  <style:graphic-properties");
1139         outs.printf(" draw:fill=\"%s\" ", s.fill.c_str());
1140         if (s.fill != "none")
1141             {
1142             outs.printf(" draw:fill-color=\"%s\" ", s.fillColor.c_str());
1143             outs.printf(" draw:fill-opacity=\"%s\" ", s.fillOpacity.c_str());
1144             }
1145         outs.printf(" draw:stroke=\"%s\" ", s.stroke.c_str());
1146         if (s.stroke != "none")
1147             {
1148             outs.printf(" svg:stroke-width=\"%s\" ", s.strokeWidth.c_str());
1149             outs.printf(" svg:stroke-color=\"%s\" ", s.strokeColor.c_str());
1150             outs.printf(" svg:stroke-opacity=\"%s\" ", s.strokeOpacity.c_str());
1151             }
1152         outs.printf("/>\n");
1153         outs.printf("</style:style>\n");
1154         }
1156     outs.printf("</office:automatic-styles>\n");
1157     outs.printf("\n");
1159     return true;
1163 static void
1164 writePath(Writer &outs, NArtBpath const *bpath,
1165           NR::Matrix &tf, double xoff, double yoff)
1167     bool closed = false;
1168     NArtBpath *bp = (NArtBpath *)bpath;
1169     for (  ; bp->code != NR_END; bp++)
1170         {
1171         NR::Point const p1(bp->c(1) * tf);
1172         NR::Point const p2(bp->c(2) * tf);
1173         NR::Point const p3(bp->c(3) * tf);
1174         double x1 = (p1[NR::X] * pxToCm - xoff) * 1000.0;
1175         double y1 = (p1[NR::Y] * pxToCm - yoff) * 1000.0;
1176         double x2 = (p2[NR::X] * pxToCm - xoff) * 1000.0;
1177         double y2 = (p2[NR::Y] * pxToCm - yoff) * 1000.0;
1178         double x3 = (p3[NR::X] * pxToCm - xoff) * 1000.0;
1179         double y3 = (p3[NR::Y] * pxToCm - yoff) * 1000.0;
1181         switch (bp->code)
1182             {
1183             case NR_LINETO:
1184                 outs.printf("L %.3f,%.3f ",  x3 , y3);
1185                 break;
1187             case NR_CURVETO:
1188                 outs.printf("C %.3f,%.3f %.3f,%.3f %.3f,%.3f ",
1189                               x1, y1, x2, y2, x3, y3);
1190                 break;
1192             case NR_MOVETO_OPEN:
1193             case NR_MOVETO:
1194                 if (closed)
1195                     outs.printf("z ");
1196                 closed = ( bp->code == NR_MOVETO );
1197                 outs.printf("M %.3f,%.3f ",  x3 , y3);
1198                 break;
1200             default:
1201                 break;
1203             }
1205         }
1207     if (closed)
1208         outs.printf("z");;
1214 bool OdfOutput::writeTree(Writer &outs, Inkscape::XML::Node *node)
1216     //# Get the SPItem, if applicable
1217     SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node);
1218     if (!reprobj)
1219         return true;
1220     if (!SP_IS_ITEM(reprobj))
1221         {
1222         return true;
1223         }
1224     SPItem *item = SP_ITEM(reprobj);
1227     std::string nodeName = node->name();
1228     std::string id       = getAttribute(node, "id");
1230     NR::Matrix tf        = sp_item_i2d_affine(item);
1231     NR::Rect bbox        = sp_item_bbox_desktop(item);
1233     //Flip Y into document coordinates
1234     double doc_height    = sp_document_height(SP_ACTIVE_DOCUMENT);
1235     NR::Matrix doc2dt_tf = NR::Matrix(NR::scale(1, -1));
1236     doc2dt_tf            = doc2dt_tf * NR::Matrix(NR::translate(0, doc_height));
1237     tf                   = tf   * doc2dt_tf;
1238     bbox                 = bbox * doc2dt_tf;
1240     double x      = pxToCm * bbox.min()[NR::X];
1241     double y      = pxToCm * bbox.min()[NR::Y];
1242     double width  = pxToCm * ( bbox.max()[NR::X] - bbox.min()[NR::X] );
1243     double height = pxToCm * ( bbox.max()[NR::Y] - bbox.min()[NR::Y] );
1246     //# Do our stuff
1247     SPCurve *curve = NULL;
1249     //g_message("##### %s #####", nodeName.c_str());
1251     if (nodeName == "svg" || nodeName == "svg:svg")
1252         {
1253         //# Iterate through the children
1254         for (Inkscape::XML::Node *child = node->firstChild() ; child ; child = child->next())
1255             {
1256             if (!writeTree(outs, child))
1257                 return false;
1258             }
1259         return true;
1260         }
1261     else if (nodeName == "g" || nodeName == "svg:g")
1262         {
1263         if (id.size() > 0)
1264             outs.printf("<draw:g id=\"%s\">\n", id.c_str());
1265         else
1266             outs.printf("<draw:g>\n");
1267         //# Iterate through the children
1268         for (Inkscape::XML::Node *child = node->firstChild() ; child ; child = child->next())
1269             {
1270             if (!writeTree(outs, child))
1271                 return false;
1272             }
1273         if (id.size() > 0)
1274             outs.printf("</draw:g> <!-- id=\"%s\" -->\n", id.c_str());
1275         else
1276             outs.printf("</draw:g>\n");
1277         return true;
1278         }
1279     else if (nodeName == "image" || nodeName == "svg:image")
1280         {
1281         if (!SP_IS_IMAGE(item))
1282             {
1283             g_warning("<image> is not an SPImage.  Why?  ;-)");
1284             return false;
1285             }
1287         SPImage *img   = SP_IMAGE(item);
1288         double ix      = img->x.computed;
1289         double iy      = img->y.computed;
1290         double iwidth  = img->width.computed;
1291         double iheight = img->height.computed;
1293         NR::Rect ibbox(NR::Point(ix, iy), NR::Point(iwidth, iheight));
1294         ix      = pxToCm * ibbox.min()[NR::X];
1295         iy      = pxToCm * ibbox.min()[NR::Y];
1296         iwidth  = pxToCm * ( ibbox.max()[NR::X] - ibbox.min()[NR::X] );
1297         iheight = pxToCm * ( ibbox.max()[NR::Y] - ibbox.min()[NR::Y] );
1299         NR::Matrix itemTransform = item->transform;
1300         std::string itemTransformString = formatTransform(itemTransform);
1301         g_message("trans:%s", itemTransformString.c_str());
1302         analyzeTransform(itemTransform);
1304         std::string href = getAttribute(node, "xlink:href");
1305         std::map<std::string, std::string>::iterator iter = imageTable.find(href);
1306         if (iter == imageTable.end())
1307             {
1308             g_warning("image '%s' not in table", href.c_str());
1309             return false;
1310             }
1311         std::string newName = iter->second;
1313         outs.printf("<draw:frame ");
1314         if (id.size() > 0)
1315             outs.printf("id=\"%s\" ", id.c_str());
1316         outs.printf("draw:style-name=\"gr1\" draw:text-style-name=\"P1\" draw:layer=\"layout\" ");
1317         outs.printf("svg:x=\"%.3fcm\" svg:y=\"%.3fcm\" ",
1318                                   ix, iy);
1319         outs.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
1320                                   iwidth, iheight);
1321         if (itemTransformString.size() > 0)
1322             outs.printf("draw:transform=\"%s\" ", itemTransformString.c_str());
1324         outs.printf(">\n");
1325         outs.printf("    <draw:image xlink:href=\"%s\" xlink:type=\"simple\"\n",
1326                               newName.c_str());
1327         outs.printf("        xlink:show=\"embed\" xlink:actuate=\"onLoad\">\n");
1328         outs.printf("        <text:p/>\n");
1329         outs.printf("    </draw:image>\n");
1330         outs.printf("</draw:frame>\n");
1331         return true;
1332         }
1333     else if (SP_IS_SHAPE(item))
1334         {
1335         //g_message("### %s is a shape", nodeName.c_str());
1336         curve = sp_shape_get_curve(SP_SHAPE(item));
1337         }
1338     else if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))
1339         {
1340         curve = te_get_layout(item)->convertToCurves();
1341         }
1343     if (curve)
1344         {
1345         //### Default <path> output
1347         outs.printf("<draw:path ");
1348         if (id.size()>0)
1349             outs.printf("id=\"%s\" ", id.c_str());
1351         std::map<std::string, std::string>::iterator iter;
1352         iter = styleLookupTable.find(id);
1353         if (iter != styleLookupTable.end())
1354             {
1355             std::string styleName = iter->second;
1356             outs.printf("draw:style-name=\"%s\" ", styleName.c_str());
1357             }
1359         outs.printf("draw:layer=\"layout\" svg:x=\"%.3fcm\" svg:y=\"%.3fcm\" ",
1360                        x, y);
1361         outs.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
1362                        width, height);
1363         outs.printf("svg:viewBox=\"0.0 0.0 %.3f %.3f\"\n",
1364                        width * 1000.0, height * 1000.0);
1366         outs.printf("    svg:d=\"");
1367         writePath(outs, curve->bpath, tf, x, y);
1368         outs.printf("\"");
1370         outs.printf(">\n");
1371         outs.printf("</draw:path>\n");
1374         sp_curve_unref(curve);
1375         }
1377     return true;
1383 bool OdfOutput::writeContent(ZipFile &zf, Inkscape::XML::Node *node)
1385     BufferOutputStream bouts;
1386     OutputStreamWriter outs(bouts);
1388     time_t tim;
1389     time(&tim);
1391     outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1392     outs.printf("\n");
1393     outs.printf("\n");
1394     outs.printf("<!--\n");
1395     outs.printf("*************************************************************************\n");
1396     outs.printf("  file:  content.xml\n");
1397     outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
1398     outs.printf("  http://www.inkscape.org\n");
1399     outs.printf("*************************************************************************\n");
1400     outs.printf("-->\n");
1401     outs.printf("\n");
1402     outs.printf("\n");
1403     outs.printf("<office:document-content\n");
1404     outs.printf("    xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
1405     outs.printf("    xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");
1406     outs.printf("    xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");
1407     outs.printf("    xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");
1408     outs.printf("    xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");
1409     outs.printf("    xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");
1410     outs.printf("    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
1411     outs.printf("    xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
1412     outs.printf("    xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
1413     outs.printf("    xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");
1414     outs.printf("    xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
1415     outs.printf("    xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");
1416     outs.printf("    xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");
1417     outs.printf("    xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");
1418     outs.printf("    xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");
1419     outs.printf("    xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");
1420     outs.printf("    xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");
1421     outs.printf("    xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
1422     outs.printf("    xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");
1423     outs.printf("    xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");
1424     outs.printf("    xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");
1425     outs.printf("    xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");
1426     outs.printf("    xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
1427     outs.printf("    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
1428     outs.printf("    xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
1429     outs.printf("    xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
1430     outs.printf("    office:version=\"1.0\">\n");
1431     outs.printf("\n");
1432     outs.printf("\n");
1433     outs.printf("<office:scripts/>\n");
1434     outs.printf("\n");
1435     outs.printf("\n");
1436     //AffineTransform trans = new AffineTransform();
1437     //trans.scale(12.0, 12.0);
1438     outs.printf("<!-- ######### CONVERSION FROM SVG STARTS ######## -->\n");
1439     outs.printf("<!--\n");
1440     outs.printf("*************************************************************************\n");
1441     outs.printf("  S T Y L E S\n");
1442     outs.printf("  Style entries have been pulled from the svg style and\n");
1443     outs.printf("  representation attributes in the SVG tree.  The tree elements\n");
1444     outs.printf("  then refer to them by name, in the ODF manner\n");
1445     outs.printf("*************************************************************************\n");
1446     outs.printf("-->\n");
1447     outs.printf("\n");
1448     outs.printf("\n");
1450     if (!writeStyle(outs))
1451         {
1452         g_warning("Failed to write styles");
1453         return false;
1454         }
1456     outs.printf("\n");
1457     outs.printf("\n");
1458     outs.printf("\n");
1459     outs.printf("\n");
1460     outs.printf("<!--\n");
1461     outs.printf("*************************************************************************\n");
1462     outs.printf("  D R A W I N G\n");
1463     outs.printf("  This section is the heart of SVG-ODF conversion.  We are\n");
1464     outs.printf("  starting with simple conversions, and will slowly evolve\n");
1465     outs.printf("  into a 'smarter' translation as time progresses.  Any help\n");
1466     outs.printf("  in improving .odg export is welcome.\n");
1467     outs.printf("*************************************************************************\n");
1468     outs.printf("-->\n");
1469     outs.printf("\n");
1470     outs.printf("\n");
1471     outs.printf("<office:body>\n");
1472     outs.printf("<office:drawing>\n");
1473     outs.printf("<draw:page draw:name=\"page1\" draw:style-name=\"dp1\"\n");
1474     outs.printf("        draw:master-page-name=\"Default\">\n");
1475     outs.printf("\n");
1476     outs.printf("\n");
1478     if (!writeTree(outs, node))
1479         {
1480         g_warning("Failed to convert SVG tree");
1481         return false;
1482         }
1484     outs.printf("\n");
1485     outs.printf("\n");
1487     outs.printf("</draw:page>\n");
1488     outs.printf("</office:drawing>\n");
1490     outs.printf("\n");
1491     outs.printf("\n");
1492     outs.printf("<!-- ######### CONVERSION FROM SVG ENDS ######## -->\n");
1493     outs.printf("\n");
1494     outs.printf("\n");
1496     outs.printf("</office:body>\n");
1497     outs.printf("</office:document-content>\n");
1498     outs.printf("\n");
1499     outs.printf("\n");
1500     outs.printf("\n");
1501     outs.printf("<!--\n");
1502     outs.printf("*************************************************************************\n");
1503     outs.printf("  E N D    O F    F I L E\n");
1504     outs.printf("  Have a nice day  - ishmal\n");
1505     outs.printf("*************************************************************************\n");
1506     outs.printf("-->\n");
1507     outs.printf("\n");
1508     outs.printf("\n");
1512     //Make our entry
1513     ZipEntry *ze = zf.newEntry("content.xml", "ODF master content file");
1514     ze->setUncompressedData(bouts.getBuffer());
1515     ze->finish();
1517     return true;
1523 /**
1524  * Descends into the SVG tree, mapping things to ODF when appropriate
1525  */
1526 void
1527 OdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *uri)
1529     //g_message("native file:%s\n", uri);
1530     documentUri = URI(uri);
1532     ZipFile zf;
1533     styleTable.clear();
1534     styleLookupTable.clear();
1535     imageTable.clear();
1536     preprocess(zf, doc->rroot);
1538     if (!writeManifest(zf))
1539         {
1540         g_warning("Failed to write manifest");
1541         return;
1542         }
1544     if (!writeMeta(zf))
1545         {
1546         g_warning("Failed to write metafile");
1547         return;
1548         }
1550     if (!writeContent(zf, doc->rroot))
1551         {
1552         g_warning("Failed to write content");
1553         return;
1554         }
1556     if (!zf.writeFile(uri))
1557         {
1558         return;
1559         }
1563 /**
1564  * This is the definition of PovRay output.  This function just
1565  * calls the extension system with the memory allocated XML that
1566  * describes the data.
1567 */
1568 void
1569 OdfOutput::init()
1571     Inkscape::Extension::build_from_mem(
1572         "<inkscape-extension>\n"
1573             "<name>" N_("OpenDocument Drawing Output") "</name>\n"
1574             "<id>org.inkscape.output.odf</id>\n"
1575             "<output>\n"
1576                 "<extension>.odg</extension>\n"
1577                 "<mimetype>text/x-povray-script</mimetype>\n"
1578                 "<filetypename>" N_("OpenDocument drawing (*.odg)") "</filetypename>\n"
1579                 "<filetypetooltip>" N_("OpenDocument drawing file") "</filetypetooltip>\n"
1580             "</output>\n"
1581         "</inkscape-extension>",
1582         new OdfOutput());
1585 /**
1586  * Make sure that we are in the database
1587  */
1588 bool
1589 OdfOutput::check (Inkscape::Extension::Extension *module)
1591     /* We don't need a Key
1592     if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_POV))
1593         return FALSE;
1594     */
1596     return TRUE;
1601 //########################################################################
1602 //# I N P U T
1603 //########################################################################
1607 //#######################
1608 //# L A T E R  !!!  :-)
1609 //#######################
1623 }  //namespace Internal
1624 }  //namespace Extension
1625 }  //namespace Inkscape
1628 //########################################################################
1629 //# E N D    O F    F I L E
1630 //########################################################################
1632 /*
1633   Local Variables:
1634   mode:c++
1635   c-file-style:"stroustrup"
1636   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1637   indent-tabs-mode:nil
1638   fill-column:99
1639   End:
1640 */
1641 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :