Code

Got handedness-reversal to work. Yaay. Images look good now
[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 //########################################################################
767 #define pi 3.14159
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 /*
839 static void analyzeTransform1(NR::Matrix &tf)
841     SingularValueDecomposition svd(tf);
842     double scale1 = svd.getS0();
843     double rotate = svd.getS1();
844     double scale2 = svd.getS2();
845     NR::Matrix u   = svd.getU();
846     NR::Matrix v   = svd.getV();
847     NR::Matrix uvt = svd.getUVt();
848     //g_message("s1:%f  rot:%f  s2:%f", scale1, rotate, scale2);
849     std::string us = formatTransform(u);
850     //g_message("u:%s", us.c_str());
851     std::string vs = formatTransform(v);
852     //g_message("v:%s", vs.c_str());
853     std::string uvts = formatTransform(uvt);
854     //g_message("uvt:%s", uvts.c_str());
856 */
859 static void analyzeTransform2(NR::Matrix &tf,
860            double &xskew, double &yskew, double &xscale, double &yscale)
862     //Let's calculate some of the qualities of the transform directly
863     //Make a unit rect and transform it
864     NR::Point top_left(0.0, 0.0);
865     NR::Point top_right(1.0, 0.0);
866     NR::Point bottom_left(0.0, 1.0);
867     NR::Point bottom_right(1.0, 1.0);
868     top_left     *= tf;
869     top_right    *= tf;
870     bottom_left  *= tf;
871     bottom_right *= tf;
872     double dx_tr = top_right[NR::X]   - top_left[NR::X];
873     double dy_tr = top_right[NR::Y]   - top_left[NR::Y];
874     double dx_bl = bottom_left[NR::X] - top_left[NR::X];
875     double dy_bl = bottom_left[NR::Y] - top_left[NR::Y];
877     double xskew_angle = 0.0;
878     double yskew_angle = 0.0;
879     if (fabs(dx_tr) < 1.0e-10 && fabs(dy_tr) > 1.0e-10)  //90 degrees?
880         {
881         if (dy_tr>0)
882             yskew_angle = pi / 2.0;
883         else
884             yskew_angle = -pi / 2.0;
885         }
886     else
887         {
888         yskew_angle = atan(dy_tr / dx_tr);
889         }
891     if (fabs(dy_bl) < 1.0e-10 && fabs(dx_bl) > 1.0e-10)  //90 degrees?
892         {
893         if (dx_bl>0)
894             xskew_angle = pi / 2.0;
895         else
896             xskew_angle = -pi / 2.0;
897         }
898     else
899         {
900         xskew_angle = atan(dx_bl / dy_bl);
901         }
903     double expected_xsize = 1.0 + dx_bl;
904     xscale =
905         ( bottom_right[NR::X] - top_left[NR::X] )/ expected_xsize;
906     double expected_ysize = 1.0 + dy_tr;
907     yscale =
908         ( bottom_right[NR::Y] - top_left[NR::Y] )/ expected_ysize;
910     //g_message("xskew:%f yskew:%f xscale:%f yscale:%f",
911     //      xskew_angle, yskew_angle, xscale, yscale);
912     xskew = xskew_angle;
913     yskew = xskew_angle;
919 /**
920  * Method descends into the repr tree, converting image and style info
921  * into forms compatible in ODF.
922  */
923 void
924 OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node)
927     std::string nodeName = node->name();
928     std::string id       = getAttribute(node, "id");
930     if (nodeName == "image" || nodeName == "svg:image")
931         {
932         //g_message("image");
933         std::string href = getAttribute(node, "xlink:href");
934         if (href.size() > 0)
935             {
936             std::string oldName = href;
937             std::string ext = getExtension(oldName);
938             if (ext == ".jpeg")
939                 ext = ".jpg";
940             if (imageTable.find(oldName) == imageTable.end())
941                 {
942                 char buf[64];
943                 snprintf(buf, 63, "Pictures/image%d%s",
944                     imageTable.size(), ext.c_str());
945                 std::string newName = buf;
946                 imageTable[oldName] = newName;
947                 std::string comment = "old name was: ";
948                 comment.append(oldName);
949                 URI oldUri(oldName);
950                 //g_message("oldpath:%s", oldUri.getNativePath().c_str());
951                 //# if relative to the documentURI, get proper path
952                 URI resUri = documentUri.resolve(oldUri);
953                 DOMString pathName = resUri.getNativePath();
954                 //g_message("native path:%s", pathName.c_str());
955                 ZipEntry *ze = zf.addFile(pathName, comment);
956                 if (ze)
957                     {
958                     ze->setFileName(newName);
959                     }
960                 else
961                     {
962                     g_warning("Could not load image file '%s'", pathName.c_str());
963                     }
964                 }
965             }
966         }
970     SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node);
971     if (!reprobj)
972         return;
973     if (!SP_IS_ITEM(reprobj))
974         {
975         return;
976         }
977     SPItem *item = SP_ITEM(reprobj);
978     SPStyle *style = SP_OBJECT_STYLE(item);
979     if (style && id.size()>0)
980         {
981         StyleInfo si;
982         if (style->fill.type == SP_PAINT_TYPE_COLOR)
983             {
984             guint32 fillCol =
985                 sp_color_get_rgba32_ualpha(&style->fill.value.color, 0);
986             char buf[16];
987             int r = (fillCol >> 24) & 0xff;
988             int g = (fillCol >> 16) & 0xff;
989             int b = (fillCol >>  8) & 0xff;
990             //g_message("## %s %lx", id.c_str(), (unsigned int)fillCol);
991             snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
992             si.fillColor = buf;
993             si.fill      = "solid";
994             double opacityPercent = 100.0 *
995                  (SP_SCALE24_TO_FLOAT(style->fill_opacity.value));
996             snprintf(buf, 15, "%.2f%%", opacityPercent);
997             si.fillOpacity = buf;
998             }
999         if (style->stroke.type == SP_PAINT_TYPE_COLOR)
1000             {
1001             guint32 strokeCol =
1002                 sp_color_get_rgba32_ualpha(&style->stroke.value.color, 0);
1003             char buf[16];
1004             int r = (strokeCol >> 24) & 0xff;
1005             int g = (strokeCol >> 16) & 0xff;
1006             int b = (strokeCol >>  8) & 0xff;
1007             snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
1008             si.strokeColor = buf;
1009             snprintf(buf, 15, "%.2fpt", style->stroke_width.value);
1010             si.strokeWidth = buf;
1011             si.stroke      = "solid";
1012             double opacityPercent = 100.0 *
1013                  (SP_SCALE24_TO_FLOAT(style->stroke_opacity.value));
1014             snprintf(buf, 15, "%.2f%%", opacityPercent);
1015             si.strokeOpacity = buf;
1016             }
1018         //Look for existing identical style;
1019         bool styleMatch = false;
1020         std::vector<StyleInfo>::iterator iter;
1021         for (iter=styleTable.begin() ; iter!=styleTable.end() ; iter++)
1022             {
1023             if (si.equals(*iter))
1024                 {
1025                 //map to existing styleTable entry
1026                 std::string styleName = iter->name;
1027                 //g_message("found duplicate style:%s", styleName.c_str());
1028                 styleLookupTable[id] = styleName;
1029                 styleMatch = true;
1030                 break;
1031                 }
1032             }
1033         //None found, make a new pair or entries
1034         if (!styleMatch)
1035             {
1036             char buf[16];
1037             snprintf(buf, 15, "style%d", styleTable.size());
1038             std::string styleName = buf;
1039             si.name = styleName;
1040             styleTable.push_back(si);
1041             styleLookupTable[id] = styleName;
1042             }
1043         }
1046     for (Inkscape::XML::Node *child = node->firstChild() ;
1047             child ; child = child->next())
1048         preprocess(zf, child);
1053 bool OdfOutput::writeManifest(ZipFile &zf)
1055     BufferOutputStream bouts;
1056     OutputStreamWriter outs(bouts);
1058     time_t tim;
1059     time(&tim);
1061     outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1062     outs.printf("<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">\n");
1063     outs.printf("\n");
1064     outs.printf("\n");
1065     outs.printf("<!--\n");
1066     outs.printf("*************************************************************************\n");
1067     outs.printf("  file:  manifest.xml\n");
1068     outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
1069     outs.printf("  http://www.inkscape.org\n");
1070     outs.printf("*************************************************************************\n");
1071     outs.printf("-->\n");
1072     outs.printf("\n");
1073     outs.printf("\n");
1074     outs.printf("<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n");
1075     outs.printf("    <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.graphics\" manifest:full-path=\"/\"/>\n");
1076     outs.printf("    <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>\n");
1077     outs.printf("    <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>\n");
1078     outs.printf("    <!--List our images here-->\n");
1079     std::map<std::string, std::string>::iterator iter;
1080     for (iter = imageTable.begin() ; iter!=imageTable.end() ; iter++)
1081         {
1082         std::string oldName = iter->first;
1083         std::string newName = iter->second;
1085         std::string ext = getExtension(oldName);
1086         if (ext == ".jpeg")
1087             ext = ".jpg";
1088         outs.printf("    <manifest:file-entry manifest:media-type=\"");
1089         if (ext == ".gif")
1090             outs.printf("image/gif");
1091         else if (ext == ".png")
1092             outs.printf("image/png");
1093         else if (ext == ".jpg")
1094             outs.printf("image/jpeg");
1095         outs.printf("\" manifest:full-path=\"");
1096         outs.printf((char *)newName.c_str());
1097         outs.printf("\"/>\n");
1098         }
1099     outs.printf("</manifest:manifest>\n");
1101     outs.close();
1103     //Make our entry
1104     ZipEntry *ze = zf.newEntry("META-INF/manifest.xml", "ODF file manifest");
1105     ze->setUncompressedData(bouts.getBuffer());
1106     ze->finish();
1108     return true;
1112 bool OdfOutput::writeMeta(ZipFile &zf)
1114     BufferOutputStream bouts;
1115     OutputStreamWriter outs(bouts);
1117     time_t tim;
1118     time(&tim);
1120     outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1121     outs.printf("\n");
1122     outs.printf("\n");
1123     outs.printf("<!--\n");
1124     outs.printf("*************************************************************************\n");
1125     outs.printf("  file:  meta.xml\n");
1126     outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
1127     outs.printf("  http://www.inkscape.org\n");
1128     outs.printf("*************************************************************************\n");
1129     outs.printf("-->\n");
1130     outs.printf("\n");
1131     outs.printf("\n");
1132     outs.printf("<office:document-meta\n");
1133     outs.printf("xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
1134     outs.printf("xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
1135     outs.printf("xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
1136     outs.printf("xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
1137     outs.printf("xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
1138     outs.printf("xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
1139     outs.printf("xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
1140     outs.printf("xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
1141     outs.printf("office:version=\"1.0\">\n");
1142     outs.printf("<office:meta>\n");
1143     outs.printf("    <meta:generator>Inkscape.org - 0.44</meta:generator>\n");
1144     outs.printf("    <meta:initial-creator>clark kent</meta:initial-creator>\n");
1145     outs.printf("    <meta:creation-date>2006-04-13T17:12:29</meta:creation-date>\n");
1146     outs.printf("    <dc:creator>clark kent</dc:creator>\n");
1147     outs.printf("    <dc:date>2006-04-13T17:13:20</dc:date>\n");
1148     outs.printf("    <dc:language>en-US</dc:language>\n");
1149     outs.printf("    <meta:editing-cycles>2</meta:editing-cycles>\n");
1150     outs.printf("    <meta:editing-duration>PT56S</meta:editing-duration>\n");
1151     outs.printf("    <meta:user-defined meta:name=\"Info 1\"/>\n");
1152     outs.printf("    <meta:user-defined meta:name=\"Info 2\"/>\n");
1153     outs.printf("    <meta:user-defined meta:name=\"Info 3\"/>\n");
1154     outs.printf("    <meta:user-defined meta:name=\"Info 4\"/>\n");
1155     outs.printf("    <meta:document-statistic meta:object-count=\"2\"/>\n");
1156     outs.printf("</office:meta>\n");
1157     outs.printf("</office:document-meta>\n");
1158     outs.printf("\n");
1159     outs.printf("\n");
1162     outs.close();
1164     //Make our entry
1165     ZipEntry *ze = zf.newEntry("meta.xml", "ODF info file");
1166     ze->setUncompressedData(bouts.getBuffer());
1167     ze->finish();
1169     return true;
1173 bool OdfOutput::writeStyle(Writer &outs)
1175     outs.printf("<office:automatic-styles>\n");
1176     outs.printf("<!-- ####### 'Standard' styles ####### -->\n");
1177     outs.printf("<style:style style:name=\"dp1\" style:family=\"drawing-page\"/>\n");
1178     outs.printf("<style:style style:name=\"gr1\" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
1179     outs.printf("  <style:graphic-properties draw:stroke=\"none\" draw:fill=\"none\"\n");
1180     outs.printf("       draw:textarea-horizontal-align=\"center\"\n");
1181     outs.printf("       draw:textarea-vertical-align=\"middle\" draw:color-mode=\"standard\"\n");
1182     outs.printf("       draw:luminance=\"0%\" draw:contrast=\"0%\" draw:gamma=\"100%\" draw:red=\"0%\"\n");
1183     outs.printf("       draw:green=\"0%\" draw:blue=\"0%\" fo:clip=\"rect(0cm 0cm 0cm 0cm)\"\n");
1184     outs.printf("       draw:image-opacity=\"100%\" style:mirror=\"none\"/>\n");
1185     outs.printf("</style:style>\n");
1186     outs.printf("<style:style style:name=\"P1\" style:family=\"paragraph\">\n");
1187     outs.printf("  <style:paragraph-properties fo:text-align=\"center\"/>\n");
1188     outs.printf("</style:style>\n");
1190     //##  Dump our style table
1191     outs.printf("<!-- ####### Styles from Inkscape document ####### -->\n");
1192     std::vector<StyleInfo>::iterator iter;
1193     for (iter = styleTable.begin() ; iter != styleTable.end() ; iter++)
1194         {
1195         outs.printf("<style:style style:name=\"%s\"", iter->name.c_str());
1196         StyleInfo s(*iter);
1197         outs.printf(" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
1198         outs.printf("  <style:graphic-properties");
1199         outs.printf(" draw:fill=\"%s\" ", s.fill.c_str());
1200         if (s.fill != "none")
1201             {
1202             outs.printf(" draw:fill-color=\"%s\" ", s.fillColor.c_str());
1203             outs.printf(" draw:fill-opacity=\"%s\" ", s.fillOpacity.c_str());
1204             }
1205         outs.printf(" draw:stroke=\"%s\" ", s.stroke.c_str());
1206         if (s.stroke != "none")
1207             {
1208             outs.printf(" svg:stroke-width=\"%s\" ", s.strokeWidth.c_str());
1209             outs.printf(" svg:stroke-color=\"%s\" ", s.strokeColor.c_str());
1210             outs.printf(" svg:stroke-opacity=\"%s\" ", s.strokeOpacity.c_str());
1211             }
1212         outs.printf("/>\n");
1213         outs.printf("</style:style>\n");
1214         }
1216     outs.printf("</office:automatic-styles>\n");
1217     outs.printf("\n");
1219     return true;
1223 static void
1224 writePath(Writer &outs, NArtBpath const *bpath,
1225           NR::Matrix &tf, double xoff, double yoff)
1227     bool closed = false;
1228     NArtBpath *bp = (NArtBpath *)bpath;
1229     for (  ; bp->code != NR_END; bp++)
1230         {
1231         NR::Point const p1(bp->c(1) * tf);
1232         NR::Point const p2(bp->c(2) * tf);
1233         NR::Point const p3(bp->c(3) * tf);
1234         double x1 = (p1[NR::X] * pxToCm - xoff) * 1000.0;
1235         double y1 = (p1[NR::Y] * pxToCm - yoff) * 1000.0;
1236         double x2 = (p2[NR::X] * pxToCm - xoff) * 1000.0;
1237         double y2 = (p2[NR::Y] * pxToCm - yoff) * 1000.0;
1238         double x3 = (p3[NR::X] * pxToCm - xoff) * 1000.0;
1239         double y3 = (p3[NR::Y] * pxToCm - yoff) * 1000.0;
1241         switch (bp->code)
1242             {
1243             case NR_LINETO:
1244                 outs.printf("L %.3f,%.3f ",  x3 , y3);
1245                 break;
1247             case NR_CURVETO:
1248                 outs.printf("C %.3f,%.3f %.3f,%.3f %.3f,%.3f ",
1249                               x1, y1, x2, y2, x3, y3);
1250                 break;
1252             case NR_MOVETO_OPEN:
1253             case NR_MOVETO:
1254                 if (closed)
1255                     outs.printf("z ");
1256                 closed = ( bp->code == NR_MOVETO );
1257                 outs.printf("M %.3f,%.3f ",  x3 , y3);
1258                 break;
1260             default:
1261                 break;
1263             }
1265         }
1267     if (closed)
1268         outs.printf("z");;
1274 bool OdfOutput::writeTree(Writer &outs, Inkscape::XML::Node *node)
1276     //# Get the SPItem, if applicable
1277     SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node);
1278     if (!reprobj)
1279         return true;
1280     if (!SP_IS_ITEM(reprobj))
1281         {
1282         return true;
1283         }
1284     SPItem *item = SP_ITEM(reprobj);
1287     std::string nodeName = node->name();
1288     std::string id       = getAttribute(node, "id");
1290     NR::Matrix tf        = sp_item_i2d_affine(item);
1291     NR::Rect bbox        = sp_item_bbox_desktop(item);
1293     //Flip Y into document coordinates
1294     double doc_height    = sp_document_height(SP_ACTIVE_DOCUMENT);
1295     NR::Matrix doc2dt_tf = NR::Matrix(NR::scale(1, -1));
1296     doc2dt_tf            = doc2dt_tf * NR::Matrix(NR::translate(0, doc_height));
1297     tf                   = tf   * doc2dt_tf;
1298     bbox                 = bbox * doc2dt_tf;
1300     double x      = pxToCm * bbox.min()[NR::X];
1301     double y      = pxToCm * bbox.min()[NR::Y];
1302     double width  = pxToCm * ( bbox.max()[NR::X] - bbox.min()[NR::X] );
1303     double height = pxToCm * ( bbox.max()[NR::Y] - bbox.min()[NR::Y] );
1306     double xskew;
1307     double yskew;
1308     double xscale;
1309     double yscale;
1310     analyzeTransform2(tf, xskew, yskew, xscale, yscale);
1312     double item_xskew;
1313     double item_yskew;
1314     double item_xscale;
1315     double item_yscale;
1316     analyzeTransform2(item->transform,
1317         item_xskew, item_yskew, item_xscale, item_yscale);
1319     //# Do our stuff
1320     SPCurve *curve = NULL;
1322     //g_message("##### %s #####", nodeName.c_str());
1324     if (nodeName == "svg" || nodeName == "svg:svg")
1325         {
1326         //# Iterate through the children
1327         for (Inkscape::XML::Node *child = node->firstChild() ; child ; child = child->next())
1328             {
1329             if (!writeTree(outs, child))
1330                 return false;
1331             }
1332         return true;
1333         }
1334     else if (nodeName == "g" || nodeName == "svg:g")
1335         {
1336         if (id.size() > 0)
1337             outs.printf("<draw:g id=\"%s\">\n", id.c_str());
1338         else
1339             outs.printf("<draw:g>\n");
1340         //# Iterate through the children
1341         for (Inkscape::XML::Node *child = node->firstChild() ; child ; child = child->next())
1342             {
1343             if (!writeTree(outs, child))
1344                 return false;
1345             }
1346         if (id.size() > 0)
1347             outs.printf("</draw:g> <!-- id=\"%s\" -->\n", id.c_str());
1348         else
1349             outs.printf("</draw:g>\n");
1350         return true;
1351         }
1352     else if (nodeName == "image" || nodeName == "svg:image")
1353         {
1354         if (!SP_IS_IMAGE(item))
1355             {
1356             g_warning("<image> is not an SPImage.  Why?  ;-)");
1357             return false;
1358             }
1360         SPImage *img   = SP_IMAGE(item);
1361         double ix      = img->x.value;
1362         double iy      = img->y.value;
1363         double iwidth  = img->width.value;
1364         double iheight = img->height.value;
1366         NR::Rect ibbox(NR::Point(ix, iy), NR::Point(ix+iwidth, iy+iheight));
1367         ibbox = ibbox * tf;
1368         ix      = pxToCm * ibbox.min()[NR::X];
1369         iy      = pxToCm * ibbox.min()[NR::Y];
1370         //iwidth  = pxToCm * ( ibbox.max()[NR::X] - ibbox.min()[NR::X] );
1371         //iheight = pxToCm * ( ibbox.max()[NR::Y] - ibbox.min()[NR::Y] );
1372         iwidth  = pxToCm * xscale * iwidth;
1373         iheight = pxToCm * yscale * iheight;
1375         NR::Matrix itemTransform = NR::Matrix(NR::scale(1, -1));
1376         itemTransform = itemTransform * item->transform;
1377         itemTransform = itemTransform * NR::Matrix(NR::scale(1, -1));
1379         std::string itemTransformString = formatTransform(itemTransform);
1381         std::string href = getAttribute(node, "xlink:href");
1382         std::map<std::string, std::string>::iterator iter = imageTable.find(href);
1383         if (iter == imageTable.end())
1384             {
1385             g_warning("image '%s' not in table", href.c_str());
1386             return false;
1387             }
1388         std::string newName = iter->second;
1390         outs.printf("<draw:frame ");
1391         if (id.size() > 0)
1392             outs.printf("id=\"%s\" ", id.c_str());
1393         outs.printf("draw:style-name=\"gr1\" draw:text-style-name=\"P1\" draw:layer=\"layout\" ");
1394         //no x or y.  make them the translate transform, last one
1395         outs.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
1396                                   iwidth, iheight);
1397         if (itemTransformString.size() > 0)
1398             outs.printf("draw:transform=\"%s translate(%.3fcm, %.3fcm)\" ",
1399                 itemTransformString.c_str(), ix, iy);
1401         outs.printf(">\n");
1402         outs.printf("    <draw:image xlink:href=\"%s\" xlink:type=\"simple\"\n",
1403                               newName.c_str());
1404         outs.printf("        xlink:show=\"embed\" xlink:actuate=\"onLoad\">\n");
1405         outs.printf("        <text:p/>\n");
1406         outs.printf("    </draw:image>\n");
1407         outs.printf("</draw:frame>\n");
1408         return true;
1409         }
1410     else if (SP_IS_SHAPE(item))
1411         {
1412         //g_message("### %s is a shape", nodeName.c_str());
1413         curve = sp_shape_get_curve(SP_SHAPE(item));
1414         }
1415     else if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))
1416         {
1417         curve = te_get_layout(item)->convertToCurves();
1418         }
1420     if (curve)
1421         {
1422         //### Default <path> output
1424         outs.printf("<draw:path ");
1425         if (id.size()>0)
1426             outs.printf("id=\"%s\" ", id.c_str());
1428         std::map<std::string, std::string>::iterator iter;
1429         iter = styleLookupTable.find(id);
1430         if (iter != styleLookupTable.end())
1431             {
1432             std::string styleName = iter->second;
1433             outs.printf("draw:style-name=\"%s\" ", styleName.c_str());
1434             }
1436         outs.printf("draw:layer=\"layout\" svg:x=\"%.3fcm\" svg:y=\"%.3fcm\" ",
1437                        x, y);
1438         outs.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
1439                        width, height);
1440         outs.printf("svg:viewBox=\"0.0 0.0 %.3f %.3f\"\n",
1441                        width * 1000.0, height * 1000.0);
1443         outs.printf("    svg:d=\"");
1444         writePath(outs, curve->bpath, tf, x, y);
1445         outs.printf("\"");
1447         outs.printf(">\n");
1448         outs.printf("</draw:path>\n");
1451         sp_curve_unref(curve);
1452         }
1454     return true;
1460 bool OdfOutput::writeContent(ZipFile &zf, Inkscape::XML::Node *node)
1462     BufferOutputStream bouts;
1463     OutputStreamWriter outs(bouts);
1465     time_t tim;
1466     time(&tim);
1468     outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1469     outs.printf("\n");
1470     outs.printf("\n");
1471     outs.printf("<!--\n");
1472     outs.printf("*************************************************************************\n");
1473     outs.printf("  file:  content.xml\n");
1474     outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
1475     outs.printf("  http://www.inkscape.org\n");
1476     outs.printf("*************************************************************************\n");
1477     outs.printf("-->\n");
1478     outs.printf("\n");
1479     outs.printf("\n");
1480     outs.printf("<office:document-content\n");
1481     outs.printf("    xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
1482     outs.printf("    xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");
1483     outs.printf("    xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");
1484     outs.printf("    xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");
1485     outs.printf("    xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");
1486     outs.printf("    xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");
1487     outs.printf("    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
1488     outs.printf("    xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
1489     outs.printf("    xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
1490     outs.printf("    xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");
1491     outs.printf("    xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
1492     outs.printf("    xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");
1493     outs.printf("    xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");
1494     outs.printf("    xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");
1495     outs.printf("    xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");
1496     outs.printf("    xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");
1497     outs.printf("    xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");
1498     outs.printf("    xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
1499     outs.printf("    xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");
1500     outs.printf("    xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");
1501     outs.printf("    xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");
1502     outs.printf("    xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");
1503     outs.printf("    xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
1504     outs.printf("    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
1505     outs.printf("    xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
1506     outs.printf("    xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
1507     outs.printf("    office:version=\"1.0\">\n");
1508     outs.printf("\n");
1509     outs.printf("\n");
1510     outs.printf("<office:scripts/>\n");
1511     outs.printf("\n");
1512     outs.printf("\n");
1513     //AffineTransform trans = new AffineTransform();
1514     //trans.scale(12.0, 12.0);
1515     outs.printf("<!-- ######### CONVERSION FROM SVG STARTS ######## -->\n");
1516     outs.printf("<!--\n");
1517     outs.printf("*************************************************************************\n");
1518     outs.printf("  S T Y L E S\n");
1519     outs.printf("  Style entries have been pulled from the svg style and\n");
1520     outs.printf("  representation attributes in the SVG tree.  The tree elements\n");
1521     outs.printf("  then refer to them by name, in the ODF manner\n");
1522     outs.printf("*************************************************************************\n");
1523     outs.printf("-->\n");
1524     outs.printf("\n");
1525     outs.printf("\n");
1527     if (!writeStyle(outs))
1528         {
1529         g_warning("Failed to write styles");
1530         return false;
1531         }
1533     outs.printf("\n");
1534     outs.printf("\n");
1535     outs.printf("\n");
1536     outs.printf("\n");
1537     outs.printf("<!--\n");
1538     outs.printf("*************************************************************************\n");
1539     outs.printf("  D R A W I N G\n");
1540     outs.printf("  This section is the heart of SVG-ODF conversion.  We are\n");
1541     outs.printf("  starting with simple conversions, and will slowly evolve\n");
1542     outs.printf("  into a 'smarter' translation as time progresses.  Any help\n");
1543     outs.printf("  in improving .odg export is welcome.\n");
1544     outs.printf("*************************************************************************\n");
1545     outs.printf("-->\n");
1546     outs.printf("\n");
1547     outs.printf("\n");
1548     outs.printf("<office:body>\n");
1549     outs.printf("<office:drawing>\n");
1550     outs.printf("<draw:page draw:name=\"page1\" draw:style-name=\"dp1\"\n");
1551     outs.printf("        draw:master-page-name=\"Default\">\n");
1552     outs.printf("\n");
1553     outs.printf("\n");
1555     if (!writeTree(outs, node))
1556         {
1557         g_warning("Failed to convert SVG tree");
1558         return false;
1559         }
1561     outs.printf("\n");
1562     outs.printf("\n");
1564     outs.printf("</draw:page>\n");
1565     outs.printf("</office:drawing>\n");
1567     outs.printf("\n");
1568     outs.printf("\n");
1569     outs.printf("<!-- ######### CONVERSION FROM SVG ENDS ######## -->\n");
1570     outs.printf("\n");
1571     outs.printf("\n");
1573     outs.printf("</office:body>\n");
1574     outs.printf("</office:document-content>\n");
1575     outs.printf("\n");
1576     outs.printf("\n");
1577     outs.printf("\n");
1578     outs.printf("<!--\n");
1579     outs.printf("*************************************************************************\n");
1580     outs.printf("  E N D    O F    F I L E\n");
1581     outs.printf("  Have a nice day  - ishmal\n");
1582     outs.printf("*************************************************************************\n");
1583     outs.printf("-->\n");
1584     outs.printf("\n");
1585     outs.printf("\n");
1589     //Make our entry
1590     ZipEntry *ze = zf.newEntry("content.xml", "ODF master content file");
1591     ze->setUncompressedData(bouts.getBuffer());
1592     ze->finish();
1594     return true;
1600 /**
1601  * Descends into the SVG tree, mapping things to ODF when appropriate
1602  */
1603 void
1604 OdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *uri)
1606     //g_message("native file:%s\n", uri);
1607     documentUri = URI(uri);
1609     ZipFile zf;
1610     styleTable.clear();
1611     styleLookupTable.clear();
1612     imageTable.clear();
1613     preprocess(zf, doc->rroot);
1615     if (!writeManifest(zf))
1616         {
1617         g_warning("Failed to write manifest");
1618         return;
1619         }
1621     if (!writeMeta(zf))
1622         {
1623         g_warning("Failed to write metafile");
1624         return;
1625         }
1627     if (!writeContent(zf, doc->rroot))
1628         {
1629         g_warning("Failed to write content");
1630         return;
1631         }
1633     if (!zf.writeFile(uri))
1634         {
1635         return;
1636         }
1640 /**
1641  * This is the definition of PovRay output.  This function just
1642  * calls the extension system with the memory allocated XML that
1643  * describes the data.
1644 */
1645 void
1646 OdfOutput::init()
1648     Inkscape::Extension::build_from_mem(
1649         "<inkscape-extension>\n"
1650             "<name>" N_("OpenDocument Drawing Output") "</name>\n"
1651             "<id>org.inkscape.output.odf</id>\n"
1652             "<output>\n"
1653                 "<extension>.odg</extension>\n"
1654                 "<mimetype>text/x-povray-script</mimetype>\n"
1655                 "<filetypename>" N_("OpenDocument drawing (*.odg)") "</filetypename>\n"
1656                 "<filetypetooltip>" N_("OpenDocument drawing file") "</filetypetooltip>\n"
1657             "</output>\n"
1658         "</inkscape-extension>",
1659         new OdfOutput());
1662 /**
1663  * Make sure that we are in the database
1664  */
1665 bool
1666 OdfOutput::check (Inkscape::Extension::Extension *module)
1668     /* We don't need a Key
1669     if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_POV))
1670         return FALSE;
1671     */
1673     return TRUE;
1678 //########################################################################
1679 //# I N P U T
1680 //########################################################################
1684 //#######################
1685 //# L A T E R  !!!  :-)
1686 //#######################
1700 }  //namespace Internal
1701 }  //namespace Extension
1702 }  //namespace Inkscape
1705 //########################################################################
1706 //# E N D    O F    F I L E
1707 //########################################################################
1709 /*
1710   Local Variables:
1711   mode:c++
1712   c-file-style:"stroustrup"
1713   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1714   indent-tabs-mode:nil
1715   fill-column:99
1716   End:
1717 */
1718 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :