~valavanisalex/ubuntu/precise/inkscape/fix-943984

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/extension/internal/odf.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.  People should consider this to be a framework
 
9
 * that can be continously upgraded for ever improving fidelity.  Potential
 
10
 * developers should especially look in preprocess() and writeTree() to see how
 
11
 * the SVG tree is scanned, read, translated, and then written to ODF.
 
12
 *
 
13
 * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
 
14
 *
 
15
 * Authors:
 
16
 *   Bob Jamison
 
17
 *
 
18
 * Copyright (C) 2006, 2007 Bob Jamison
 
19
 *
 
20
 *  This library is free software; you can redistribute it and/or
 
21
 *  modify it under the terms of the GNU Lesser General Public
 
22
 *  License as published by the Free Software Foundation; either
 
23
 *  version 2.1 of the License, or (at your option) any later version.
 
24
 *
 
25
 *  This library is distributed in the hope that it will be useful,
 
26
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
27
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
28
 *  Lesser General Public License for more details.
 
29
 *
 
30
 *  You should have received a copy of the GNU Lesser General Public
 
31
 *  License along with this library; if not, write to the Free Software
 
32
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
33
 */
 
34
 
 
35
 
 
36
 
 
37
#ifdef HAVE_CONFIG_H
 
38
# include <config.h>
 
39
#endif
 
40
 
 
41
#include "odf.h"
 
42
 
 
43
//# System includes
 
44
#include <stdio.h>
 
45
#include <time.h>
 
46
#include <vector>
 
47
 
 
48
 
 
49
//# Inkscape includes
 
50
#include "clear-n_.h"
 
51
#include "inkscape.h"
 
52
#include <style.h>
 
53
#include "display/curve.h"
 
54
#include <2geom/pathvector.h>
 
55
#include <2geom/bezier-curve.h>
 
56
#include <2geom/hvlinesegment.h>
 
57
#include <2geom/transforms.h>
 
58
#include <helper/geom.h>
 
59
#include "helper/geom-curves.h"
 
60
#include "extension/system.h"
 
61
 
 
62
#include "xml/repr.h"
 
63
#include "xml/attribute-record.h"
 
64
#include "sp-image.h"
 
65
#include "sp-gradient.h"
 
66
#include "sp-stop.h"
 
67
#include "gradient-chemistry.h"
 
68
#include "sp-linear-gradient.h"
 
69
#include "sp-radial-gradient.h"
 
70
#include "sp-path.h"
 
71
#include "sp-text.h"
 
72
#include "sp-flowtext.h"
 
73
#include "svg/svg.h"
 
74
#include "text-editing.h"
 
75
 
 
76
 
 
77
//# DOM-specific includes
 
78
#include "dom/dom.h"
 
79
#include "dom/util/ziptool.h"
 
80
#include "dom/io/domstream.h"
 
81
#include "dom/io/bufferstream.h"
 
82
#include "dom/io/stringstream.h"
 
83
 
 
84
 
 
85
 
 
86
 
 
87
 
 
88
 
 
89
namespace Inkscape
 
90
{
 
91
namespace Extension
 
92
{
 
93
namespace Internal
 
94
{
 
95
 
 
96
 
 
97
 
 
98
//# Shorthand notation
 
99
typedef org::w3c::dom::DOMString DOMString;
 
100
typedef org::w3c::dom::XMLCh XMLCh;
 
101
typedef org::w3c::dom::io::OutputStreamWriter OutputStreamWriter;
 
102
typedef org::w3c::dom::io::BufferOutputStream BufferOutputStream;
 
103
typedef org::w3c::dom::io::StringOutputStream StringOutputStream;
 
104
 
 
105
//########################################################################
 
106
//# C L A S S    SingularValueDecomposition
 
107
//########################################################################
 
108
#include <math.h>
 
109
 
 
110
class SVDMatrix
 
111
{
 
112
public:
 
113
 
 
114
    SVDMatrix()
 
115
        {
 
116
        init();
 
117
        }
 
118
 
 
119
    SVDMatrix(unsigned int rowSize, unsigned int colSize)
 
120
        {
 
121
        init();
 
122
        rows = rowSize;
 
123
        cols = colSize;
 
124
        size = rows * cols;
 
125
        d    = new double[size];
 
126
        for (unsigned int i=0 ; i<size ; i++)
 
127
            d[i] = 0.0;
 
128
        }
 
129
 
 
130
    SVDMatrix(double *vals, unsigned int rowSize, unsigned int colSize)
 
131
        {
 
132
        init();
 
133
        rows = rowSize;
 
134
        cols = colSize;
 
135
        size = rows * cols;
 
136
        d    = new double[size];
 
137
        for (unsigned int i=0 ; i<size ; i++)
 
138
            d[i] = vals[i];
 
139
        }
 
140
 
 
141
 
 
142
    SVDMatrix(const SVDMatrix &other)
 
143
        {
 
144
        init();
 
145
        assign(other);
 
146
        }
 
147
 
 
148
    SVDMatrix &operator=(const SVDMatrix &other)
 
149
        {
 
150
        assign(other);
 
151
        return *this;
 
152
        }
 
153
 
 
154
    virtual ~SVDMatrix()
 
155
        {
 
156
        delete[] d;
 
157
        }
 
158
 
 
159
     double& operator() (unsigned int row, unsigned int col)
 
160
         {
 
161
         if (row >= rows || col >= cols)
 
162
             return badval;
 
163
         return d[cols*row + col];
 
164
         }
 
165
 
 
166
     double operator() (unsigned int row, unsigned int col) const
 
167
         {
 
168
         if (row >= rows || col >= cols)
 
169
             return badval;
 
170
         return d[cols*row + col];
 
171
         }
 
172
 
 
173
     unsigned int getRows()
 
174
         {
 
175
         return rows;
 
176
         }
 
177
 
 
178
     unsigned int getCols()
 
179
         {
 
180
         return cols;
 
181
         }
 
182
 
 
183
     SVDMatrix multiply(const SVDMatrix &other)
 
184
         {
 
185
         if (cols != other.rows)
 
186
             {
 
187
             SVDMatrix dummy;
 
188
             return dummy;
 
189
             }
 
190
         SVDMatrix result(rows, other.cols);
 
191
         for (unsigned int i=0 ; i<rows ; i++)
 
192
             {
 
193
             for (unsigned int j=0 ; j<other.cols ; j++)
 
194
             {
 
195
                 double sum = 0.0;
 
196
                 for (unsigned int k=0 ; k<cols ; k++)
 
197
                     {
 
198
                     //sum += a[i][k] * b[k][j];
 
199
                     sum += d[i*cols +k] * other(k, j);
 
200
                     }
 
201
                 result(i, j) = sum;
 
202
                 }
 
203
 
 
204
             }
 
205
         return result;
 
206
         }
 
207
 
 
208
     SVDMatrix transpose()
 
209
         {
 
210
         SVDMatrix result(cols, rows);
 
211
         for (unsigned int i=0 ; i<rows ; i++)
 
212
             for (unsigned int j=0 ; j<cols ; j++)
 
213
                 result(j, i) = d[i*cols + j];
 
214
         return result;
 
215
         }
 
216
 
 
217
private:
 
218
 
 
219
 
 
220
    virtual void init()
 
221
        {
 
222
        badval = 0.0;
 
223
        d      = NULL;
 
224
        rows   = 0;
 
225
        cols   = 0;
 
226
        size   = 0;
 
227
        }
 
228
 
 
229
     void assign(const SVDMatrix &other)
 
230
        {
 
231
        if (d)
 
232
            {
 
233
            delete[] d;
 
234
            d = 0;
 
235
            }
 
236
        rows = other.rows;
 
237
        cols = other.cols;
 
238
        size = other.size;
 
239
        d = new double[size];
 
240
        for (unsigned int i=0 ; i<size ; i++)
 
241
            d[i] = other.d[i];
 
242
        }
 
243
 
 
244
    double badval;
 
245
 
 
246
    double *d;
 
247
    unsigned int rows;
 
248
    unsigned int cols;
 
249
    unsigned int size;
 
250
};
 
251
 
 
252
 
 
253
 
 
254
/**
 
255
 *
 
256
 * ====================================================
 
257
 *
 
258
 * NOTE:
 
259
 * This class is ported almost verbatim from the public domain
 
260
 * JAMA Matrix package.  It is modified to handle only 3x3 matrices
 
261
 * and our Geom::Matrix affine transform class.  We give full
 
262
 * attribution to them, along with many thanks.  JAMA can be found at:
 
263
 *     http://math.nist.gov/javanumerics/jama
 
264
 *
 
265
 * ====================================================
 
266
 *
 
267
 * Singular Value Decomposition.
 
268
 * <P>
 
269
 * For an m-by-n matrix A with m >= n, the singular value decomposition is
 
270
 * an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
 
271
 * an n-by-n orthogonal matrix V so that A = U*S*V'.
 
272
 * <P>
 
273
 * The singular values, sigma[k] = S[k][k], are ordered so that
 
274
 * sigma[0] >= sigma[1] >= ... >= sigma[n-1].
 
275
 * <P>
 
276
 * The singular value decompostion always exists, so the constructor will
 
277
 * never fail.  The matrix condition number and the effective numerical
 
278
 * rank can be computed from this decomposition.
 
279
 */
 
280
class SingularValueDecomposition
 
281
{
 
282
public:
 
283
 
 
284
   /** Construct the singular value decomposition
 
285
   @param A    Rectangular matrix
 
286
   @return     Structure to access U, S and V.
 
287
   */
 
288
 
 
289
    SingularValueDecomposition (const SVDMatrix &mat)
 
290
        {
 
291
        A      = mat;
 
292
        s      = NULL;
 
293
        s_size = 0;
 
294
        calculate();
 
295
        }
 
296
 
 
297
    virtual ~SingularValueDecomposition()
 
298
        {
 
299
        delete[] s;
 
300
        }
 
301
 
 
302
    /**
 
303
     * Return the left singular vectors
 
304
     * @return     U
 
305
     */
 
306
    SVDMatrix &getU();
 
307
 
 
308
    /**
 
309
     * Return the right singular vectors
 
310
     * @return     V
 
311
     */
 
312
    SVDMatrix &getV();
 
313
 
 
314
    /**
 
315
     *  Return the s[index] value
 
316
     */    double getS(unsigned int index);
 
317
 
 
318
    /**
 
319
     * Two norm
 
320
     * @return max(S)
 
321
     */
 
322
    double norm2();
 
323
 
 
324
    /**
 
325
     * Two norm condition number
 
326
     *  @return max(S)/min(S)
 
327
     */
 
328
    double cond();
 
329
 
 
330
    /**
 
331
     *  Effective numerical matrix rank
 
332
     *  @return     Number of nonnegligible singular values.
 
333
     */
 
334
    int rank();
 
335
 
 
336
private:
 
337
 
 
338
      void calculate();
 
339
 
 
340
      SVDMatrix A;
 
341
      SVDMatrix U;
 
342
      double *s;
 
343
      unsigned int s_size;
 
344
      SVDMatrix V;
 
345
 
 
346
};
 
347
 
 
348
 
 
349
static double svd_hypot(double a, double b)
 
350
{
 
351
    double r;
 
352
 
 
353
    if (fabs(a) > fabs(b))
 
354
        {
 
355
        r = b/a;
 
356
        r = fabs(a) * sqrt(1+r*r);
 
357
        }
 
358
    else if (b != 0)
 
359
        {
 
360
        r = a/b;
 
361
        r = fabs(b) * sqrt(1+r*r);
 
362
        }
 
363
    else
 
364
        {
 
365
        r = 0.0;
 
366
        }
 
367
    return r;
 
368
}
 
369
 
 
370
 
 
371
 
 
372
void SingularValueDecomposition::calculate()
 
373
{
 
374
      // Initialize.
 
375
      int m = A.getRows();
 
376
      int n = A.getCols();
 
377
 
 
378
      int nu = (m > n) ? m : n;
 
379
      s_size = (m+1 < n) ? m+1 : n;
 
380
      s = new double[s_size];
 
381
      U = SVDMatrix(m, nu);
 
382
      V = SVDMatrix(n, n);
 
383
      double *e = new double[n];
 
384
      double *work = new double[m];
 
385
      bool wantu = true;
 
386
      bool wantv = true;
 
387
 
 
388
      // Reduce A to bidiagonal form, storing the diagonal elements
 
389
      // in s and the super-diagonal elements in e.
 
390
 
 
391
      int nct = (m-1<n) ? m-1 : n;
 
392
      int nrtx = (n-2<m) ? n-2 : m;
 
393
      int nrt = (nrtx>0) ? nrtx : 0;
 
394
      for (int k = 0; k < 2; k++) {
 
395
         if (k < nct) {
 
396
 
 
397
            // Compute the transformation for the k-th column and
 
398
            // place the k-th diagonal in s[k].
 
399
            // Compute 2-norm of k-th column without under/overflow.
 
400
            s[k] = 0;
 
401
            for (int i = k; i < m; i++) {
 
402
               s[k] = svd_hypot(s[k],A(i, k));
 
403
            }
 
404
            if (s[k] != 0.0) {
 
405
               if (A(k, k) < 0.0) {
 
406
                  s[k] = -s[k];
 
407
               }
 
408
               for (int i = k; i < m; i++) {
 
409
                  A(i, k) /= s[k];
 
410
               }
 
411
               A(k, k) += 1.0;
 
412
            }
 
413
            s[k] = -s[k];
 
414
         }
 
415
         for (int j = k+1; j < n; j++) {
 
416
            if ((k < nct) & (s[k] != 0.0))  {
 
417
 
 
418
            // Apply the transformation.
 
419
 
 
420
               double t = 0;
 
421
               for (int i = k; i < m; i++) {
 
422
                  t += A(i, k) * A(i, j);
 
423
               }
 
424
               t = -t/A(k, k);
 
425
               for (int i = k; i < m; i++) {
 
426
                  A(i, j) += t*A(i, k);
 
427
               }
 
428
            }
 
429
 
 
430
            // Place the k-th row of A into e for the
 
431
            // subsequent calculation of the row transformation.
 
432
 
 
433
            e[j] = A(k, j);
 
434
         }
 
435
         if (wantu & (k < nct)) {
 
436
 
 
437
            // Place the transformation in U for subsequent back
 
438
            // multiplication.
 
439
 
 
440
            for (int i = k; i < m; i++) {
 
441
               U(i, k) = A(i, k);
 
442
            }
 
443
         }
 
444
         if (k < nrt) {
 
445
 
 
446
            // Compute the k-th row transformation and place the
 
447
            // k-th super-diagonal in e[k].
 
448
            // Compute 2-norm without under/overflow.
 
449
            e[k] = 0;
 
450
            for (int i = k+1; i < n; i++) {
 
451
               e[k] = svd_hypot(e[k],e[i]);
 
452
            }
 
453
            if (e[k] != 0.0) {
 
454
               if (e[k+1] < 0.0) {
 
455
                  e[k] = -e[k];
 
456
               }
 
457
               for (int i = k+1; i < n; i++) {
 
458
                  e[i] /= e[k];
 
459
               }
 
460
               e[k+1] += 1.0;
 
461
            }
 
462
            e[k] = -e[k];
 
463
            if ((k+1 < m) & (e[k] != 0.0)) {
 
464
 
 
465
            // Apply the transformation.
 
466
 
 
467
               for (int i = k+1; i < m; i++) {
 
468
                  work[i] = 0.0;
 
469
               }
 
470
               for (int j = k+1; j < n; j++) {
 
471
                  for (int i = k+1; i < m; i++) {
 
472
                     work[i] += e[j]*A(i, j);
 
473
                  }
 
474
               }
 
475
               for (int j = k+1; j < n; j++) {
 
476
                  double t = -e[j]/e[k+1];
 
477
                  for (int i = k+1; i < m; i++) {
 
478
                     A(i, j) += t*work[i];
 
479
                  }
 
480
               }
 
481
            }
 
482
            if (wantv) {
 
483
 
 
484
            // Place the transformation in V for subsequent
 
485
            // back multiplication.
 
486
 
 
487
               for (int i = k+1; i < n; i++) {
 
488
                  V(i, k) = e[i];
 
489
               }
 
490
            }
 
491
         }
 
492
      }
 
493
 
 
494
      // Set up the final bidiagonal matrix or order p.
 
495
 
 
496
      int p = (n < m+1) ? n : m+1;
 
497
      if (nct < n) {
 
498
         s[nct] = A(nct, nct);
 
499
      }
 
500
      if (m < p) {
 
501
         s[p-1] = 0.0;
 
502
      }
 
503
      if (nrt+1 < p) {
 
504
         e[nrt] = A(nrt, p-1);
 
505
      }
 
506
      e[p-1] = 0.0;
 
507
 
 
508
      // If required, generate U.
 
509
 
 
510
      if (wantu) {
 
511
         for (int j = nct; j < nu; j++) {
 
512
            for (int i = 0; i < m; i++) {
 
513
               U(i, j) = 0.0;
 
514
            }
 
515
            U(j, j) = 1.0;
 
516
         }
 
517
         for (int k = nct-1; k >= 0; k--) {
 
518
            if (s[k] != 0.0) {
 
519
               for (int j = k+1; j < nu; j++) {
 
520
                  double t = 0;
 
521
                  for (int i = k; i < m; i++) {
 
522
                     t += U(i, k)*U(i, j);
 
523
                  }
 
524
                  t = -t/U(k, k);
 
525
                  for (int i = k; i < m; i++) {
 
526
                     U(i, j) += t*U(i, k);
 
527
                  }
 
528
               }
 
529
               for (int i = k; i < m; i++ ) {
 
530
                  U(i, k) = -U(i, k);
 
531
               }
 
532
               U(k, k) = 1.0 + U(k, k);
 
533
               for (int i = 0; i < k-1; i++) {
 
534
                  U(i, k) = 0.0;
 
535
               }
 
536
            } else {
 
537
               for (int i = 0; i < m; i++) {
 
538
                  U(i, k) = 0.0;
 
539
               }
 
540
               U(k, k) = 1.0;
 
541
            }
 
542
         }
 
543
      }
 
544
 
 
545
      // If required, generate V.
 
546
 
 
547
      if (wantv) {
 
548
         for (int k = n-1; k >= 0; k--) {
 
549
            if ((k < nrt) & (e[k] != 0.0)) {
 
550
               for (int j = k+1; j < nu; j++) {
 
551
                  double t = 0;
 
552
                  for (int i = k+1; i < n; i++) {
 
553
                     t += V(i, k)*V(i, j);
 
554
                  }
 
555
                  t = -t/V(k+1, k);
 
556
                  for (int i = k+1; i < n; i++) {
 
557
                     V(i, j) += t*V(i, k);
 
558
                  }
 
559
               }
 
560
            }
 
561
            for (int i = 0; i < n; i++) {
 
562
               V(i, k) = 0.0;
 
563
            }
 
564
            V(k, k) = 1.0;
 
565
         }
 
566
      }
 
567
 
 
568
      // Main iteration loop for the singular values.
 
569
 
 
570
      int pp = p-1;
 
571
      int iter = 0;
 
572
      //double eps = pow(2.0,-52.0);
 
573
      //double tiny = pow(2.0,-966.0);
 
574
      //let's just calculate these now
 
575
      //a double can be e � 308.25, so this is safe
 
576
      double eps = 2.22e-16;
 
577
      double tiny = 1.6e-291;
 
578
      while (p > 0) {
 
579
         int k,kase;
 
580
 
 
581
         // Here is where a test for too many iterations would go.
 
582
 
 
583
         // This section of the program inspects for
 
584
         // negligible elements in the s and e arrays.  On
 
585
         // completion the variables kase and k are set as follows.
 
586
 
 
587
         // kase = 1     if s(p) and e[k-1] are negligible and k<p
 
588
         // kase = 2     if s(k) is negligible and k<p
 
589
         // kase = 3     if e[k-1] is negligible, k<p, and
 
590
         //              s(k), ..., s(p) are not negligible (qr step).
 
591
         // kase = 4     if e(p-1) is negligible (convergence).
 
592
 
 
593
         for (k = p-2; k >= -1; k--) {
 
594
            if (k == -1) {
 
595
               break;
 
596
            }
 
597
            if (fabs(e[k]) <=
 
598
                  tiny + eps*(fabs(s[k]) + fabs(s[k+1]))) {
 
599
               e[k] = 0.0;
 
600
               break;
 
601
            }
 
602
         }
 
603
         if (k == p-2) {
 
604
            kase = 4;
 
605
         } else {
 
606
            int ks;
 
607
            for (ks = p-1; ks >= k; ks--) {
 
608
               if (ks == k) {
 
609
                  break;
 
610
               }
 
611
               double t = (ks != p ? fabs(e[ks]) : 0.) +
 
612
                          (ks != k+1 ? fabs(e[ks-1]) : 0.);
 
613
               if (fabs(s[ks]) <= tiny + eps*t)  {
 
614
                  s[ks] = 0.0;
 
615
                  break;
 
616
               }
 
617
            }
 
618
            if (ks == k) {
 
619
               kase = 3;
 
620
            } else if (ks == p-1) {
 
621
               kase = 1;
 
622
            } else {
 
623
               kase = 2;
 
624
               k = ks;
 
625
            }
 
626
         }
 
627
         k++;
 
628
 
 
629
         // Perform the task indicated by kase.
 
630
 
 
631
         switch (kase) {
 
632
 
 
633
            // Deflate negligible s(p).
 
634
 
 
635
            case 1: {
 
636
               double f = e[p-2];
 
637
               e[p-2] = 0.0;
 
638
               for (int j = p-2; j >= k; j--) {
 
639
                  double t = svd_hypot(s[j],f);
 
640
                  double cs = s[j]/t;
 
641
                  double sn = f/t;
 
642
                  s[j] = t;
 
643
                  if (j != k) {
 
644
                     f = -sn*e[j-1];
 
645
                     e[j-1] = cs*e[j-1];
 
646
                  }
 
647
                  if (wantv) {
 
648
                     for (int i = 0; i < n; i++) {
 
649
                        t = cs*V(i, j) + sn*V(i, p-1);
 
650
                        V(i, p-1) = -sn*V(i, j) + cs*V(i, p-1);
 
651
                        V(i, j) = t;
 
652
                     }
 
653
                  }
 
654
               }
 
655
            }
 
656
            break;
 
657
 
 
658
            // Split at negligible s(k).
 
659
 
 
660
            case 2: {
 
661
               double f = e[k-1];
 
662
               e[k-1] = 0.0;
 
663
               for (int j = k; j < p; j++) {
 
664
                  double t = svd_hypot(s[j],f);
 
665
                  double cs = s[j]/t;
 
666
                  double sn = f/t;
 
667
                  s[j] = t;
 
668
                  f = -sn*e[j];
 
669
                  e[j] = cs*e[j];
 
670
                  if (wantu) {
 
671
                     for (int i = 0; i < m; i++) {
 
672
                        t = cs*U(i, j) + sn*U(i, k-1);
 
673
                        U(i, k-1) = -sn*U(i, j) + cs*U(i, k-1);
 
674
                        U(i, j) = t;
 
675
                     }
 
676
                  }
 
677
               }
 
678
            }
 
679
            break;
 
680
 
 
681
            // Perform one qr step.
 
682
 
 
683
            case 3: {
 
684
 
 
685
               // Calculate the shift.
 
686
 
 
687
               double scale = fabs(s[p-1]);
 
688
               double d = fabs(s[p-2]);
 
689
               if (d>scale) scale=d;
 
690
               d = fabs(e[p-2]);
 
691
               if (d>scale) scale=d;
 
692
               d = fabs(s[k]);
 
693
               if (d>scale) scale=d;
 
694
               d = fabs(e[k]);
 
695
               if (d>scale) scale=d;
 
696
               double sp = s[p-1]/scale;
 
697
               double spm1 = s[p-2]/scale;
 
698
               double epm1 = e[p-2]/scale;
 
699
               double sk = s[k]/scale;
 
700
               double ek = e[k]/scale;
 
701
               double b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
 
702
               double c = (sp*epm1)*(sp*epm1);
 
703
               double shift = 0.0;
 
704
               if ((b != 0.0) | (c != 0.0)) {
 
705
                  shift = sqrt(b*b + c);
 
706
                  if (b < 0.0) {
 
707
                     shift = -shift;
 
708
                  }
 
709
                  shift = c/(b + shift);
 
710
               }
 
711
               double f = (sk + sp)*(sk - sp) + shift;
 
712
               double g = sk*ek;
 
713
 
 
714
               // Chase zeros.
 
715
 
 
716
               for (int j = k; j < p-1; j++) {
 
717
                  double t = svd_hypot(f,g);
 
718
                  double cs = f/t;
 
719
                  double sn = g/t;
 
720
                  if (j != k) {
 
721
                     e[j-1] = t;
 
722
                  }
 
723
                  f = cs*s[j] + sn*e[j];
 
724
                  e[j] = cs*e[j] - sn*s[j];
 
725
                  g = sn*s[j+1];
 
726
                  s[j+1] = cs*s[j+1];
 
727
                  if (wantv) {
 
728
                     for (int i = 0; i < n; i++) {
 
729
                        t = cs*V(i, j) + sn*V(i, j+1);
 
730
                        V(i, j+1) = -sn*V(i, j) + cs*V(i, j+1);
 
731
                        V(i, j) = t;
 
732
                     }
 
733
                  }
 
734
                  t = svd_hypot(f,g);
 
735
                  cs = f/t;
 
736
                  sn = g/t;
 
737
                  s[j] = t;
 
738
                  f = cs*e[j] + sn*s[j+1];
 
739
                  s[j+1] = -sn*e[j] + cs*s[j+1];
 
740
                  g = sn*e[j+1];
 
741
                  e[j+1] = cs*e[j+1];
 
742
                  if (wantu && (j < m-1)) {
 
743
                     for (int i = 0; i < m; i++) {
 
744
                        t = cs*U(i, j) + sn*U(i, j+1);
 
745
                        U(i, j+1) = -sn*U(i, j) + cs*U(i, j+1);
 
746
                        U(i, j) = t;
 
747
                     }
 
748
                  }
 
749
               }
 
750
               e[p-2] = f;
 
751
               iter = iter + 1;
 
752
            }
 
753
            break;
 
754
 
 
755
            // Convergence.
 
756
 
 
757
            case 4: {
 
758
 
 
759
               // Make the singular values positive.
 
760
 
 
761
               if (s[k] <= 0.0) {
 
762
                  s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
 
763
                  if (wantv) {
 
764
                     for (int i = 0; i <= pp; i++) {
 
765
                        V(i, k) = -V(i, k);
 
766
                     }
 
767
                  }
 
768
               }
 
769
 
 
770
               // Order the singular values.
 
771
 
 
772
               while (k < pp) {
 
773
                  if (s[k] >= s[k+1]) {
 
774
                     break;
 
775
                  }
 
776
                  double t = s[k];
 
777
                  s[k] = s[k+1];
 
778
                  s[k+1] = t;
 
779
                  if (wantv && (k < n-1)) {
 
780
                     for (int i = 0; i < n; i++) {
 
781
                        t = V(i, k+1); V(i, k+1) = V(i, k); V(i, k) = t;
 
782
                     }
 
783
                  }
 
784
                  if (wantu && (k < m-1)) {
 
785
                     for (int i = 0; i < m; i++) {
 
786
                        t = U(i, k+1); U(i, k+1) = U(i, k); U(i, k) = t;
 
787
                     }
 
788
                  }
 
789
                  k++;
 
790
               }
 
791
               iter = 0;
 
792
               p--;
 
793
            }
 
794
            break;
 
795
         }
 
796
      }
 
797
 
 
798
    delete e;
 
799
    delete work;
 
800
 
 
801
}
 
802
 
 
803
 
 
804
 
 
805
/**
 
806
 * Return the left singular vectors
 
807
 * @return     U
 
808
 */
 
809
SVDMatrix &SingularValueDecomposition::getU()
 
810
{
 
811
    return U;
 
812
}
 
813
 
 
814
/**
 
815
 * Return the right singular vectors
 
816
 * @return     V
 
817
 */
 
818
 
 
819
SVDMatrix &SingularValueDecomposition::getV()
 
820
{
 
821
    return V;
 
822
}
 
823
 
 
824
/**
 
825
 *  Return the s[0] value
 
826
 */
 
827
double SingularValueDecomposition::getS(unsigned int index)
 
828
{
 
829
    if (index >= s_size)
 
830
        return 0.0;
 
831
    return s[index];
 
832
}
 
833
 
 
834
/**
 
835
 * Two norm
 
836
 * @return     max(S)
 
837
 */
 
838
double SingularValueDecomposition::norm2()
 
839
{
 
840
    return s[0];
 
841
}
 
842
 
 
843
/**
 
844
 * Two norm condition number
 
845
 *  @return     max(S)/min(S)
 
846
 */
 
847
 
 
848
double SingularValueDecomposition::cond()
 
849
{
 
850
    return s[0]/s[2];
 
851
}
 
852
 
 
853
/**
 
854
 *  Effective numerical matrix rank
 
855
 *  @return     Number of nonnegligible singular values.
 
856
 */
 
857
int SingularValueDecomposition::rank()
 
858
{
 
859
    double eps = pow(2.0,-52.0);
 
860
    double tol = 3.0*s[0]*eps;
 
861
    int r = 0;
 
862
    for (int i = 0; i < 3; i++)
 
863
        {
 
864
        if (s[i] > tol)
 
865
            r++;
 
866
        }
 
867
    return r;
 
868
}
 
869
 
 
870
//########################################################################
 
871
//# E N D    C L A S S    SingularValueDecomposition
 
872
//########################################################################
 
873
 
 
874
 
 
875
 
 
876
 
 
877
 
 
878
#define pi 3.14159
 
879
//#define pxToCm  0.0275
 
880
#define pxToCm  0.03
 
881
#define piToRad 0.0174532925
 
882
#define docHeightCm 22.86
 
883
 
 
884
 
 
885
//########################################################################
 
886
//# O U T P U T
 
887
//########################################################################
 
888
 
 
889
/**
 
890
 * Get the value of a node/attribute pair
 
891
 */
 
892
static Glib::ustring getAttribute( Inkscape::XML::Node *node, char const *attrName)
 
893
{
 
894
    Glib::ustring val;
 
895
    char const *valstr = node->attribute(attrName);
 
896
    if (valstr)
 
897
        val = valstr;
 
898
    return val;
 
899
}
 
900
 
 
901
 
 
902
 
 
903
/**
 
904
 * Get the extension suffix from the end of a file name
 
905
 */
 
906
static Glib::ustring getExtension(const Glib::ustring &fname)
 
907
{
 
908
    Glib::ustring ext;
 
909
 
 
910
    std::string::size_type pos = fname.rfind('.');
 
911
    if (pos == fname.npos)
 
912
        {
 
913
        ext = "";
 
914
        }
 
915
    else
 
916
        {
 
917
        ext = fname.substr(pos);
 
918
        }
 
919
    return ext;
 
920
}
 
921
 
 
922
 
 
923
static Glib::ustring formatTransform(Geom::Matrix &tf)
 
924
{
 
925
    Glib::ustring str;
 
926
    if (!tf.isIdentity())
 
927
        {
 
928
        StringOutputStream outs;
 
929
        OutputStreamWriter out(outs);
 
930
        out.printf("matrix(%.3f %.3f %.3f %.3f %.3f %.3f)",
 
931
                tf[0], tf[1], tf[2], tf[3], tf[4], tf[5]);
 
932
        str = outs.getString();
 
933
        }
 
934
    return str;
 
935
}
 
936
 
 
937
 
 
938
 
 
939
 
 
940
 
 
941
/**
 
942
 * Get the general transform from SVG pixels to
 
943
 * ODF cm
 
944
 */
 
945
static Geom::Matrix getODFTransform(const SPItem *item)
 
946
{
 
947
    //### Get SVG-to-ODF transform
 
948
    Geom::Matrix tf (sp_item_i2d_affine(item));
 
949
    //Flip Y into document coordinates
 
950
    double doc_height    = sp_document_height(SP_ACTIVE_DOCUMENT);
 
951
    Geom::Matrix doc2dt_tf = Geom::Matrix(Geom::Scale(1.0, -1.0));
 
952
    doc2dt_tf            = doc2dt_tf * Geom::Matrix(Geom::Translate(0, doc_height));
 
953
    tf                   = tf * doc2dt_tf;
 
954
    tf                   = tf * Geom::Matrix(Geom::Scale(pxToCm));
 
955
    return tf;
 
956
}
 
957
 
 
958
 
 
959
 
 
960
 
 
961
/**
 
962
 * Get the bounding box of an item, as mapped onto
 
963
 * an ODF document, in cm.
 
964
 */
 
965
static Geom::OptRect getODFBoundingBox(const SPItem *item)
 
966
{
 
967
    Geom::OptRect bbox_temp = sp_item_bbox_desktop((SPItem *)item);
 
968
    Geom::OptRect bbox;
 
969
    if (bbox_temp) {
 
970
        bbox = *bbox_temp;
 
971
        double doc_height    = sp_document_height(SP_ACTIVE_DOCUMENT);
 
972
        Geom::Matrix doc2dt_tf = Geom::Matrix(Geom::Scale(1.0, -1.0));
 
973
        doc2dt_tf            = doc2dt_tf * Geom::Matrix(Geom::Translate(0, doc_height));
 
974
        bbox                 = *bbox * doc2dt_tf;
 
975
        bbox                 = *bbox * Geom::Matrix(Geom::Scale(pxToCm));
 
976
    }
 
977
    return bbox;
 
978
}
 
979
 
 
980
 
 
981
 
 
982
/**
 
983
 * Get the transform for an item, correcting for
 
984
 * handedness reversal
 
985
 */
 
986
static Geom::Matrix getODFItemTransform(const SPItem *item)
 
987
{
 
988
    Geom::Matrix itemTransform (Geom::Scale(1, -1));
 
989
    itemTransform = itemTransform * (Geom::Matrix)item->transform;
 
990
    itemTransform = itemTransform * Geom::Scale(1, -1);
 
991
    return itemTransform;
 
992
}
 
993
 
 
994
 
 
995
 
 
996
/**
 
997
 * Get some fun facts from the transform
 
998
 */
 
999
static void analyzeTransform(Geom::Matrix &tf,
 
1000
                             double &rotate, double &/*xskew*/, double &/*yskew*/,
 
1001
                             double &xscale, double &yscale)
 
1002
{
 
1003
    SVDMatrix mat(2, 2);
 
1004
    mat(0, 0) = tf[0];
 
1005
    mat(0, 1) = tf[1];
 
1006
    mat(1, 0) = tf[2];
 
1007
    mat(1, 1) = tf[3];
 
1008
 
 
1009
    SingularValueDecomposition svd(mat);
 
1010
 
 
1011
    SVDMatrix U = svd.getU();
 
1012
    SVDMatrix V = svd.getV();
 
1013
    SVDMatrix Vt = V.transpose();
 
1014
    SVDMatrix UVt = U.multiply(Vt);
 
1015
    double s0 = svd.getS(0);
 
1016
    double s1 = svd.getS(1);
 
1017
    xscale = s0;
 
1018
    yscale = s1;
 
1019
    //g_message("## s0:%.3f s1:%.3f", s0, s1);
 
1020
    //g_message("## u:%.3f %.3f %.3f %.3f", U(0,0), U(0,1), U(1,0), U(1,1));
 
1021
    //g_message("## v:%.3f %.3f %.3f %.3f", V(0,0), V(0,1), V(1,0), V(1,1));
 
1022
    //g_message("## vt:%.3f %.3f %.3f %.3f", Vt(0,0), Vt(0,1), Vt(1,0), Vt(1,1));
 
1023
    //g_message("## uvt:%.3f %.3f %.3f %.3f", UVt(0,0), UVt(0,1), UVt(1,0), UVt(1,1));
 
1024
    rotate = UVt(0,0);
 
1025
}
 
1026
 
 
1027
 
 
1028
 
 
1029
static void gatherText(Inkscape::XML::Node *node, Glib::ustring &buf)
 
1030
{
 
1031
    if (node->type() == Inkscape::XML::TEXT_NODE)
 
1032
        {
 
1033
        char *s = (char *)node->content();
 
1034
        if (s)
 
1035
            buf.append(s);
 
1036
        }
 
1037
 
 
1038
    for (Inkscape::XML::Node *child = node->firstChild() ;
 
1039
                child != NULL; child = child->next())
 
1040
        {
 
1041
        gatherText(child, buf);
 
1042
        }
 
1043
 
 
1044
}
 
1045
 
 
1046
/**
 
1047
 * FIRST PASS.
 
1048
 * Method descends into the repr tree, converting image, style, and gradient info
 
1049
 * into forms compatible in ODF.
 
1050
 */
 
1051
void
 
1052
OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node)
 
1053
{
 
1054
 
 
1055
    Glib::ustring nodeName = node->name();
 
1056
    Glib::ustring id       = getAttribute(node, "id");
 
1057
 
 
1058
    //### First, check for metadata
 
1059
    if (nodeName == "metadata" || nodeName == "svg:metadata")
 
1060
        {
 
1061
        Inkscape::XML::Node *mchild = node->firstChild() ;
 
1062
        if (!mchild || strcmp(mchild->name(), "rdf:RDF"))
 
1063
            return;
 
1064
        Inkscape::XML::Node *rchild = mchild->firstChild() ;
 
1065
        if (!rchild || strcmp(rchild->name(), "cc:Work"))
 
1066
            return;
 
1067
        for (Inkscape::XML::Node *cchild = rchild->firstChild() ;
 
1068
            cchild ; cchild = cchild->next())
 
1069
            {
 
1070
            Glib::ustring ccName = cchild->name();
 
1071
            Glib::ustring ccVal;
 
1072
            gatherText(cchild, ccVal);
 
1073
            //g_message("ccName: %s  ccVal:%s", ccName.c_str(), ccVal.c_str());
 
1074
            metadata[ccName] = ccVal;
 
1075
            }
 
1076
        return;
 
1077
        }
 
1078
 
 
1079
    //Now consider items.
 
1080
    SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node);
 
1081
    if (!reprobj)
 
1082
        return;
 
1083
    if (!SP_IS_ITEM(reprobj))
 
1084
        {
 
1085
        return;
 
1086
        }
 
1087
    SPItem *item  = SP_ITEM(reprobj);
 
1088
    //### Get SVG-to-ODF transform
 
1089
    Geom::Matrix tf = getODFTransform(item);
 
1090
 
 
1091
    if (nodeName == "image" || nodeName == "svg:image")
 
1092
        {
 
1093
        //g_message("image");
 
1094
        Glib::ustring href = getAttribute(node, "xlink:href");
 
1095
        if (href.size() > 0)
 
1096
            {
 
1097
            Glib::ustring oldName = href;
 
1098
            Glib::ustring ext = getExtension(oldName);
 
1099
            if (ext == ".jpeg")
 
1100
                ext = ".jpg";
 
1101
            if (imageTable.find(oldName) == imageTable.end())
 
1102
                {
 
1103
                char buf[64];
 
1104
                snprintf(buf, sizeof(buf), "Pictures/image%u%s",
 
1105
                         static_cast<unsigned int>(imageTable.size()), ext.c_str());
 
1106
                Glib::ustring newName = buf;
 
1107
                imageTable[oldName] = newName;
 
1108
                Glib::ustring comment = "old name was: ";
 
1109
                comment.append(oldName);
 
1110
                URI oldUri(oldName);
 
1111
                //g_message("oldpath:%s", oldUri.getNativePath().c_str());
 
1112
                //# if relative to the documentURI, get proper path
 
1113
                URI resUri = documentUri.resolve(oldUri);
 
1114
                DOMString pathName = resUri.getNativePath();
 
1115
                //g_message("native path:%s", pathName.c_str());
 
1116
                ZipEntry *ze = zf.addFile(pathName, comment);
 
1117
                if (ze)
 
1118
                    {
 
1119
                    ze->setFileName(newName);
 
1120
                    }
 
1121
                else
 
1122
                    {
 
1123
                    g_warning("Could not load image file '%s'", pathName.c_str());
 
1124
                    }
 
1125
                }
 
1126
            }
 
1127
        }
 
1128
 
 
1129
    for (Inkscape::XML::Node *child = node->firstChild() ;
 
1130
            child ; child = child->next())
 
1131
        preprocess(zf, child);
 
1132
}
 
1133
 
 
1134
 
 
1135
 
 
1136
/**
 
1137
 * Writes the manifest.  Currently it only changes according to the
 
1138
 * file names of images packed into the zip file.
 
1139
 */
 
1140
bool OdfOutput::writeManifest(ZipFile &zf)
 
1141
{
 
1142
    BufferOutputStream bouts;
 
1143
    OutputStreamWriter outs(bouts);
 
1144
 
 
1145
    time_t tim;
 
1146
    time(&tim);
 
1147
 
 
1148
    outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 
1149
    outs.printf("<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">\n");
 
1150
    outs.printf("\n");
 
1151
    outs.printf("\n");
 
1152
    outs.printf("<!--\n");
 
1153
    outs.printf("*************************************************************************\n");
 
1154
    outs.printf("  file:  manifest.xml\n");
 
1155
    outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
 
1156
    outs.printf("  http://www.inkscape.org\n");
 
1157
    outs.printf("*************************************************************************\n");
 
1158
    outs.printf("-->\n");
 
1159
    outs.printf("\n");
 
1160
    outs.printf("\n");
 
1161
    outs.printf("<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n");
 
1162
    outs.printf("    <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.graphics\" manifest:full-path=\"/\"/>\n");
 
1163
    outs.printf("    <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>\n");
 
1164
    outs.printf("    <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"styles.xml\"/>\n");
 
1165
    outs.printf("    <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>\n");
 
1166
    outs.printf("    <!--List our images here-->\n");
 
1167
    std::map<Glib::ustring, Glib::ustring>::iterator iter;
 
1168
    for (iter = imageTable.begin() ; iter!=imageTable.end() ; iter++)
 
1169
        {
 
1170
        Glib::ustring oldName = iter->first;
 
1171
        Glib::ustring newName = iter->second;
 
1172
 
 
1173
        Glib::ustring ext = getExtension(oldName);
 
1174
        if (ext == ".jpeg")
 
1175
            ext = ".jpg";
 
1176
        outs.printf("    <manifest:file-entry manifest:media-type=\"");
 
1177
        if (ext == ".gif")
 
1178
            outs.printf("image/gif");
 
1179
        else if (ext == ".png")
 
1180
            outs.printf("image/png");
 
1181
        else if (ext == ".jpg")
 
1182
            outs.printf("image/jpeg");
 
1183
        outs.printf("\" manifest:full-path=\"");
 
1184
        outs.printf(newName.c_str());
 
1185
        outs.printf("\"/>\n");
 
1186
        }
 
1187
    outs.printf("</manifest:manifest>\n");
 
1188
 
 
1189
    outs.close();
 
1190
 
 
1191
    //Make our entry
 
1192
    ZipEntry *ze = zf.newEntry("META-INF/manifest.xml", "ODF file manifest");
 
1193
    ze->setUncompressedData(bouts.getBuffer());
 
1194
    ze->finish();
 
1195
 
 
1196
    return true;
 
1197
}
 
1198
 
 
1199
 
 
1200
/**
 
1201
 * This writes the document meta information to meta.xml
 
1202
 */
 
1203
bool OdfOutput::writeMeta(ZipFile &zf)
 
1204
{
 
1205
    BufferOutputStream bouts;
 
1206
    OutputStreamWriter outs(bouts);
 
1207
 
 
1208
    time_t tim;
 
1209
    time(&tim);
 
1210
 
 
1211
    std::map<Glib::ustring, Glib::ustring>::iterator iter;
 
1212
    Glib::ustring creator = "unknown";
 
1213
    iter = metadata.find("dc:creator");
 
1214
    if (iter != metadata.end())
 
1215
        creator = iter->second;
 
1216
    Glib::ustring date = "";
 
1217
    iter = metadata.find("dc:date");
 
1218
    if (iter != metadata.end())
 
1219
        date = iter->second;
 
1220
 
 
1221
    outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 
1222
    outs.printf("\n");
 
1223
    outs.printf("\n");
 
1224
    outs.printf("<!--\n");
 
1225
    outs.printf("*************************************************************************\n");
 
1226
    outs.printf("  file:  meta.xml\n");
 
1227
    outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
 
1228
    outs.printf("  http://www.inkscape.org\n");
 
1229
    outs.printf("*************************************************************************\n");
 
1230
    outs.printf("-->\n");
 
1231
    outs.printf("\n");
 
1232
    outs.printf("\n");
 
1233
    outs.printf("<office:document-meta\n");
 
1234
    outs.printf("xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
 
1235
    outs.printf("xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
 
1236
    outs.printf("xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
 
1237
    outs.printf("xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
 
1238
    outs.printf("xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
 
1239
    outs.printf("xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
 
1240
    outs.printf("xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
 
1241
    outs.printf("xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
 
1242
    outs.printf("office:version=\"1.0\">\n");
 
1243
    outs.printf("<office:meta>\n");
 
1244
    outs.printf("    <meta:generator>Inkscape.org - 0.45</meta:generator>\n");
 
1245
    outs.printf("    <meta:initial-creator>%#s</meta:initial-creator>\n",
 
1246
                                  creator.c_str());
 
1247
    outs.printf("    <meta:creation-date>%#s</meta:creation-date>\n", date.c_str());
 
1248
    for (iter = metadata.begin() ; iter != metadata.end() ; iter++)
 
1249
        {
 
1250
        Glib::ustring name  = iter->first;
 
1251
        Glib::ustring value = iter->second;
 
1252
        if (name.size() > 0 && value.size()>0)
 
1253
            {
 
1254
            outs.printf("    <%#s>%#s</%#s>\n",
 
1255
                      name.c_str(), value.c_str(), name.c_str());
 
1256
            }
 
1257
        }
 
1258
    outs.printf("    <meta:editing-cycles>2</meta:editing-cycles>\n");
 
1259
    outs.printf("    <meta:editing-duration>PT56S</meta:editing-duration>\n");
 
1260
    outs.printf("    <meta:user-defined meta:name=\"Info 1\"/>\n");
 
1261
    outs.printf("    <meta:user-defined meta:name=\"Info 2\"/>\n");
 
1262
    outs.printf("    <meta:user-defined meta:name=\"Info 3\"/>\n");
 
1263
    outs.printf("    <meta:user-defined meta:name=\"Info 4\"/>\n");
 
1264
    outs.printf("    <meta:document-statistic meta:object-count=\"2\"/>\n");
 
1265
    outs.printf("</office:meta>\n");
 
1266
    outs.printf("</office:document-meta>\n");
 
1267
    outs.printf("\n");
 
1268
    outs.printf("\n");
 
1269
 
 
1270
 
 
1271
    outs.close();
 
1272
 
 
1273
    //Make our entry
 
1274
    ZipEntry *ze = zf.newEntry("meta.xml", "ODF info file");
 
1275
    ze->setUncompressedData(bouts.getBuffer());
 
1276
    ze->finish();
 
1277
 
 
1278
    return true;
 
1279
}
 
1280
 
 
1281
 
 
1282
 
 
1283
 
 
1284
/**
 
1285
 * This is called just before writeTree(), since it will write style and
 
1286
 * gradient information above the <draw> tag in the content.xml file
 
1287
 */
 
1288
bool OdfOutput::writeStyle(ZipFile &zf)
 
1289
{
 
1290
    BufferOutputStream bouts;
 
1291
    OutputStreamWriter outs(bouts);
 
1292
 
 
1293
    /*
 
1294
    ==========================================================
 
1295
    Dump our style table.  Styles should have a general layout
 
1296
    something like the following.  Look in:
 
1297
    http://books.evc-cit.info/odbook/ch06.html#draw-style-file-section
 
1298
    for style and gradient information.
 
1299
    <style:style style:name="gr13"
 
1300
      style:family="graphic" style:parent-style-name="standard">
 
1301
        <style:graphic-properties draw:stroke="solid"
 
1302
            svg:stroke-width="0.1cm"
 
1303
            svg:stroke-color="#ff0000"
 
1304
            draw:fill="solid" draw:fill-color="#e6e6ff"/>
 
1305
    </style:style>
 
1306
    ==========================================================
 
1307
    */
 
1308
    outs.printf("<!-- ####### Styles from Inkscape document ####### -->\n");
 
1309
    std::vector<StyleInfo>::iterator iter;
 
1310
    for (iter = styleTable.begin() ; iter != styleTable.end() ; iter++)
 
1311
        {
 
1312
        outs.printf("<style:style style:name=\"%s\"", iter->name.c_str());
 
1313
        StyleInfo s(*iter);
 
1314
        outs.printf(" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
 
1315
        outs.printf("  <style:graphic-properties");
 
1316
        outs.printf(" draw:fill=\"%s\" ", s.fill.c_str());
 
1317
        if (s.fill != "none")
 
1318
            {
 
1319
            outs.printf(" draw:fill-color=\"%s\" ", s.fillColor.c_str());
 
1320
            outs.printf(" draw:fill-opacity=\"%s\" ", s.fillOpacity.c_str());
 
1321
            }
 
1322
        outs.printf(" draw:stroke=\"%s\" ", s.stroke.c_str());
 
1323
        if (s.stroke != "none")
 
1324
            {
 
1325
            outs.printf(" svg:stroke-width=\"%s\" ", s.strokeWidth.c_str());
 
1326
            outs.printf(" svg:stroke-color=\"%s\" ", s.strokeColor.c_str());
 
1327
            outs.printf(" svg:stroke-opacity=\"%s\" ", s.strokeOpacity.c_str());
 
1328
            }
 
1329
        outs.printf("/>\n");
 
1330
        outs.printf("</style:style>\n");
 
1331
        }
 
1332
 
 
1333
    //##  Dump our gradient table
 
1334
    int gradientCount = 0;
 
1335
    outs.printf("\n");
 
1336
    outs.printf("<!-- ####### Gradients from Inkscape document ####### -->\n");
 
1337
    std::vector<GradientInfo>::iterator giter;
 
1338
    for (giter = gradientTable.begin() ; giter != gradientTable.end() ; giter++)
 
1339
        {
 
1340
        GradientInfo gi(*giter);
 
1341
        if (gi.style == "linear")
 
1342
            {
 
1343
            /*
 
1344
            ===================================================================
 
1345
            LINEAR gradient.  We need something that looks like this:
 
1346
            <draw:gradient draw:name="Gradient_20_7"
 
1347
                draw:display-name="Gradient 7"
 
1348
                draw:style="linear"
 
1349
                draw:start-color="#008080" draw:end-color="#993366"
 
1350
                draw:start-intensity="100%" draw:end-intensity="100%"
 
1351
                draw:angle="150" draw:border="0%"/>
 
1352
            ===================================================================
 
1353
            */
 
1354
            if (gi.stops.size() < 2)
 
1355
                {
 
1356
                g_warning("Need at least 2 tops for a linear gradient");
 
1357
                continue;
 
1358
                }
 
1359
            outs.printf("<svg:linearGradient ");
 
1360
            outs.printf("id=\"%#s_g\" ", gi.name.c_str());
 
1361
            outs.printf("draw:name=\"%#s_g\"\n", gi.name.c_str());
 
1362
            outs.printf("    draw:display-name=\"imported linear %u\"\n",
 
1363
                        gradientCount);
 
1364
            outs.printf("    svg:x1=\"%05.3fcm\" svg:y1=\"%05.3fcm\"\n",
 
1365
                        gi.x1, gi.y1);
 
1366
            outs.printf("    svg:x2=\"%05.3fcm\" svg:y2=\"%05.3fcm\"\n",
 
1367
                        gi.x2, gi.y2);
 
1368
            outs.printf("    svg:gradientUnits=\"objectBoundingBox\">\n");
 
1369
            outs.printf("    <svg:stop\n");
 
1370
            outs.printf("        svg:stop-color=\"#%06lx\"\n",
 
1371
                        gi.stops[0].rgb);
 
1372
            outs.printf("        svg:stop-opacity=\"%f%%\"\n",
 
1373
                        gi.stops[0].opacity * 100.0);
 
1374
            outs.printf("        svg:offset=\"0\"/>\n");
 
1375
            outs.printf("    <svg:stop\n");
 
1376
            outs.printf("        svg:stop-color=\"#%06lx\"\n",
 
1377
                        gi.stops[1].rgb);
 
1378
            outs.printf("        svg:stop-opacity=\"%f%%\"\n",
 
1379
                        gi.stops[1].opacity * 100.0);
 
1380
            outs.printf("        svg:offset=\"1\"/>\n");
 
1381
            outs.printf("</svg:linearGradient>\n");
 
1382
            }
 
1383
        else if (gi.style == "radial")
 
1384
            {
 
1385
            /*
 
1386
            ===================================================================
 
1387
            RADIAL gradient.  We need something that looks like this:
 
1388
            <!-- radial gradient, light gray to white, centered, 0% border -->
 
1389
            <draw:gradient draw:name="radial_20_borderless"
 
1390
                draw:display-name="radial borderless"
 
1391
                draw:style="radial"
 
1392
                draw:cx="50%" draw:cy="50%"
 
1393
                draw:start-color="#999999" draw:end-color="#ffffff"
 
1394
                draw:border="0%"/>
 
1395
            ===================================================================
 
1396
            */
 
1397
            if (gi.stops.size() < 2)
 
1398
                {
 
1399
                g_warning("Need at least 2 tops for a radial gradient");
 
1400
                continue;
 
1401
                }
 
1402
            outs.printf("<svg:radialGradient ");
 
1403
            outs.printf("id=\"%#s_g\" ", gi.name.c_str());
 
1404
            outs.printf("draw:name=\"%#s_g\"\n", gi.name.c_str());
 
1405
            outs.printf("    draw:display-name=\"imported radial %d\"\n",
 
1406
                        gradientCount);
 
1407
            outs.printf("    svg:cx=\"%05.3f\" svg:cy=\"%05.3f\"\n",
 
1408
                        gi.cx, gi.cy);
 
1409
            outs.printf("    svg:fx=\"%05.3f\" svg:fy=\"%05.3f\"\n",
 
1410
                        gi.fx, gi.fy);
 
1411
            outs.printf("    svg:r=\"%05.3f\"\n",
 
1412
                        gi.r);
 
1413
            outs.printf("    svg:gradientUnits=\"objectBoundingBox\">\n");
 
1414
            outs.printf("    <svg:stop\n");
 
1415
            outs.printf("        svg:stop-color=\"#%06lx\"\n",
 
1416
                        gi.stops[0].rgb);
 
1417
            outs.printf("        svg:stop-opacity=\"%f%%\"\n",
 
1418
                        gi.stops[0].opacity * 100.0);
 
1419
            outs.printf("        svg:offset=\"0\"/>\n");
 
1420
            outs.printf("    <svg:stop\n");
 
1421
            outs.printf("        svg:stop-color=\"#%06lx\"\n",
 
1422
                        gi.stops[1].rgb);
 
1423
            outs.printf("        svg:stop-opacity=\"%f%%\"\n",
 
1424
                        gi.stops[1].opacity * 100.0);
 
1425
            outs.printf("        svg:offset=\"1\"/>\n");
 
1426
            outs.printf("</svg:radialGradient>\n");
 
1427
            }
 
1428
        else
 
1429
            {
 
1430
            g_warning("unsupported gradient style '%s'", gi.style.c_str());
 
1431
            }
 
1432
        outs.printf("<style:style style:name=\"%#s\" style:family=\"graphic\" ",
 
1433
                  gi.name.c_str());
 
1434
        outs.printf("style:parent-style-name=\"standard\">\n");
 
1435
        outs.printf("    <style:graphic-properties draw:fill=\"gradient\" ");
 
1436
        outs.printf("draw:fill-gradient-name=\"%#s_g\"\n",
 
1437
                  gi.name.c_str());
 
1438
        outs.printf("        draw:textarea-horizontal-align=\"center\" ");
 
1439
        outs.printf("draw:textarea-vertical-align=\"middle\"/>\n");
 
1440
        outs.printf("</style:style>\n\n");
 
1441
 
 
1442
        gradientCount++;
 
1443
        }
 
1444
 
 
1445
    outs.printf("\n");
 
1446
    outs.printf("</office:automatic-styles>\n");
 
1447
    outs.printf("\n");
 
1448
    outs.printf("\n");
 
1449
    outs.printf("<office:master-styles>\n");
 
1450
    outs.printf("<draw:layer-set>\n");
 
1451
    outs.printf("    <draw:layer draw:name=\"layout\"/>\n");
 
1452
    outs.printf("    <draw:layer draw:name=\"background\"/>\n");
 
1453
    outs.printf("    <draw:layer draw:name=\"backgroundobjects\"/>\n");
 
1454
    outs.printf("    <draw:layer draw:name=\"controls\"/>\n");
 
1455
    outs.printf("    <draw:layer draw:name=\"measurelines\"/>\n");
 
1456
    outs.printf("</draw:layer-set>\n");
 
1457
    outs.printf("\n");
 
1458
    outs.printf("<style:master-page style:name=\"Default\"\n");
 
1459
    outs.printf("    style:page-master-name=\"PM1\" draw:style-name=\"dp1\"/>\n");
 
1460
    outs.printf("</office:master-styles>\n");
 
1461
    outs.printf("\n");
 
1462
    outs.printf("\n");
 
1463
    outs.printf("\n");
 
1464
    outs.printf("</office:document-styles>\n");
 
1465
    outs.printf("\n");
 
1466
    outs.printf("<!--\n");
 
1467
    outs.printf("*************************************************************************\n");
 
1468
    outs.printf("  E N D    O F    F I L E\n");
 
1469
    outs.printf("  Have a nice day  - ishmal\n");
 
1470
    outs.printf("*************************************************************************\n");
 
1471
    outs.printf("-->\n");
 
1472
    outs.printf("\n");
 
1473
 
 
1474
    //Make our entry
 
1475
    ZipEntry *ze = zf.newEntry("styles.xml", "ODF style file");
 
1476
    ze->setUncompressedData(bouts.getBuffer());
 
1477
    ze->finish();
 
1478
 
 
1479
    return true;
 
1480
}
 
1481
 
 
1482
 
 
1483
 
 
1484
/**
 
1485
 * Writes an SVG path as an ODF <draw:path> and returns the number of points written
 
1486
 */
 
1487
static int
 
1488
writePath(Writer &outs, Geom::PathVector const &pathv,
 
1489
          Geom::Matrix const &tf, double xoff, double yoff)
 
1490
{
 
1491
    using Geom::X;
 
1492
    using Geom::Y;
 
1493
 
 
1494
    int nrPoints  = 0;
 
1495
 
 
1496
    // convert the path to only lineto's and cubic curveto's:
 
1497
    Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv * tf * Geom::Translate(xoff, yoff) * Geom::Scale(1000.));
 
1498
 
 
1499
        for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
 
1500
 
 
1501
            double destx = pit->initialPoint()[X];
 
1502
            double desty = pit->initialPoint()[Y];
 
1503
            if (fabs(destx)<1.0) destx = 0.0;   // Why is this needed? Shouldn't we just round all numbers then?
 
1504
            if (fabs(desty)<1.0) desty = 0.0;
 
1505
            outs.printf("M %.3f %.3f ", destx, desty);
 
1506
            nrPoints++;
 
1507
 
 
1508
            for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_closed(); ++cit) {
 
1509
 
 
1510
                if( is_straight_curve(*cit) )
 
1511
                {
 
1512
                    double destx = cit->finalPoint()[X];
 
1513
                    double desty = cit->finalPoint()[Y];
 
1514
                    if (fabs(destx)<1.0) destx = 0.0;   // Why is this needed? Shouldn't we just round all numbers then?
 
1515
                    if (fabs(desty)<1.0) desty = 0.0;
 
1516
                    outs.printf("L %.3f %.3f ",  destx, desty);
 
1517
                }
 
1518
                else if(Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) {
 
1519
                    std::vector<Geom::Point> points = cubic->points();
 
1520
                    for (unsigned i = 1; i <= 3; i++) {
 
1521
                        if (fabs(points[i][X])<1.0) points[i][X] = 0.0;   // Why is this needed? Shouldn't we just round all numbers then?
 
1522
                        if (fabs(points[i][Y])<1.0) points[i][Y] = 0.0;
 
1523
                    }
 
1524
                    outs.printf("C %.3f %.3f %.3f %.3f %.3f %.3f ", points[1][X],points[1][Y], points[2][X],points[2][Y], points[3][X],points[3][Y]);
 
1525
                }
 
1526
                else {
 
1527
                    g_error ("logical error, because pathv_to_linear_and_cubic_beziers was used");
 
1528
                }
 
1529
 
 
1530
                nrPoints++;
 
1531
            }
 
1532
 
 
1533
            if (pit->closed()) {
 
1534
                outs.printf("Z");
 
1535
            }
 
1536
        }
 
1537
 
 
1538
    return nrPoints;
 
1539
}
 
1540
 
 
1541
 
 
1542
 
 
1543
bool OdfOutput::processStyle(Writer &outs, SPItem *item,
 
1544
                             const Glib::ustring &id)
 
1545
{
 
1546
    SPStyle *style = item->style;
 
1547
 
 
1548
    StyleInfo si;
 
1549
 
 
1550
    //## FILL
 
1551
    if (style->fill.isColor())
 
1552
        {
 
1553
        guint32 fillCol = style->fill.value.color.toRGBA32( 0 );
 
1554
        char buf[16];
 
1555
        int r = (fillCol >> 24) & 0xff;
 
1556
        int g = (fillCol >> 16) & 0xff;
 
1557
        int b = (fillCol >>  8) & 0xff;
 
1558
        //g_message("## %s %lx", id.c_str(), (unsigned int)fillCol);
 
1559
        snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
 
1560
        si.fillColor = buf;
 
1561
        si.fill      = "solid";
 
1562
        double opacityPercent = 100.0 *
 
1563
             (SP_SCALE24_TO_FLOAT(style->fill_opacity.value));
 
1564
        snprintf(buf, 15, "%.3f%%", opacityPercent);
 
1565
        si.fillOpacity = buf;
 
1566
        }
 
1567
 
 
1568
    //## STROKE
 
1569
    if (style->stroke.isColor())
 
1570
        {
 
1571
        guint32 strokeCol = style->stroke.value.color.toRGBA32( 0 );
 
1572
        char buf[16];
 
1573
        int r = (strokeCol >> 24) & 0xff;
 
1574
        int g = (strokeCol >> 16) & 0xff;
 
1575
        int b = (strokeCol >>  8) & 0xff;
 
1576
        snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
 
1577
        si.strokeColor = buf;
 
1578
        snprintf(buf, 15, "%.3fpt", style->stroke_width.value);
 
1579
        si.strokeWidth = buf;
 
1580
        si.stroke      = "solid";
 
1581
        double opacityPercent = 100.0 *
 
1582
             (SP_SCALE24_TO_FLOAT(style->stroke_opacity.value));
 
1583
        snprintf(buf, 15, "%.3f%%", opacityPercent);
 
1584
        si.strokeOpacity = buf;
 
1585
        }
 
1586
 
 
1587
    //Look for existing identical style;
 
1588
    bool styleMatch = false;
 
1589
    std::vector<StyleInfo>::iterator iter;
 
1590
    for (iter=styleTable.begin() ; iter!=styleTable.end() ; iter++)
 
1591
        {
 
1592
        if (si.equals(*iter))
 
1593
            {
 
1594
            //map to existing styleTable entry
 
1595
            Glib::ustring styleName = iter->name;
 
1596
            //g_message("found duplicate style:%s", styleName.c_str());
 
1597
            styleLookupTable[id] = styleName;
 
1598
            styleMatch = true;
 
1599
            break;
 
1600
            }
 
1601
        }
 
1602
 
 
1603
    //## Dont need a new style
 
1604
    if (styleMatch)
 
1605
        return false;
 
1606
 
 
1607
    char buf[16];
 
1608
    snprintf(buf, 15, "style%d", (int)styleTable.size());
 
1609
    Glib::ustring styleName = buf;
 
1610
    si.name = styleName;
 
1611
    styleTable.push_back(si);
 
1612
    styleLookupTable[id] = styleName;
 
1613
 
 
1614
    outs.printf("<style:style style:name=\"%s\"", si.name.c_str());
 
1615
    outs.printf(" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
 
1616
    outs.printf("  <style:graphic-properties");
 
1617
    outs.printf(" draw:fill=\"%s\" ", si.fill.c_str());
 
1618
    if (si.fill != "none")
 
1619
        {
 
1620
        outs.printf(" draw:fill-color=\"%s\" ", si.fillColor.c_str());
 
1621
        outs.printf(" draw:fill-opacity=\"%s\" ", si.fillOpacity.c_str());
 
1622
        }
 
1623
    outs.printf(" draw:stroke=\"%s\" ", si.stroke.c_str());
 
1624
    if (si.stroke != "none")
 
1625
        {
 
1626
        outs.printf(" svg:stroke-width=\"%s\" ", si.strokeWidth.c_str());
 
1627
        outs.printf(" svg:stroke-color=\"%s\" ", si.strokeColor.c_str());
 
1628
        outs.printf(" svg:stroke-opacity=\"%s\" ", si.strokeOpacity.c_str());
 
1629
        }
 
1630
    outs.printf("/>\n");
 
1631
    outs.printf("</style:style>\n");
 
1632
 
 
1633
    return true;
 
1634
}
 
1635
 
 
1636
 
 
1637
 
 
1638
 
 
1639
bool OdfOutput::processGradient(Writer &outs, SPItem *item,
 
1640
                                const Glib::ustring &id, Geom::Matrix &/*tf*/)
 
1641
{
 
1642
    if (!item)
 
1643
        return false;
 
1644
 
 
1645
    SPStyle *style = item->style;
 
1646
 
 
1647
    if (!style)
 
1648
        return false;
 
1649
 
 
1650
    if (!style->fill.isPaintserver())
 
1651
        return false;
 
1652
 
 
1653
    //## Gradient.  Look in writeStyle() below to see what info
 
1654
    //   we need to read into GradientInfo.
 
1655
    if (!SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)))
 
1656
        return false;
 
1657
 
 
1658
    SPGradient *gradient = SP_GRADIENT(SP_STYLE_FILL_SERVER(style));
 
1659
 
 
1660
    GradientInfo gi;
 
1661
 
 
1662
    SPGradient *grvec = sp_gradient_get_vector(gradient, FALSE);
 
1663
    for (SPStop *stop = sp_first_stop(grvec) ;
 
1664
          stop ; stop = sp_next_stop(stop))
 
1665
        {
 
1666
        unsigned long rgba = sp_stop_get_rgba32(stop);
 
1667
        unsigned long rgb  = (rgba >> 8) & 0xffffff;
 
1668
        double opacity     = ((double)(rgba & 0xff)) / 256.0;
 
1669
        GradientStop gs(rgb, opacity);
 
1670
        gi.stops.push_back(gs);
 
1671
        }
 
1672
 
 
1673
    if (SP_IS_LINEARGRADIENT(gradient))
 
1674
        {
 
1675
        gi.style = "linear";
 
1676
        SPLinearGradient *linGrad = SP_LINEARGRADIENT(gradient);
 
1677
        /*
 
1678
        Geom::Point p1(linGrad->x1.value, linGrad->y1.value);
 
1679
        p1 = p1 * tf;
 
1680
        gi.x1 = p1[Geom::X];
 
1681
        gi.y1 = p1[Geom::Y];
 
1682
        Geom::Point p2(linGrad->x2.value, linGrad->y2.value);
 
1683
        p2 = p2 * tf;
 
1684
        gi.x2 = p2[Geom::X];
 
1685
        gi.y2 = p2[Geom::Y];
 
1686
        */
 
1687
        gi.x1 = linGrad->x1.value;
 
1688
        gi.y1 = linGrad->y1.value;
 
1689
        gi.x2 = linGrad->x2.value;
 
1690
        gi.y2 = linGrad->y2.value;
 
1691
        }
 
1692
    else if (SP_IS_RADIALGRADIENT(gradient))
 
1693
        {
 
1694
        gi.style = "radial";
 
1695
        SPRadialGradient *radGrad = SP_RADIALGRADIENT(gradient);
 
1696
        gi.cx = radGrad->cx.computed * 100.0;//ODG cx is percentages
 
1697
        gi.cy = radGrad->cy.computed * 100.0;
 
1698
        }
 
1699
    else
 
1700
        {
 
1701
        g_warning("not a supported gradient type");
 
1702
        return false;
 
1703
        }
 
1704
 
 
1705
    //Look for existing identical style;
 
1706
    bool gradientMatch = false;
 
1707
    std::vector<GradientInfo>::iterator iter;
 
1708
    for (iter=gradientTable.begin() ; iter!=gradientTable.end() ; iter++)
 
1709
        {
 
1710
        if (gi.equals(*iter))
 
1711
            {
 
1712
            //map to existing gradientTable entry
 
1713
            Glib::ustring gradientName = iter->name;
 
1714
            //g_message("found duplicate style:%s", gradientName.c_str());
 
1715
            gradientLookupTable[id] = gradientName;
 
1716
            gradientMatch = true;
 
1717
            break;
 
1718
            }
 
1719
        }
 
1720
 
 
1721
    if (gradientMatch)
 
1722
        return true;
 
1723
 
 
1724
    //## No match, let us write a new entry
 
1725
    char buf[16];
 
1726
    snprintf(buf, 15, "gradient%d", (int)gradientTable.size());
 
1727
    Glib::ustring gradientName = buf;
 
1728
    gi.name = gradientName;
 
1729
    gradientTable.push_back(gi);
 
1730
    gradientLookupTable[id] = gradientName;
 
1731
 
 
1732
    int gradientCount = gradientTable.size();
 
1733
 
 
1734
    if (gi.style == "linear")
 
1735
        {
 
1736
        /*
 
1737
        ===================================================================
 
1738
        LINEAR gradient.  We need something that looks like this:
 
1739
        <draw:gradient draw:name="Gradient_20_7"
 
1740
            draw:display-name="Gradient 7"
 
1741
            draw:style="linear"
 
1742
            draw:start-color="#008080" draw:end-color="#993366"
 
1743
            draw:start-intensity="100%" draw:end-intensity="100%"
 
1744
            draw:angle="150" draw:border="0%"/>
 
1745
        ===================================================================
 
1746
        */
 
1747
        if (gi.stops.size() < 2)
 
1748
            {
 
1749
            g_warning("Need at least 2 stops for a linear gradient");
 
1750
            return false;;
 
1751
            }
 
1752
        outs.printf("<svg:linearGradient ");
 
1753
        outs.printf("id=\"%#s_g\" ", gi.name.c_str());
 
1754
        outs.printf("draw:name=\"%#s_g\"\n", gi.name.c_str());
 
1755
        outs.printf("    draw:display-name=\"imported linear %d\"\n",
 
1756
                    gradientCount);
 
1757
        outs.printf("    svg:gradientUnits=\"objectBoundingBox\"\n");
 
1758
        outs.printf("    svg:x1=\"%05.3fcm\" svg:y1=\"%05.3fcm\"\n",
 
1759
                    gi.x1 * pxToCm, gi.y1 * pxToCm);
 
1760
        outs.printf("    svg:x2=\"%05.3fcm\" svg:y2=\"%05.3fcm\">\n",
 
1761
                    gi.x2 * pxToCm, gi.y2 * pxToCm);
 
1762
        outs.printf("    <svg:stop\n");
 
1763
        outs.printf("        svg:stop-color=\"#%06lx\"\n",
 
1764
                    gi.stops[0].rgb);
 
1765
        outs.printf("        svg:stop-opacity=\"%f%%\"\n",
 
1766
                    gi.stops[0].opacity * 100.0);
 
1767
        outs.printf("        svg:offset=\"0\"/>\n");
 
1768
        outs.printf("    <svg:stop\n");
 
1769
        outs.printf("        svg:stop-color=\"#%06lx\"\n",
 
1770
                    gi.stops[1].rgb);
 
1771
        outs.printf("        svg:stop-opacity=\"%f%%\"\n",
 
1772
                    gi.stops[1].opacity * 100.0);
 
1773
        outs.printf("        svg:offset=\"1\"/>\n");
 
1774
        outs.printf("</svg:linearGradient>\n");
 
1775
        }
 
1776
    else if (gi.style == "radial")
 
1777
        {
 
1778
        /*
 
1779
        ===================================================================
 
1780
        RADIAL gradient.  We need something that looks like this:
 
1781
        <!-- radial gradient, light gray to white, centered, 0% border -->
 
1782
        <draw:gradient draw:name="radial_20_borderless"
 
1783
            draw:display-name="radial borderless"
 
1784
            draw:style="radial"
 
1785
            draw:cx="50%" draw:cy="50%"
 
1786
            draw:start-color="#999999" draw:end-color="#ffffff"
 
1787
            draw:border="0%"/>
 
1788
        ===================================================================
 
1789
        */
 
1790
        if (gi.stops.size() < 2)
 
1791
            {
 
1792
            g_warning("Need at least 2 stops for a radial gradient");
 
1793
            return false;
 
1794
            }
 
1795
        outs.printf("<svg:radialGradient ");
 
1796
        outs.printf("id=\"%#s_g\" ", gi.name.c_str());
 
1797
        outs.printf("draw:name=\"%#s_g\"\n", gi.name.c_str());
 
1798
        outs.printf("    draw:display-name=\"imported radial %d\"\n",
 
1799
                    gradientCount);
 
1800
        outs.printf("    svg:gradientUnits=\"objectBoundingBox\"\n");
 
1801
        outs.printf("    svg:cx=\"%05.3f\" svg:cy=\"%05.3f\"\n",
 
1802
                    gi.cx, gi.cy);
 
1803
        outs.printf("    svg:fx=\"%05.3f\" svg:fy=\"%05.3f\"\n",
 
1804
                    gi.fx, gi.fy);
 
1805
        outs.printf("    svg:r=\"%05.3f\">\n",
 
1806
                    gi.r);
 
1807
        outs.printf("    <svg:stop\n");
 
1808
        outs.printf("        svg:stop-color=\"#%06lx\"\n",
 
1809
                    gi.stops[0].rgb);
 
1810
        outs.printf("        svg:stop-opacity=\"%f%%\"\n",
 
1811
                    gi.stops[0].opacity * 100.0);
 
1812
        outs.printf("        svg:offset=\"0\"/>\n");
 
1813
        outs.printf("    <svg:stop\n");
 
1814
        outs.printf("        svg:stop-color=\"#%06lx\"\n",
 
1815
                    gi.stops[1].rgb);
 
1816
        outs.printf("        svg:stop-opacity=\"%f%%\"\n",
 
1817
                    gi.stops[1].opacity * 100.0);
 
1818
        outs.printf("        svg:offset=\"1\"/>\n");
 
1819
        outs.printf("</svg:radialGradient>\n");
 
1820
        }
 
1821
    else
 
1822
        {
 
1823
        g_warning("unsupported gradient style '%s'", gi.style.c_str());
 
1824
        return false;
 
1825
        }
 
1826
    outs.printf("<style:style style:name=\"%#s\" style:family=\"graphic\" ",
 
1827
              gi.name.c_str());
 
1828
    outs.printf("style:parent-style-name=\"standard\">\n");
 
1829
    outs.printf("    <style:graphic-properties draw:fill=\"gradient\" ");
 
1830
    outs.printf("draw:fill-gradient-name=\"%#s_g\"\n",
 
1831
              gi.name.c_str());
 
1832
    outs.printf("        draw:textarea-horizontal-align=\"center\" ");
 
1833
    outs.printf("draw:textarea-vertical-align=\"middle\"/>\n");
 
1834
    outs.printf("</style:style>\n\n");
 
1835
 
 
1836
    return true;
 
1837
}
 
1838
 
 
1839
 
 
1840
 
 
1841
 
 
1842
/**
 
1843
 * SECOND PASS.
 
1844
 * This is the main SPObject tree output to ODF.  preprocess()
 
1845
 * must be called prior to this, as elements will often reference
 
1846
 * data parsed and tabled in preprocess().
 
1847
 */
 
1848
bool OdfOutput::writeTree(Writer &couts, Writer &souts,
 
1849
                          Inkscape::XML::Node *node)
 
1850
{
 
1851
    //# Get the SPItem, if applicable
 
1852
    SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node);
 
1853
    if (!reprobj)
 
1854
        return true;
 
1855
    if (!SP_IS_ITEM(reprobj))
 
1856
        {
 
1857
        return true;
 
1858
        }
 
1859
    SPItem *item = SP_ITEM(reprobj);
 
1860
 
 
1861
 
 
1862
    Glib::ustring nodeName = node->name();
 
1863
    Glib::ustring id       = getAttribute(node, "id");
 
1864
 
 
1865
    //### Get SVG-to-ODF transform
 
1866
    Geom::Matrix tf        = getODFTransform(item);
 
1867
 
 
1868
    //### Get ODF bounding box params for item
 
1869
    Geom::OptRect bbox = getODFBoundingBox(item);
 
1870
    if (!bbox) {
 
1871
        return true;
 
1872
    }
 
1873
 
 
1874
    double bbox_x        = bbox->min()[Geom::X];
 
1875
    double bbox_y        = bbox->min()[Geom::Y];
 
1876
    double bbox_width    = (*bbox)[Geom::X].extent();
 
1877
    double bbox_height   = (*bbox)[Geom::Y].extent();
 
1878
 
 
1879
    double rotate;
 
1880
    double xskew;
 
1881
    double yskew;
 
1882
    double xscale;
 
1883
    double yscale;
 
1884
    analyzeTransform(tf, rotate, xskew, yskew, xscale, yscale);
 
1885
 
 
1886
    //# Do our stuff
 
1887
    SPCurve *curve = NULL;
 
1888
 
 
1889
 
 
1890
 
 
1891
    if (nodeName == "svg" || nodeName == "svg:svg")
 
1892
        {
 
1893
        //# Iterate through the children
 
1894
        for (Inkscape::XML::Node *child = node->firstChild() ;
 
1895
               child ; child = child->next())
 
1896
            {
 
1897
            if (!writeTree(couts, souts, child))
 
1898
                return false;
 
1899
            }
 
1900
        return true;
 
1901
        }
 
1902
    else if (nodeName == "g" || nodeName == "svg:g")
 
1903
        {
 
1904
        if (id.size() > 0)
 
1905
            couts.printf("<draw:g id=\"%s\">\n", id.c_str());
 
1906
        else
 
1907
            couts.printf("<draw:g>\n");
 
1908
        //# Iterate through the children
 
1909
        for (Inkscape::XML::Node *child = node->firstChild() ;
 
1910
               child ; child = child->next())
 
1911
            {
 
1912
            if (!writeTree(couts, souts, child))
 
1913
                return false;
 
1914
            }
 
1915
        if (id.size() > 0)
 
1916
            couts.printf("</draw:g> <!-- id=\"%s\" -->\n", id.c_str());
 
1917
        else
 
1918
            couts.printf("</draw:g>\n");
 
1919
        return true;
 
1920
        }
 
1921
 
 
1922
    //######################################
 
1923
    //# S T Y L E
 
1924
    //######################################
 
1925
    processStyle(souts, item, id);
 
1926
 
 
1927
    //######################################
 
1928
    //# G R A D I E N T
 
1929
    //######################################
 
1930
    processGradient(souts, item, id, tf);
 
1931
 
 
1932
 
 
1933
 
 
1934
 
 
1935
    //######################################
 
1936
    //# I T E M    D A T A
 
1937
    //######################################
 
1938
    //g_message("##### %s #####", nodeName.c_str());
 
1939
    if (nodeName == "image" || nodeName == "svg:image")
 
1940
        {
 
1941
        if (!SP_IS_IMAGE(item))
 
1942
            {
 
1943
            g_warning("<image> is not an SPImage.  Why?  ;-)");
 
1944
            return false;
 
1945
            }
 
1946
 
 
1947
        SPImage *img   = SP_IMAGE(item);
 
1948
        double ix      = img->x.value;
 
1949
        double iy      = img->y.value;
 
1950
        double iwidth  = img->width.value;
 
1951
        double iheight = img->height.value;
 
1952
 
 
1953
        Geom::Rect ibbox(Geom::Point(ix, iy), Geom::Point(ix+iwidth, iy+iheight));
 
1954
        ibbox = ibbox * tf;
 
1955
        ix      = ibbox.min()[Geom::X];
 
1956
        iy      = ibbox.min()[Geom::Y];
 
1957
        //iwidth  = ibbox.max()[Geom::X] - ibbox.min()[Geom::X];
 
1958
        //iheight = ibbox.max()[Geom::Y] - ibbox.min()[Geom::Y];
 
1959
        iwidth  = xscale * iwidth;
 
1960
        iheight = yscale * iheight;
 
1961
 
 
1962
        Geom::Matrix itemTransform = getODFItemTransform(item);
 
1963
 
 
1964
        Glib::ustring itemTransformString = formatTransform(itemTransform);
 
1965
 
 
1966
        Glib::ustring href = getAttribute(node, "xlink:href");
 
1967
        std::map<Glib::ustring, Glib::ustring>::iterator iter = imageTable.find(href);
 
1968
        if (iter == imageTable.end())
 
1969
            {
 
1970
            g_warning("image '%s' not in table", href.c_str());
 
1971
            return false;
 
1972
            }
 
1973
        Glib::ustring newName = iter->second;
 
1974
 
 
1975
        couts.printf("<draw:frame ");
 
1976
        if (id.size() > 0)
 
1977
            couts.printf("id=\"%s\" ", id.c_str());
 
1978
        couts.printf("draw:style-name=\"gr1\" draw:text-style-name=\"P1\" draw:layer=\"layout\" ");
 
1979
        //no x or y.  make them the translate transform, last one
 
1980
        couts.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
 
1981
                                  iwidth, iheight);
 
1982
        if (itemTransformString.size() > 0)
 
1983
            {
 
1984
            couts.printf("draw:transform=\"%s translate(%.3fcm, %.3fcm)\" ",
 
1985
                           itemTransformString.c_str(), ix, iy);
 
1986
            }
 
1987
        else
 
1988
            {
 
1989
            couts.printf("draw:transform=\"translate(%.3fcm, %.3fcm)\" ",
 
1990
                                ix, iy);
 
1991
            }
 
1992
 
 
1993
        couts.printf(">\n");
 
1994
        couts.printf("    <draw:image xlink:href=\"%s\" xlink:type=\"simple\"\n",
 
1995
                              newName.c_str());
 
1996
        couts.printf("        xlink:show=\"embed\" xlink:actuate=\"onLoad\">\n");
 
1997
        couts.printf("        <text:p/>\n");
 
1998
        couts.printf("    </draw:image>\n");
 
1999
        couts.printf("</draw:frame>\n");
 
2000
        return true;
 
2001
        }
 
2002
    else if (SP_IS_SHAPE(item))
 
2003
        {
 
2004
        //g_message("### %s is a shape", nodeName.c_str());
 
2005
        curve = sp_shape_get_curve(SP_SHAPE(item));
 
2006
        }
 
2007
    else if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))
 
2008
        {
 
2009
        curve = te_get_layout(item)->convertToCurves();
 
2010
        }
 
2011
 
 
2012
    if (curve)
 
2013
        {
 
2014
        //### Default <path> output
 
2015
 
 
2016
        couts.printf("<draw:path ");
 
2017
        if (id.size()>0)
 
2018
            couts.printf("id=\"%s\" ", id.c_str());
 
2019
 
 
2020
        std::map<Glib::ustring, Glib::ustring>::iterator siter;
 
2021
        siter = styleLookupTable.find(id);
 
2022
        if (siter != styleLookupTable.end())
 
2023
            {
 
2024
            Glib::ustring styleName = siter->second;
 
2025
            couts.printf("draw:style-name=\"%s\" ", styleName.c_str());
 
2026
            }
 
2027
 
 
2028
        std::map<Glib::ustring, Glib::ustring>::iterator giter;
 
2029
        giter = gradientLookupTable.find(id);
 
2030
        if (giter != gradientLookupTable.end())
 
2031
            {
 
2032
            Glib::ustring gradientName = giter->second;
 
2033
            couts.printf("draw:fill-gradient-name=\"%s\" ",
 
2034
                 gradientName.c_str());
 
2035
            }
 
2036
 
 
2037
        couts.printf("draw:layer=\"layout\" svg:x=\"%.3fcm\" svg:y=\"%.3fcm\" ",
 
2038
                       bbox_x, bbox_y);
 
2039
        couts.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
 
2040
                       bbox_width, bbox_height);
 
2041
        couts.printf("svg:viewBox=\"0.0 0.0 %.3f %.3f\"\n",
 
2042
                       bbox_width * 1000.0, bbox_height * 1000.0);
 
2043
 
 
2044
        couts.printf("    svg:d=\"");
 
2045
        int nrPoints = writePath(couts, curve->get_pathvector(),
 
2046
                             tf, bbox_x, bbox_y);
 
2047
        couts.printf("\"");
 
2048
 
 
2049
        couts.printf(">\n");
 
2050
        couts.printf("    <!-- %d nodes -->\n", nrPoints);
 
2051
        couts.printf("</draw:path>\n\n");
 
2052
 
 
2053
 
 
2054
        curve->unref();
 
2055
        }
 
2056
 
 
2057
    return true;
 
2058
}
 
2059
 
 
2060
 
 
2061
 
 
2062
/**
 
2063
 * Write the header for the content.xml file
 
2064
 */
 
2065
bool OdfOutput::writeStyleHeader(Writer &outs)
 
2066
{
 
2067
    time_t tim;
 
2068
    time(&tim);
 
2069
 
 
2070
    outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 
2071
    outs.printf("\n");
 
2072
    outs.printf("\n");
 
2073
    outs.printf("<!--\n");
 
2074
    outs.printf("*************************************************************************\n");
 
2075
    outs.printf("  file:  styles.xml\n");
 
2076
    outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
 
2077
    outs.printf("  http://www.inkscape.org\n");
 
2078
    outs.printf("*************************************************************************\n");
 
2079
    outs.printf("-->\n");
 
2080
    outs.printf("\n");
 
2081
    outs.printf("\n");
 
2082
    outs.printf("<office:document-styles\n");
 
2083
    outs.printf("    xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
 
2084
    outs.printf("    xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");
 
2085
    outs.printf("    xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");
 
2086
    outs.printf("    xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");
 
2087
    outs.printf("    xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");
 
2088
    outs.printf("    xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");
 
2089
    outs.printf("    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
 
2090
    outs.printf("    xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
 
2091
    outs.printf("    xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
 
2092
    outs.printf("    xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");
 
2093
    outs.printf("    xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
 
2094
    outs.printf("    xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");
 
2095
    outs.printf("    xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");
 
2096
    outs.printf("    xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");
 
2097
    outs.printf("    xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");
 
2098
    outs.printf("    xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");
 
2099
    outs.printf("    xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");
 
2100
    outs.printf("    xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
 
2101
    outs.printf("    xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");
 
2102
    outs.printf("    xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");
 
2103
    outs.printf("    xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");
 
2104
    outs.printf("    xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");
 
2105
    outs.printf("    xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
 
2106
    outs.printf("    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
 
2107
    outs.printf("    xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
 
2108
    outs.printf("    xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
 
2109
    outs.printf("    office:version=\"1.0\">\n");
 
2110
    outs.printf("\n");
 
2111
    outs.printf("\n");
 
2112
    outs.printf("<!--\n");
 
2113
    outs.printf("*************************************************************************\n");
 
2114
    outs.printf("  S T Y L E S\n");
 
2115
    outs.printf("  Style entries have been pulled from the svg style and\n");
 
2116
    outs.printf("  representation attributes in the SVG tree.  The tree elements\n");
 
2117
    outs.printf("  then refer to them by name, in the ODF manner\n");
 
2118
    outs.printf("*************************************************************************\n");
 
2119
    outs.printf("-->\n");
 
2120
    outs.printf("\n");
 
2121
    outs.printf("<office:styles>\n");
 
2122
    outs.printf("\n");
 
2123
 
 
2124
    return true;
 
2125
}
 
2126
 
 
2127
 
 
2128
/**
 
2129
 * Write the footer for the style.xml file
 
2130
 */
 
2131
bool OdfOutput::writeStyleFooter(Writer &outs)
 
2132
{
 
2133
    outs.printf("\n");
 
2134
    outs.printf("</office:styles>\n");
 
2135
    outs.printf("\n");
 
2136
    outs.printf("\n");
 
2137
    outs.printf("<office:automatic-styles>\n");
 
2138
    outs.printf("<!-- ####### 'Standard' styles ####### -->\n");
 
2139
    outs.printf("<style:style style:name=\"dp1\" style:family=\"drawing-page\"/>\n");
 
2140
    outs.printf("<style:style style:name=\"gr1\" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
 
2141
    outs.printf("  <style:graphic-properties draw:stroke=\"none\" draw:fill=\"none\"\n");
 
2142
    outs.printf("       draw:textarea-horizontal-align=\"center\"\n");
 
2143
    outs.printf("       draw:textarea-vertical-align=\"middle\" draw:color-mode=\"standard\"\n");
 
2144
    outs.printf("       draw:luminance=\"0%%\" draw:contrast=\"0%%\" draw:gamma=\"100%%\" draw:red=\"0%%\"\n");
 
2145
    outs.printf("       draw:green=\"0%%\" draw:blue=\"0%%\" fo:clip=\"rect(0cm 0cm 0cm 0cm)\"\n");
 
2146
    outs.printf("       draw:image-opacity=\"100%%\" style:mirror=\"none\"/>\n");
 
2147
    outs.printf("</style:style>\n");
 
2148
    outs.printf("<style:style style:name=\"P1\" style:family=\"paragraph\">\n");
 
2149
    outs.printf("  <style:paragraph-properties fo:text-align=\"center\"/>\n");
 
2150
    outs.printf("</style:style>\n");
 
2151
    outs.printf("</office:automatic-styles>\n");
 
2152
    outs.printf("\n");
 
2153
    outs.printf("\n");
 
2154
    outs.printf("<office:master-styles>\n");
 
2155
    outs.printf("<draw:layer-set>\n");
 
2156
    outs.printf("    <draw:layer draw:name=\"layout\"/>\n");
 
2157
    outs.printf("    <draw:layer draw:name=\"background\"/>\n");
 
2158
    outs.printf("    <draw:layer draw:name=\"backgroundobjects\"/>\n");
 
2159
    outs.printf("    <draw:layer draw:name=\"controls\"/>\n");
 
2160
    outs.printf("    <draw:layer draw:name=\"measurelines\"/>\n");
 
2161
    outs.printf("</draw:layer-set>\n");
 
2162
    outs.printf("\n");
 
2163
    outs.printf("<style:master-page style:name=\"Default\"\n");
 
2164
    outs.printf("    style:page-master-name=\"PM1\" draw:style-name=\"dp1\"/>\n");
 
2165
    outs.printf("</office:master-styles>\n");
 
2166
    outs.printf("\n");
 
2167
    outs.printf("\n");
 
2168
    outs.printf("\n");
 
2169
    outs.printf("</office:document-styles>\n");
 
2170
    outs.printf("\n");
 
2171
    outs.printf("<!--\n");
 
2172
    outs.printf("*************************************************************************\n");
 
2173
    outs.printf("  E N D    O F    F I L E\n");
 
2174
    outs.printf("  Have a nice day  - ishmal\n");
 
2175
    outs.printf("*************************************************************************\n");
 
2176
    outs.printf("-->\n");
 
2177
    outs.printf("\n");
 
2178
 
 
2179
    return true;
 
2180
}
 
2181
 
 
2182
 
 
2183
 
 
2184
 
 
2185
/**
 
2186
 * Write the header for the content.xml file
 
2187
 */
 
2188
bool OdfOutput::writeContentHeader(Writer &outs)
 
2189
{
 
2190
    time_t tim;
 
2191
    time(&tim);
 
2192
 
 
2193
    outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 
2194
    outs.printf("\n");
 
2195
    outs.printf("\n");
 
2196
    outs.printf("<!--\n");
 
2197
    outs.printf("*************************************************************************\n");
 
2198
    outs.printf("  file:  content.xml\n");
 
2199
    outs.printf("  Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
 
2200
    outs.printf("  http://www.inkscape.org\n");
 
2201
    outs.printf("*************************************************************************\n");
 
2202
    outs.printf("-->\n");
 
2203
    outs.printf("\n");
 
2204
    outs.printf("\n");
 
2205
    outs.printf("<office:document-content\n");
 
2206
    outs.printf("    xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
 
2207
    outs.printf("    xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");
 
2208
    outs.printf("    xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");
 
2209
    outs.printf("    xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");
 
2210
    outs.printf("    xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");
 
2211
    outs.printf("    xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");
 
2212
    outs.printf("    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
 
2213
    outs.printf("    xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
 
2214
    outs.printf("    xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
 
2215
    outs.printf("    xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");
 
2216
    outs.printf("    xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
 
2217
    outs.printf("    xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");
 
2218
    outs.printf("    xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");
 
2219
    outs.printf("    xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");
 
2220
    outs.printf("    xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");
 
2221
    outs.printf("    xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");
 
2222
    outs.printf("    xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");
 
2223
    outs.printf("    xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
 
2224
    outs.printf("    xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");
 
2225
    outs.printf("    xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");
 
2226
    outs.printf("    xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");
 
2227
    outs.printf("    xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");
 
2228
    outs.printf("    xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
 
2229
    outs.printf("    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
 
2230
    outs.printf("    xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
 
2231
    outs.printf("    xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
 
2232
    outs.printf("    office:version=\"1.0\">\n");
 
2233
    outs.printf("\n");
 
2234
    outs.printf("\n");
 
2235
    outs.printf("<office:scripts/>\n");
 
2236
    outs.printf("\n");
 
2237
    outs.printf("\n");
 
2238
    outs.printf("<!--\n");
 
2239
    outs.printf("*************************************************************************\n");
 
2240
    outs.printf("  D R A W I N G\n");
 
2241
    outs.printf("  This section is the heart of SVG-ODF conversion.  We are\n");
 
2242
    outs.printf("  starting with simple conversions, and will slowly evolve\n");
 
2243
    outs.printf("  into a 'smarter' translation as time progresses.  Any help\n");
 
2244
    outs.printf("  in improving .odg export is welcome.\n");
 
2245
    outs.printf("*************************************************************************\n");
 
2246
    outs.printf("-->\n");
 
2247
    outs.printf("\n");
 
2248
    outs.printf("\n");
 
2249
    outs.printf("<office:body>\n");
 
2250
    outs.printf("<office:drawing>\n");
 
2251
    outs.printf("<draw:page draw:name=\"page1\" draw:style-name=\"dp1\"\n");
 
2252
    outs.printf("        draw:master-page-name=\"Default\">\n");
 
2253
    outs.printf("\n");
 
2254
    outs.printf("\n");
 
2255
 
 
2256
    return true;
 
2257
}
 
2258
 
 
2259
 
 
2260
/**
 
2261
 * Write the footer for the content.xml file
 
2262
 */
 
2263
bool OdfOutput::writeContentFooter(Writer &outs)
 
2264
{
 
2265
    outs.printf("\n");
 
2266
    outs.printf("\n");
 
2267
 
 
2268
    outs.printf("</draw:page>\n");
 
2269
    outs.printf("</office:drawing>\n");
 
2270
 
 
2271
    outs.printf("\n");
 
2272
    outs.printf("\n");
 
2273
    outs.printf("<!-- ######### CONVERSION FROM SVG ENDS ######## -->\n");
 
2274
    outs.printf("\n");
 
2275
    outs.printf("\n");
 
2276
 
 
2277
    outs.printf("</office:body>\n");
 
2278
    outs.printf("</office:document-content>\n");
 
2279
    outs.printf("\n");
 
2280
    outs.printf("\n");
 
2281
    outs.printf("\n");
 
2282
    outs.printf("<!--\n");
 
2283
    outs.printf("*************************************************************************\n");
 
2284
    outs.printf("  E N D    O F    F I L E\n");
 
2285
    outs.printf("  Have a nice day  - ishmal\n");
 
2286
    outs.printf("*************************************************************************\n");
 
2287
    outs.printf("-->\n");
 
2288
    outs.printf("\n");
 
2289
    outs.printf("\n");
 
2290
 
 
2291
    return true;
 
2292
}
 
2293
 
 
2294
 
 
2295
 
 
2296
/**
 
2297
 * Write the content.xml file.  Writes the namesspace headers, then
 
2298
 * calls writeTree().
 
2299
 */
 
2300
bool OdfOutput::writeContent(ZipFile &zf, Inkscape::XML::Node *node)
 
2301
{
 
2302
    //Content.xml stream
 
2303
    BufferOutputStream cbouts;
 
2304
    OutputStreamWriter couts(cbouts);
 
2305
 
 
2306
    if (!writeContentHeader(couts))
 
2307
        return false;
 
2308
 
 
2309
    //Style.xml stream
 
2310
    BufferOutputStream sbouts;
 
2311
    OutputStreamWriter souts(sbouts);
 
2312
 
 
2313
    if (!writeStyleHeader(souts))
 
2314
        return false;
 
2315
 
 
2316
 
 
2317
    //# Descend into the tree, doing all of our conversions
 
2318
    //# to both files as the same time
 
2319
    if (!writeTree(couts, souts, node))
 
2320
        {
 
2321
        g_warning("Failed to convert SVG tree");
 
2322
        return false;
 
2323
        }
 
2324
 
 
2325
 
 
2326
 
 
2327
    //# Finish content file
 
2328
    if (!writeContentFooter(couts))
 
2329
        return false;
 
2330
 
 
2331
    ZipEntry *ze = zf.newEntry("content.xml", "ODF master content file");
 
2332
    ze->setUncompressedData(cbouts.getBuffer());
 
2333
    ze->finish();
 
2334
 
 
2335
 
 
2336
 
 
2337
    //# Finish style file
 
2338
    if (!writeStyleFooter(souts))
 
2339
        return false;
 
2340
 
 
2341
    ze = zf.newEntry("styles.xml", "ODF style file");
 
2342
    ze->setUncompressedData(sbouts.getBuffer());
 
2343
    ze->finish();
 
2344
 
 
2345
    return true;
 
2346
}
 
2347
 
 
2348
 
 
2349
/**
 
2350
 * Resets class to its pristine condition, ready to use again
 
2351
 */
 
2352
void
 
2353
OdfOutput::reset()
 
2354
{
 
2355
    metadata.clear();
 
2356
    styleTable.clear();
 
2357
    styleLookupTable.clear();
 
2358
    gradientTable.clear();
 
2359
    gradientLookupTable.clear();
 
2360
    imageTable.clear();
 
2361
 
 
2362
 
 
2363
}
 
2364
 
 
2365
 
 
2366
/**
 
2367
 * Descends into the SVG tree, mapping things to ODF when appropriate
 
2368
 */
 
2369
void
 
2370
OdfOutput::save(Inkscape::Extension::Output */*mod*/, SPDocument *doc, gchar const *filename)
 
2371
{
 
2372
    reset();
 
2373
 
 
2374
    //g_message("native file:%s\n", filename);
 
2375
    documentUri = URI(filename);
 
2376
    /* fixme: It looks like we really are using documentUri as a URI, so we ought to call
 
2377
     * g_filename_to_uri for the URI constructor. */
 
2378
 
 
2379
    ZipFile zf;
 
2380
    preprocess(zf, doc->rroot);
 
2381
 
 
2382
    if (!writeManifest(zf))
 
2383
        {
 
2384
        g_warning("Failed to write manifest");
 
2385
        return;
 
2386
        }
 
2387
 
 
2388
    if (!writeContent(zf, doc->rroot))
 
2389
        {
 
2390
        g_warning("Failed to write content");
 
2391
        return;
 
2392
        }
 
2393
 
 
2394
    if (!writeMeta(zf))
 
2395
        {
 
2396
        g_warning("Failed to write metafile");
 
2397
        return;
 
2398
        }
 
2399
 
 
2400
    if (!zf.writeFile(filename))
 
2401
        {
 
2402
        return;
 
2403
        }
 
2404
}
 
2405
 
 
2406
 
 
2407
/**
 
2408
 * This is the definition of PovRay output.  This function just
 
2409
 * calls the extension system with the memory allocated XML that
 
2410
 * describes the data.
 
2411
*/
 
2412
void
 
2413
OdfOutput::init()
 
2414
{
 
2415
    Inkscape::Extension::build_from_mem(
 
2416
        "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
 
2417
            "<name>" N_("OpenDocument Drawing Output") "</name>\n"
 
2418
            "<id>org.inkscape.output.odf</id>\n"
 
2419
            "<output>\n"
 
2420
                "<extension>.odg</extension>\n"
 
2421
                "<mimetype>text/x-povray-script</mimetype>\n"
 
2422
                "<filetypename>" N_("OpenDocument drawing (*.odg)") "</filetypename>\n"
 
2423
                "<filetypetooltip>" N_("OpenDocument drawing file") "</filetypetooltip>\n"
 
2424
            "</output>\n"
 
2425
        "</inkscape-extension>",
 
2426
        new OdfOutput());
 
2427
}
 
2428
 
 
2429
/**
 
2430
 * Make sure that we are in the database
 
2431
 */
 
2432
bool
 
2433
OdfOutput::check (Inkscape::Extension::Extension */*module*/)
 
2434
{
 
2435
    /* We don't need a Key
 
2436
    if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_POV))
 
2437
        return FALSE;
 
2438
    */
 
2439
 
 
2440
    return TRUE;
 
2441
}
 
2442
 
 
2443
 
 
2444
 
 
2445
//########################################################################
 
2446
//# I N P U T
 
2447
//########################################################################
 
2448
 
 
2449
 
 
2450
 
 
2451
//#######################
 
2452
//# L A T E R  !!!  :-)
 
2453
//#######################
 
2454
 
 
2455
 
 
2456
 
 
2457
 
 
2458
 
 
2459
 
 
2460
 
 
2461
 
 
2462
 
 
2463
 
 
2464
 
 
2465
 
 
2466
 
 
2467
}  //namespace Internal
 
2468
}  //namespace Extension
 
2469
}  //namespace Inkscape
 
2470
 
 
2471
 
 
2472
//########################################################################
 
2473
//# E N D    O F    F I L E
 
2474
//########################################################################
 
2475
 
 
2476
/*
 
2477
  Local Variables:
 
2478
  mode:c++
 
2479
  c-file-style:"stroustrup"
 
2480
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
2481
  indent-tabs-mode:nil
 
2482
  fill-column:99
 
2483
  End:
 
2484
*/
 
2485
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :