Inkscape
Vector Graphics Editor
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages Concepts
odf.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: LGPL-2.1-or-later
/*
5 * Authors:
6 * Bob Jamison
7 * Abhishek Sharma
8 * Kris De Gussem
9 *
10 * Copyright (C) 2018 Authors
11 * Released under GNU LGPL v2.1+, read the file 'COPYING' for more information.
12 */
13/*
14 * This is an an entry in the extensions mechanism to begin to enable
15 * the inputting and outputting of OpenDocument Format (ODF) files from
16 * within Inkscape. Although the initial implementations will be very lossy
17 * due to the differences in the models of SVG and ODF, they will hopefully
18 * improve greatly with time. People should consider this to be a framework
19 * that can be continuously upgraded for ever improving fidelity. Potential
20 * developers should especially look in preprocess() and writeTree() to see how
21 * the SVG tree is scanned, read, translated, and then written to ODF.
22 *
23 * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
24 *
25 */
26
27#include "odf.h"
28
29//# System includes
30#include <clocale> // for setlocale, LC_NUMERIC
31#include <cmath> // for fabs, sqrt, atan, pow, M_PI
32#include <cstring> // for strcmp
33#include <optional> // for optional
34#include <utility> // for pair
35
36//# 2geom includes
37#include <2geom/affine.h> // for Affine
38#include <2geom/bezier-curve.h> // for CubicBezier
39#include <2geom/coord.h> // for Dim2, X, Y
40#include <2geom/curve.h> // for Curve
41#include <2geom/pathvector.h>
42#include <2geom/transforms.h>
43#include "helper/geom.h"
44#include "helper/geom-curves.h"
45
46//# Inkscape includes
47#include "attributes.h" // for SPAttr
48#include "document.h" // for SPDocument
49#include "preferences.h" // for guint32
50#include "style-internal.h" // for SPIPaint, SPIScale24, SPILe...
51#include "style.h" // for SPStyle
52#include "text-editing.h" // for te_get_layout
53
54#include "display/curve.h" // for SPCurve
55#include "extension/extension.h" // for Extension (ptr only), INKSC...
56#include "extension/internal/clear-n_.h" // for N_
57#include "extension/internal/odf.h" // for OdfOutput, GradientInfo
58#include "extension/system.h" // for build_from_mem
59#include "helper/geom-curves.h" // for is_straight_curve
60#include "inkscape-version.h" // for version_string
61#include "io/stream/bufferstream.h" // for BufferOutputStream
62#include "io/stream/stringstream.h" // for StringOutputStream
63#include "io/sys.h" // for get_file_extension
64#include "libnrtype/Layout-TNG.h" // for Layout
65#include "object/sp-flowtext.h" // for SPFlowtext
66#include "object/sp-gradient.h" // for SPGradient
67#include "object/sp-image.h" // for SPImage
68#include "object/sp-item.h" // for SPItem
69#include "object/sp-linear-gradient.h" // for SPLinearGradient
70#include "object/sp-object.h" // for SPObject
71#include "object/sp-radial-gradient.h" // for SPRadialGradient
72#include "object/sp-root.h" // for SPRoot
73#include "object/sp-shape.h" // for SPShape
74#include "object/sp-stop.h" // for SPStop
75#include "object/sp-text.h" // for SPText
76#include "object/uri.h" // for URI
77#include "svg/svg-length.h" // for SVGLength
78#include "util/cast.h" // for cast, is
79#include "util/ziptool.h" // for ZipFile
80#include "xml/node.h" // for Node, NodeType
81
82namespace Inkscape::Extension {
83class Output;
84} // namespace Inkscape::Extension
85
86
88
89//# Shorthand notation
93
94
95//########################################################################
96//# C L A S S SingularValueDecomposition
97//########################################################################
98
99class SVDMatrix
100{
101public:
102
103 SVDMatrix()
104 {
105 init();
106 }
107
108 SVDMatrix(unsigned int rowSize, unsigned int colSize)
109 {
110 init();
111 rows = rowSize;
112 cols = colSize;
113 size = rows * cols;
114 d = new double[size];
115 for (unsigned int i=0 ; i<size ; i++)
116 d[i] = 0.0;
117 }
118
119 SVDMatrix(double *vals, 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] = vals[i];
128 }
129
130
131 SVDMatrix(const SVDMatrix &other)
132 {
133 init();
134 assign(other);
135 }
136
137 SVDMatrix &operator=(const SVDMatrix &other)
138 {
139 assign(other);
140 return *this;
141 }
142
143 virtual ~SVDMatrix()
144 {
145 delete[] d;
146 }
147
148 double& operator() (unsigned int row, unsigned int col)
149 {
150 if (row >= rows || col >= cols)
151 return badval;
152 return d[cols*row + col];
153 }
154
155 double operator() (unsigned int row, unsigned int col) const
156 {
157 if (row >= rows || col >= cols)
158 return badval;
159 return d[cols*row + col];
160 }
161
162 unsigned int getRows()
163 {
164 return rows;
165 }
166
167 unsigned int getCols()
168 {
169 return cols;
170 }
171
172 SVDMatrix multiply(const SVDMatrix &other)
173 {
174 if (cols != other.rows)
175 {
176 SVDMatrix dummy;
177 return dummy;
178 }
179 SVDMatrix result(rows, other.cols);
180 for (unsigned int i=0 ; i<rows ; i++)
181 {
182 for (unsigned int j=0 ; j<other.cols ; j++)
183 {
184 double sum = 0.0;
185 for (unsigned int k=0 ; k<cols ; k++)
186 {
187 //sum += a[i][k] * b[k][j];
188 sum += d[i*cols +k] * other(k, j);
189 }
190 result(i, j) = sum;
191 }
192
193 }
194 return result;
195 }
196
197 SVDMatrix transpose()
198 {
199 SVDMatrix result(cols, rows);
200 for (unsigned int i=0 ; i<rows ; i++){
201 for (unsigned int j=0 ; j<cols ; j++){
202 result(j, i) = d[i*cols + j];
203 }
204 }
205 return result;
206 }
207
208private:
209
210
211 virtual void init()
212 {
213 badval = 0.0;
214 d = nullptr;
215 rows = 0;
216 cols = 0;
217 size = 0;
218 }
219
220 void assign(const SVDMatrix &other)
221 {
222 if (d)
223 {
224 delete[] d;
225 d = nullptr;
226 }
227 rows = other.rows;
228 cols = other.cols;
229 size = other.size;
230 badval = other.badval;
231 d = new double[size];
232 for (unsigned int i=0 ; i<size ; i++){
233 d[i] = other.d[i];
234 }
235 }
236
237 double badval;
238
239 double *d;
240 unsigned int rows;
241 unsigned int cols;
242 unsigned int size;
243};
244
245
246
273class SingularValueDecomposition
274{
275public:
276
282 SingularValueDecomposition (const SVDMatrix &mat) :
283 A (mat),
284 U (),
285 s (nullptr),
286 s_size (0),
287 V ()
288 {
289 calculate();
290 }
291
292 virtual ~SingularValueDecomposition()
293 {
294 delete[] s;
295 }
296
301 SVDMatrix &getU();
302
307 SVDMatrix &getV();
308
double getS(unsigned int index);
312
317 double norm2();
318
323 double cond();
324
329 int rank();
330
331private:
332
333 void calculate();
334
335 SVDMatrix A;
336 SVDMatrix U;
337 double *s;
338 unsigned int s_size;
339 SVDMatrix V;
340
341};
342
343
344static double svd_hypot(double a, double b)
345{
346 double r;
347
348 if (fabs(a) > fabs(b))
349 {
350 r = b/a;
351 r = fabs(a) * sqrt(1+r*r);
352 }
353 else if (b != 0)
354 {
355 r = a/b;
356 r = fabs(b) * sqrt(1+r*r);
357 }
358 else
359 {
360 r = 0.0;
361 }
362 return r;
363}
364
365
366
367void SingularValueDecomposition::calculate()
368{
369 // Initialize.
370 int m = A.getRows();
371 int n = A.getCols();
372
373 int nu = (m > n) ? m : n;
374 s_size = (m+1 < n) ? m+1 : n;
375 s = new double[s_size];
376 U = SVDMatrix(m, nu);
377 V = SVDMatrix(n, n);
378 double *e = new double[n];
379 double *work = new double[m];
380 bool wantu = true;
381 bool wantv = true;
382
383 // Reduce A to bidiagonal form, storing the diagonal elements
384 // in s and the super-diagonal elements in e.
385
386 int nct = (m-1<n) ? m-1 : n;
387 int nrtx = (n-2<m) ? n-2 : m;
388 int nrt = (nrtx>0) ? nrtx : 0;
389 for (int k = 0; k < 2; k++) {
390 if (k < nct) {
391
392 // Compute the transformation for the k-th column and
393 // place the k-th diagonal in s[k].
394 // Compute 2-norm of k-th column without under/overflow.
395 s[k] = 0;
396 for (int i = k; i < m; i++) {
397 s[k] = svd_hypot(s[k],A(i, k));
398 }
399 if (s[k] != 0.0) {
400 if (A(k, k) < 0.0) {
401 s[k] = -s[k];
402 }
403 for (int i = k; i < m; i++) {
404 A(i, k) /= s[k];
405 }
406 A(k, k) += 1.0;
407 }
408 s[k] = -s[k];
409 }
410 for (int j = k+1; j < n; j++) {
411 if ((k < nct) & (s[k] != 0.0)) {
412
413 // Apply the transformation.
414
415 double t = 0;
416 for (int i = k; i < m; i++) {
417 t += A(i, k) * A(i, j);
418 }
419 t = -t/A(k, k);
420 for (int i = k; i < m; i++) {
421 A(i, j) += t*A(i, k);
422 }
423 }
424
425 // Place the k-th row of A into e for the
426 // subsequent calculation of the row transformation.
427
428 e[j] = A(k, j);
429 }
430 if (wantu & (k < nct)) {
431
432 // Place the transformation in U for subsequent back
433 // multiplication.
434
435 for (int i = k; i < m; i++) {
436 U(i, k) = A(i, k);
437 }
438 }
439 if (k < nrt) {
440
441 // Compute the k-th row transformation and place the
442 // k-th super-diagonal in e[k].
443 // Compute 2-norm without under/overflow.
444 e[k] = 0;
445 for (int i = k+1; i < n; i++) {
446 e[k] = svd_hypot(e[k],e[i]);
447 }
448 if (e[k] != 0.0) {
449 if (e[k+1] < 0.0) {
450 e[k] = -e[k];
451 }
452 for (int i = k+1; i < n; i++) {
453 e[i] /= e[k];
454 }
455 e[k+1] += 1.0;
456 }
457 e[k] = -e[k];
458 if ((k+1 < m) & (e[k] != 0.0)) {
459
460 // Apply the transformation.
461
462 for (int i = k+1; i < m; i++) {
463 work[i] = 0.0;
464 }
465 for (int j = k+1; j < n; j++) {
466 for (int i = k+1; i < m; i++) {
467 work[i] += e[j]*A(i, j);
468 }
469 }
470 for (int j = k+1; j < n; j++) {
471 double t = -e[j]/e[k+1];
472 for (int i = k+1; i < m; i++) {
473 A(i, j) += t*work[i];
474 }
475 }
476 }
477 if (wantv) {
478
479 // Place the transformation in V for subsequent
480 // back multiplication.
481
482 for (int i = k+1; i < n; i++) {
483 V(i, k) = e[i];
484 }
485 }
486 }
487 }
488
489 // Set up the final bidiagonal matrix or order p.
490
491 int p = (n < m+1) ? n : m+1;
492 if (nct < n) {
493 s[nct] = A(nct, nct);
494 }
495 if (m < p) {
496 s[p-1] = 0.0;
497 }
498 if (nrt+1 < p) {
499 e[nrt] = A(nrt, p-1);
500 }
501 e[p-1] = 0.0;
502
503 // If required, generate U.
504
505 if (wantu) {
506 for (int j = nct; j < nu; j++) {
507 for (int i = 0; i < m; i++) {
508 U(i, j) = 0.0;
509 }
510 U(j, j) = 1.0;
511 }
512 for (int k = nct-1; k >= 0; k--) {
513 if (s[k] != 0.0) {
514 for (int j = k+1; j < nu; j++) {
515 double t = 0;
516 for (int i = k; i < m; i++) {
517 t += U(i, k)*U(i, j);
518 }
519 t = -t/U(k, k);
520 for (int i = k; i < m; i++) {
521 U(i, j) += t*U(i, k);
522 }
523 }
524 for (int i = k; i < m; i++ ) {
525 U(i, k) = -U(i, k);
526 }
527 U(k, k) = 1.0 + U(k, k);
528 for (int i = 0; i < k-1; i++) {
529 U(i, k) = 0.0;
530 }
531 } else {
532 for (int i = 0; i < m; i++) {
533 U(i, k) = 0.0;
534 }
535 U(k, k) = 1.0;
536 }
537 }
538 }
539
540 // If required, generate V.
541
542 if (wantv) {
543 for (int k = n-1; k >= 0; k--) {
544 if ((k < nrt) & (e[k] != 0.0)) {
545 for (int j = k+1; j < nu; j++) {
546 double t = 0;
547 for (int i = k+1; i < n; i++) {
548 t += V(i, k)*V(i, j);
549 }
550 t = -t/V(k+1, k);
551 for (int i = k+1; i < n; i++) {
552 V(i, j) += t*V(i, k);
553 }
554 }
555 }
556 for (int i = 0; i < n; i++) {
557 V(i, k) = 0.0;
558 }
559 V(k, k) = 1.0;
560 }
561 }
562
563 // Main iteration loop for the singular values.
564
565 int pp = p-1;
566 //double eps = pow(2.0,-52.0);
567 //double tiny = pow(2.0,-966.0);
568 //let's just calculate these now
569 //a double can be e ± 308.25, so this is safe
570 double eps = 2.22e-16;
571 double tiny = 1.6e-291;
572 while (p > 0) {
573 int k,kase;
574
575 // Here is where a test for too many iterations would go.
576
577 // This section of the program inspects for
578 // negligible elements in the s and e arrays. On
579 // completion the variables kase and k are set as follows.
580
581 // kase = 1 if s(p) and e[k-1] are negligible and k<p
582 // kase = 2 if s(k) is negligible and k<p
583 // kase = 3 if e[k-1] is negligible, k<p, and
584 // s(k), ..., s(p) are not negligible (qr step).
585 // kase = 4 if e(p-1) is negligible (convergence).
586
587 for (k = p-2; k >= -1; k--) {
588 if (k == -1) {
589 break;
590 }
591 if (fabs(e[k]) <=
592 tiny + eps*(fabs(s[k]) + fabs(s[k+1]))) {
593 e[k] = 0.0;
594 break;
595 }
596 }
597 if (k == p-2) {
598 kase = 4;
599 } else {
600 int ks;
601 for (ks = p-1; ks >= k; ks--) {
602 if (ks == k) {
603 break;
604 }
605 double t = (ks != p ? fabs(e[ks]) : 0.) +
606 (ks != k+1 ? fabs(e[ks-1]) : 0.);
607 if (fabs(s[ks]) <= tiny + eps*t) {
608 s[ks] = 0.0;
609 break;
610 }
611 }
612 if (ks == k) {
613 kase = 3;
614 } else if (ks == p-1) {
615 kase = 1;
616 } else {
617 kase = 2;
618 k = ks;
619 }
620 }
621 k++;
622
623 // Perform the task indicated by kase.
624
625 switch (kase) {
626
627 // Deflate negligible s(p).
628
629 case 1: {
630 double f = e[p-2];
631 e[p-2] = 0.0;
632 for (int j = p-2; j >= k; j--) {
633 double t = svd_hypot(s[j],f);
634 double cs = s[j]/t;
635 double sn = f/t;
636 s[j] = t;
637 if (j != k) {
638 f = -sn*e[j-1];
639 e[j-1] = cs*e[j-1];
640 }
641 if (wantv) {
642 for (int i = 0; i < n; i++) {
643 t = cs*V(i, j) + sn*V(i, p-1);
644 V(i, p-1) = -sn*V(i, j) + cs*V(i, p-1);
645 V(i, j) = t;
646 }
647 }
648 }
649 }
650 break;
651
652 // Split at negligible s(k).
653
654 case 2: {
655 double f = e[k-1];
656 e[k-1] = 0.0;
657 for (int j = k; j < p; j++) {
658 double t = svd_hypot(s[j],f);
659 double cs = s[j]/t;
660 double sn = f/t;
661 s[j] = t;
662 f = -sn*e[j];
663 e[j] = cs*e[j];
664 if (wantu) {
665 for (int i = 0; i < m; i++) {
666 t = cs*U(i, j) + sn*U(i, k-1);
667 U(i, k-1) = -sn*U(i, j) + cs*U(i, k-1);
668 U(i, j) = t;
669 }
670 }
671 }
672 }
673 break;
674
675 // Perform one qr step.
676
677 case 3: {
678
679 // Calculate the shift.
680
681 double scale = fabs(s[p-1]);
682 double d = fabs(s[p-2]);
683 if (d>scale) scale=d;
684 d = fabs(e[p-2]);
685 if (d>scale) scale=d;
686 d = fabs(s[k]);
687 if (d>scale) scale=d;
688 d = fabs(e[k]);
689 if (d>scale) scale=d;
690 double sp = s[p-1]/scale;
691 double spm1 = s[p-2]/scale;
692 double epm1 = e[p-2]/scale;
693 double sk = s[k]/scale;
694 double ek = e[k]/scale;
695 double b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
696 double c = (sp*epm1)*(sp*epm1);
697 double shift = 0.0;
698 if ((b != 0.0) | (c != 0.0)) {
699 shift = sqrt(b*b + c);
700 if (b < 0.0) {
701 shift = -shift;
702 }
703 shift = c/(b + shift);
704 }
705 double f = (sk + sp)*(sk - sp) + shift;
706 double g = sk*ek;
707
708 // Chase zeros.
709
710 for (int j = k; j < p-1; j++) {
711 double t = svd_hypot(f,g);
712 double cs = f/t;
713 double sn = g/t;
714 if (j != k) {
715 e[j-1] = t;
716 }
717 f = cs*s[j] + sn*e[j];
718 e[j] = cs*e[j] - sn*s[j];
719 g = sn*s[j+1];
720 s[j+1] = cs*s[j+1];
721 if (wantv) {
722 for (int i = 0; i < n; i++) {
723 t = cs*V(i, j) + sn*V(i, j+1);
724 V(i, j+1) = -sn*V(i, j) + cs*V(i, j+1);
725 V(i, j) = t;
726 }
727 }
728 t = svd_hypot(f,g);
729 cs = f/t;
730 sn = g/t;
731 s[j] = t;
732 f = cs*e[j] + sn*s[j+1];
733 s[j+1] = -sn*e[j] + cs*s[j+1];
734 g = sn*e[j+1];
735 e[j+1] = cs*e[j+1];
736 if (wantu && (j < m-1)) {
737 for (int i = 0; i < m; i++) {
738 t = cs*U(i, j) + sn*U(i, j+1);
739 U(i, j+1) = -sn*U(i, j) + cs*U(i, j+1);
740 U(i, j) = t;
741 }
742 }
743 }
744 e[p-2] = f;
745 }
746 break;
747
748 // Convergence.
749
750 case 4: {
751
752 // Make the singular values positive.
753
754 if (s[k] <= 0.0) {
755 s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
756 if (wantv) {
757 for (int i = 0; i <= pp; i++) {
758 V(i, k) = -V(i, k);
759 }
760 }
761 }
762
763 // Order the singular values.
764
765 while (k < pp) {
766 if (s[k] >= s[k+1]) {
767 break;
768 }
769 double t = s[k];
770 s[k] = s[k+1];
771 s[k+1] = t;
772 if (wantv && (k < n-1)) {
773 for (int i = 0; i < n; i++) {
774 t = V(i, k+1); V(i, k+1) = V(i, k); V(i, k) = t;
775 }
776 }
777 if (wantu && (k < m-1)) {
778 for (int i = 0; i < m; i++) {
779 t = U(i, k+1); U(i, k+1) = U(i, k); U(i, k) = t;
780 }
781 }
782 k++;
783 }
784 p--;
785 }
786 break;
787 }
788 }
789
790 delete [] e;
791 delete [] work;
792
793}
794
795
800SVDMatrix &SingularValueDecomposition::getU()
801{
802 return U;
803}
804
810SVDMatrix &SingularValueDecomposition::getV()
811{
812 return V;
813}
814
818double SingularValueDecomposition::getS(unsigned int index)
819{
820 if (index >= s_size)
821 return 0.0;
822 return s[index];
823}
824
829double SingularValueDecomposition::norm2()
830{
831 return s[0];
832}
833
839double SingularValueDecomposition::cond()
840{
841 return s[0]/s[2];
842}
843
848int SingularValueDecomposition::rank()
849{
850 double eps = pow(2.0,-52.0);
851 double tol = 3.0*s[0]*eps;
852 int r = 0;
853 for (int i = 0; i < 3; i++)
854 {
855 if (s[i] > tol)
856 r++;
857 }
858 return r;
859}
860
861//########################################################################
862//# E N D C L A S S SingularValueDecomposition
863//########################################################################
864
865
866
867
868
869//#define pxToCm 0.0275
870#define pxToCm 0.03
871
872
873//########################################################################
874//# O U T P U T
875//########################################################################
876
880static Glib::ustring getAttribute( Inkscape::XML::Node *node, char const *attrName)
881{
882 Glib::ustring val;
883 char const *valstr = node->attribute(attrName);
884 if (valstr)
885 val = valstr;
886 return val;
887}
888
889
890static Glib::ustring formatTransform(Geom::Affine &tf)
891{
892 Glib::ustring str;
893 if (!tf.isIdentity())
894 {
896 OutputStreamWriter out(outs);
897 out.printf("matrix(%.3f %.3f %.3f %.3f %.3f %.3f)",
898 tf[0], tf[1], tf[2], tf[3], tf[4], tf[5]);
899 str = outs.getString();
900 }
901 return str;
902}
903
904
910{
911 //### Get SVG-to-ODF transform
913 tf = tf * Geom::Affine(Geom::Scale(pxToCm));
914 return tf;
915}
916
917
923{
924 // TODO: geometric or visual?
926 if (bbox) {
927 *bbox *= Geom::Affine(Geom::Scale(pxToCm));
928 }
929 return bbox;
930}
931
932
938{
939 Geom::Affine itemTransform (item->i2doc_affine() *
941 return itemTransform;
942}
943
944
949 double &rotate, double &/*xskew*/, double &/*yskew*/,
950 double &xscale, double &yscale)
951{
952 SVDMatrix mat(2, 2);
953 mat(0, 0) = tf[0];
954 mat(0, 1) = tf[1];
955 mat(1, 0) = tf[2];
956 mat(1, 1) = tf[3];
957
958 SingularValueDecomposition svd(mat);
959
960 SVDMatrix U = svd.getU();
961 SVDMatrix V = svd.getV();
962 SVDMatrix Vt = V.transpose();
963 SVDMatrix UVt = U.multiply(Vt);
964 double s0 = svd.getS(0);
965 double s1 = svd.getS(1);
966 xscale = s0;
967 yscale = s1;
968 rotate = UVt(0,0);
969}
970
971static void gatherText(Inkscape::XML::Node *node, Glib::ustring &buf)
972{
974 {
975 char *s = (char *)node->content();
976 if (s)
977 buf.append(s);
978 }
979
981 child != nullptr; child = child->next())
982 {
984 }
985
986}
987
988
995{
996 Glib::ustring nodeName = node->name();
997 Glib::ustring id = getAttribute(node, "id");
998
999 //### First, check for metadata
1000 if (nodeName == "metadata" || nodeName == "svg:metadata")
1001 {
1002 Inkscape::XML::Node *mchild = node->firstChild() ;
1003 if (!mchild || strcmp(mchild->name(), "rdf:RDF"))
1004 return;
1005 Inkscape::XML::Node *rchild = mchild->firstChild() ;
1006 if (!rchild || strcmp(rchild->name(), "cc:Work"))
1007 return;
1008 for (Inkscape::XML::Node *cchild = rchild->firstChild() ;
1009 cchild ; cchild = cchild->next())
1010 {
1011 Glib::ustring ccName = cchild->name();
1012 Glib::ustring ccVal;
1013 gatherText(cchild, ccVal);
1014 //g_message("ccName: %s ccVal:%s", ccName.c_str(), ccVal.c_str());
1015 metadata[ccName] = ccVal;
1016 }
1017 return;
1018 }
1019
1020 //Now consider items.
1021 SPObject *reprobj = doc->getObjectByRepr(node);
1022 if (!reprobj)
1023 {
1024 return;
1025 }
1026 if (!is<SPItem>(reprobj))
1027 {
1028 return;
1029 }
1030
1031 if (nodeName == "image" || nodeName == "svg:image") {
1032 Glib::ustring href = getAttribute(node, "xlink:href");
1033 if (href.size() > 0 && imageTable.count(href) == 0) {
1034 try {
1035 auto uri = Inkscape::URI(href.c_str(), docBaseUri.c_str());
1036 auto mimetype = uri.getMimeType();
1037
1038 if (mimetype.substr(0, 6) != "image/") {
1039 return;
1040 }
1041
1042 auto ext = mimetype.substr(6);
1043 auto newName = Glib::ustring("Pictures/image") + std::to_string(imageTable.size()) + "." + ext;
1044
1045 imageTable[href] = newName;
1046
1047 auto ze = zf.newEntry(newName.raw(), "");
1048 ze->setUncompressedData(uri.getContents());
1049 ze->finish();
1050 } catch (...) {
1051 g_warning("Could not handle URI '%.100s'", href.c_str());
1052 }
1053 }
1054 }
1055
1057 child ; child = child->next())
1058 preprocess(zf, doc, child);
1059}
1060
1061
1067{
1068 BufferOutputStream bouts;
1069 OutputStreamWriter outs(bouts);
1070
1071 time_t tim;
1072 time(&tim);
1073
1074 outs.writeString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1075 outs.writeString("<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">\n");
1076 outs.writeString("\n");
1077 outs.writeString("\n");
1078 outs.writeString("<!--\n");
1079 outs.writeString("*************************************************************************\n");
1080 outs.writeString(" file: manifest.xml\n");
1081 outs.printf (" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
1082 outs.writeString(" http://www.inkscape.org\n");
1083 outs.writeString("*************************************************************************\n");
1084 outs.writeString("-->\n");
1085 outs.writeString("\n");
1086 outs.writeString("\n");
1087 outs.writeString("<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n");
1088 outs.writeString(" <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.graphics\" manifest:full-path=\"/\"/>\n");
1089 outs.writeString(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>\n");
1090 outs.writeString(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"styles.xml\"/>\n");
1091 outs.writeString(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>\n");
1092 outs.writeString(" <!--List our images here-->\n");
1093 std::map<Glib::ustring, Glib::ustring>::iterator iter;
1094 for (iter = imageTable.begin() ; iter!=imageTable.end() ; ++iter)
1095 {
1096 Glib::ustring newName = iter->second;
1097
1098 // note: mime subtype was added as file extension in OdfOutput::preprocess
1099 Glib::ustring mimesubtype = Inkscape::IO::get_file_extension(newName);
1100
1101 outs.printf(" <manifest:file-entry manifest:media-type=\"");
1102 outs.printf("image/");
1103 outs.printf("%s", mimesubtype.c_str());
1104 outs.printf("\" manifest:full-path=\"");
1105 outs.writeString(newName.c_str());
1106 outs.printf("\"/>\n");
1107 }
1108 outs.printf("</manifest:manifest>\n");
1109
1110 outs.close();
1111
1112 //Make our entry
1113 ZipEntry *ze = zf.newEntry("META-INF/manifest.xml", "ODF file manifest");
1114 ze->setUncompressedData(bouts.getBuffer());
1115 ze->finish();
1116
1117 return true;
1118}
1119
1120
1125{
1126 BufferOutputStream bouts;
1127 OutputStreamWriter outs(bouts);
1128
1129 time_t tim;
1130 time(&tim);
1131
1132 std::map<Glib::ustring, Glib::ustring>::iterator iter;
1133 Glib::ustring InkscapeVersion = Glib::ustring("Inkscape.org - ") + Inkscape::version_string;
1134 Glib::ustring creator = InkscapeVersion;
1135 iter = metadata.find("dc:creator");
1136 if (iter != metadata.end())
1137 {
1138 creator = iter->second;
1139 }
1140
1141 Glib::ustring date;
1142 Glib::ustring moddate;
1143 char buf [80];
1144 time_t rawtime;
1145 struct tm * timeinfo;
1146 time (&rawtime);
1147 timeinfo = localtime (&rawtime);
1148 strftime (buf,80,"%Y-%m-%d %H:%M:%S",timeinfo);
1149 moddate = Glib::ustring(buf);
1150
1151 iter = metadata.find("dc:date");
1152 if (iter != metadata.end())
1153 {
1154 date = iter->second;
1155 }
1156 else
1157 {
1158 date = moddate;
1159 }
1160
1161 outs.writeString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1162 outs.writeString("\n");
1163 outs.writeString("<!--\n");
1164 outs.writeString("*************************************************************************\n");
1165 outs.writeString(" file: meta.xml\n");
1166 outs.printf (" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
1167 outs.writeString(" http://www.inkscape.org\n");
1168 outs.writeString("*************************************************************************\n");
1169 outs.writeString("-->\n");
1170 outs.writeString("\n");
1171 outs.writeString("<office:document-meta\n");
1172 outs.writeString("xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
1173 outs.writeString("xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
1174 outs.writeString("xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
1175 outs.writeString("xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
1176 outs.writeString("xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
1177 outs.writeString("xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
1178 outs.writeString("xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
1179 outs.writeString("xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
1180 outs.writeString("office:version=\"1.0\">\n");
1181 outs.writeString("<office:meta>\n");
1182 Glib::ustring tmp = Glib::ustring::compose(" <meta:generator>%1</meta:generator>\n", InkscapeVersion);
1183 tmp += Glib::ustring::compose(" <meta:initial-creator>%1</meta:initial-creator>\n", creator);
1184 tmp += Glib::ustring::compose(" <meta:creation-date>%1</meta:creation-date>\n", date);
1185 tmp += Glib::ustring::compose(" <dc:date>%1</dc:date>\n", moddate);
1186 outs.writeUString(tmp);
1187 for (iter = metadata.begin() ; iter != metadata.end() ; ++iter)
1188 {
1189 Glib::ustring name = iter->first;
1190 Glib::ustring value = iter->second;
1191 if (!name.empty() && !value.empty())
1192 {
1193 tmp = Glib::ustring::compose(" <%1>%2</%3>\n", name, value, name);
1194 outs.writeUString(tmp);
1195 }
1196 }
1197 // outs.writeString(" <meta:editing-cycles>2</meta:editing-cycles>\n");
1198 // outs.writeString(" <meta:editing-duration>PT56S</meta:editing-duration>\n");
1199 // outs.writeString(" <meta:user-defined meta:name=\"Info 1\"/>\n");
1200 // outs.writeString(" <meta:user-defined meta:name=\"Info 2\"/>\n");
1201 // outs.writeString(" <meta:user-defined meta:name=\"Info 3\"/>\n");
1202 // outs.writeString(" <meta:user-defined meta:name=\"Info 4\"/>\n");
1203 // outs.writeString(" <meta:document-statistic meta:object-count=\"2\"/>\n");
1204 outs.writeString("</office:meta>\n");
1205 outs.writeString("</office:document-meta>\n");
1206 outs.close();
1207
1208 //Make our entry
1209 ZipEntry *ze = zf.newEntry("meta.xml", "ODF info file");
1210 ze->setUncompressedData(bouts.getBuffer());
1211 ze->finish();
1212
1213 return true;
1214}
1215
1216
1220static int
1222 Geom::Affine const &tf, double xoff, double yoff)
1223{
1224 using Geom::X;
1225 using Geom::Y;
1226
1227 int nrPoints = 0;
1228
1229 // convert the path to only lineto's and cubic curveto's:
1230 Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv * tf * Geom::Translate(xoff, yoff) * Geom::Scale(1000.));
1231
1232 for (const auto & pit : pv) {
1233
1234 double destx = pit.initialPoint()[X];
1235 double desty = pit.initialPoint()[Y];
1236 if (fabs(destx)<1.0) destx = 0.0; // Why is this needed? Shouldn't we just round all numbers then?
1237 if (fabs(desty)<1.0) desty = 0.0;
1238 outs.printf("M %.3f %.3f ", destx, desty);
1239 nrPoints++;
1240
1241 for (Geom::Path::const_iterator cit = pit.begin(); cit != pit.end_closed(); ++cit) {
1242
1243 if( is_straight_curve(*cit) )
1244 {
1245 double destx = cit->finalPoint()[X];
1246 double desty = cit->finalPoint()[Y];
1247 if (fabs(destx)<1.0) destx = 0.0; // Why is this needed? Shouldn't we just round all numbers then?
1248 if (fabs(desty)<1.0) desty = 0.0;
1249 outs.printf("L %.3f %.3f ", destx, desty);
1250 }
1251 else if(Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) {
1252 std::vector<Geom::Point> points = cubic->controlPoints();
1253 for (unsigned i = 1; i <= 3; i++) {
1254 if (fabs(points[i][X])<1.0) points[i][X] = 0.0; // Why is this needed? Shouldn't we just round all numbers then?
1255 if (fabs(points[i][Y])<1.0) points[i][Y] = 0.0;
1256 }
1257 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]);
1258 }
1259 else {
1260 g_error ("logical error, because pathv_to_linear_and_cubic_beziers was used");
1261 }
1262
1263 nrPoints++;
1264 }
1265
1266 if (pit.closed()) {
1267 outs.printf("Z");
1268 }
1269 }
1270
1271 return nrPoints;
1272}
1273
1274bool OdfOutput::processStyle(SPItem *item, const Glib::ustring &id, const Glib::ustring &gradientNameFill, const Glib::ustring &gradientNameStroke, Glib::ustring& output)
1275{
1276 output.clear();
1277 if (!item)
1278 {
1279 return false;
1280 }
1281
1282 SPStyle *style = item->style;
1283 if (!style)
1284 {
1285 return false;
1286 }
1287
1288 StyleInfo si;
1289
1290 // FILL
1291 if (style->fill.isColor())
1292 {
1293 guint32 fillCol = style->fill.getColor().toRGBA();
1294 char buf[16];
1295 int r = (fillCol >> 24) & 0xff;
1296 int g = (fillCol >> 16) & 0xff;
1297 int b = (fillCol >> 8) & 0xff;
1298 snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
1299 si.fillColor = buf;
1300 si.fill = "solid";
1301 double opacityPercent = 100.0 *
1302 (SP_SCALE24_TO_FLOAT(style->fill_opacity.value));
1303 snprintf(buf, 15, "%.3f%%", opacityPercent);
1304 si.fillOpacity = buf;
1305 }
1306 else if (style->fill.isPaintserver())
1307 {
1308 auto gradient = cast<SPGradient>(SP_STYLE_FILL_SERVER(style));
1309 if (gradient)
1310 {
1311 si.fill = "gradient";
1312 }
1313 }
1314
1315 // STROKE
1316 if (style->stroke.isColor())
1317 {
1318 guint32 strokeCol = style->stroke.getColor().toRGBA();
1319 char buf[16];
1320 int r = (strokeCol >> 24) & 0xff;
1321 int g = (strokeCol >> 16) & 0xff;
1322 int b = (strokeCol >> 8) & 0xff;
1323 snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
1324 si.strokeColor = buf;
1325 snprintf(buf, 15, "%.3fpt", style->stroke_width.value);
1326 si.strokeWidth = buf;
1327 si.stroke = "solid";
1328 double opacityPercent = 100.0 *
1329 (SP_SCALE24_TO_FLOAT(style->stroke_opacity.value));
1330 snprintf(buf, 15, "%.3f%%", opacityPercent);
1331 si.strokeOpacity = buf;
1332 }
1333 else if (style->stroke.isPaintserver())
1334 {
1335 auto gradient = cast<SPGradient>(SP_STYLE_STROKE_SERVER(style));
1336 if (gradient)
1337 {
1338 si.stroke = "gradient";
1339 }
1340 }
1341
1342 //Look for existing identical style;
1343 bool styleMatch = false;
1344 std::vector<StyleInfo>::iterator iter;
1345 for (iter=styleTable.begin() ; iter!=styleTable.end() ; ++iter)
1346 {
1347 if (si.equals(*iter))
1348 {
1349 //map to existing styleTable entry
1350 Glib::ustring styleName = iter->name;
1351 styleLookupTable[id] = styleName;
1352 styleMatch = true;
1353 break;
1354 }
1355 }
1356
1357 // Don't need a new style
1358 if (styleMatch)
1359 {
1360 return false;
1361 }
1362
1363 Glib::ustring styleName = Glib::ustring::compose("style%1", styleTable.size());
1364 si.name = styleName;
1365 styleTable.push_back(si);
1366 styleLookupTable[id] = styleName;
1367
1368 output = Glib::ustring::compose ("<style:style style:name=\"%1\" style:family=\"graphic\" style:parent-style-name=\"standard\">\n", si.name);
1369 output += "<style:graphic-properties";
1370 if (si.fill == "gradient")
1371 {
1372 output += Glib::ustring::compose (" draw:fill=\"gradient\" draw:fill-gradient-name=\"%1\"", gradientNameFill);
1373 }
1374 else
1375 {
1376 output += Glib::ustring(" draw:fill=\"") + si.fill + "\"";
1377 if(si.fill != "none")
1378 {
1379 output += Glib::ustring::compose(" draw:fill-color=\"%1\"", si.fillColor);
1380 }
1381 }
1382 if (si.stroke == "gradient")
1383 {
1384 //does not seem to be supported by Open Office.org
1385 output += Glib::ustring::compose (" draw:stroke=\"gradient\" draw:stroke-gradient-name=\"%1\"", gradientNameStroke);
1386 }
1387 else
1388 {
1389 output += Glib::ustring(" draw:stroke=\"") + si.stroke + "\"";
1390 if (si.stroke != "none")
1391 {
1392 output += Glib::ustring::compose (" svg:stroke-width=\"%1\" svg:stroke-color=\"%2\" ", si.strokeWidth, si.strokeColor);
1393 }
1394 }
1395 output += "/>\n</style:style>\n";
1396
1397 return true;
1398}
1399
1401 const Glib::ustring &id, Geom::Affine &/*tf*/,
1402 Glib::ustring& gradientName, Glib::ustring& output, bool checkFillGradient)
1403{
1404 output.clear();
1405 if (!item)
1406 {
1407 return false;
1408 }
1409
1410 SPStyle *style = item->style;
1411 if (!style)
1412 {
1413 return false;
1414 }
1415
1416 if ((checkFillGradient? (!style->fill.isPaintserver()) : (!style->stroke.isPaintserver())))
1417 {
1418 return false;
1419 }
1420
1421 //## Gradient
1422 auto gradient = cast<SPGradient>((checkFillGradient?(SP_STYLE_FILL_SERVER(style)) :(SP_STYLE_STROKE_SERVER(style))));
1423
1424 if (gradient == nullptr)
1425 {
1426 return false;
1427 }
1428 GradientInfo gi;
1429 SPGradient *grvec = gradient->getVector(FALSE);
1430 for (SPStop *stop = grvec->getFirstStop();
1431 stop ; stop = stop->getNextStop())
1432 {
1433 // TODO: Replace these with a color object to support more than RGB
1434 auto color = stop->getColor().toRGBA(false);
1435 auto opacity = stop->getColor().getOpacity();
1436 GradientStop gs(color, opacity);
1437 gi.stops.push_back(gs);
1438 }
1439
1440 Glib::ustring gradientName2;
1441 if (is<SPLinearGradient>(gradient))
1442 {
1443 gi.style = "linear";
1444 auto linGrad = cast<SPLinearGradient>(gradient);
1445 gi.x1 = linGrad->x1.value;
1446 gi.y1 = linGrad->y1.value;
1447 gi.x2 = linGrad->x2.value;
1448 gi.y2 = linGrad->y2.value;
1449 gradientName2 = Glib::ustring::compose("ImportedLinearGradient%1", gradientTable.size());
1450 }
1451 else if (is<SPRadialGradient>(gradient))
1452 {
1453 gi.style = "radial";
1454 auto radGrad = cast<SPRadialGradient>(gradient);
1456 gi.cx = (radGrad->cx.value-bbox->left())/bbox->width();
1457 gi.cy = (radGrad->cy.value-bbox->top())/bbox->height();
1458 gradientName2 = Glib::ustring::compose("ImportedRadialGradient%1", gradientTable.size());
1459 }
1460 else
1461 {
1462 g_warning("not a supported gradient type");
1463 return false;
1464 }
1465
1466 //Look for existing identical style;
1467 bool gradientMatch = false;
1468 std::vector<GradientInfo>::iterator iter;
1469 for (iter=gradientTable.begin() ; iter!=gradientTable.end() ; ++iter)
1470 {
1471 if (gi.equals(*iter))
1472 {
1473 //map to existing gradientTable entry
1474 gradientName = iter->name;
1475 gradientLookupTable[id] = gradientName;
1476 gradientMatch = true;
1477 break;
1478 }
1479 }
1480
1481 if (gradientMatch)
1482 {
1483 return true;
1484 }
1485
1486 // No match, let us write a new entry
1487 gradientName = gradientName2;
1488 gi.name = gradientName;
1489 gradientTable.push_back(gi);
1490 gradientLookupTable[id] = gradientName;
1491
1492 // int gradientCount = gradientTable.size();
1493 char buf[128];
1494 if (gi.style == "linear")
1495 {
1496 /*
1497 ===================================================================
1498 LINEAR gradient. We need something that looks like this:
1499 <draw:gradient draw:name="Gradient_20_7"
1500 draw:display-name="Gradient 7"
1501 draw:style="linear"
1502 draw:start-color="#008080" draw:end-color="#993366"
1503 draw:start-intensity="100%" draw:end-intensity="100%"
1504 draw:angle="150" draw:border="0%"/>
1505 ===================================================================
1506 */
1507 if (gi.stops.size() < 2)
1508 {
1509 g_warning("Need at least 2 stops for a linear gradient");
1510 return false;
1511 }
1512 output += Glib::ustring::compose("<draw:gradient draw:name=\"%1\"", gi.name);
1513 output += Glib::ustring::compose(" draw:display-name=\"%1\"", gi.name);
1514 output += " draw:style=\"linear\"";
1515 snprintf(buf, 127, " draw:start-color=\"#%06lx\" draw:end-color=\"#%06lx\"", gi.stops[0].rgb, gi.stops[1].rgb);
1516 output += buf;
1517 //TODO: apply maths, to define begin of gradient, taking gradient begin and end, as well as object boundary into account
1518 double angle = (gi.y2-gi.y1);
1519 angle = (angle != 0.) ? (atan((gi.x2-gi.x1)/(gi.y2-gi.y1))* 180. / M_PI) : 90;
1520 angle = (angle < 0)?(180+angle):angle;
1521 angle = angle * 10; //why do we need this: precision?????????????
1522 output += Glib::ustring::compose(" draw:start-intensity=\"%1\" draw:end-intensity=\"%2\" draw:angle=\"%3\"/>\n",
1523 gi.stops[0].opacity * 100.0, gi.stops[1].opacity * 100.0, angle);// draw:border=\"0%%\"
1524 }
1525 else if (gi.style == "radial")
1526 {
1527 /*
1528 ===================================================================
1529 RADIAL gradient. We need something that looks like this:
1530 <!-- radial gradient, light gray to white, centered, 0% border -->
1531 <draw:gradient draw:name="radial_20_borderless"
1532 draw:display-name="radial borderless"
1533 draw:style="radial"
1534 draw:cx="50%" draw:cy="50%"
1535 draw:start-color="#999999" draw:end-color="#ffffff"
1536 draw:border="0%"/>
1537 ===================================================================
1538 */
1539 if (gi.stops.size() < 2)
1540 {
1541 g_warning("Need at least 2 stops for a radial gradient");
1542 return false;
1543 }
1544 output += Glib::ustring::compose("<draw:gradient draw:name=\"%1\" draw:display-name=\"%1\" ", gi.name);
1545 snprintf(buf, 127, "draw:cx=\"%05.3f\" draw:cy=\"%05.3f\" ", gi.cx*100, gi.cy*100);
1546 output += Glib::ustring("draw:style=\"radial\" ") + buf;
1547 snprintf(buf, 127, "draw:start-color=\"#%06lx\" draw:end-color=\"#%06lx\" ", gi.stops[0].rgb, gi.stops[1].rgb);
1548 output += buf;
1549 snprintf(buf, 127, "draw:start-intensity=\"%f%%\" draw:end-intensity=\"%f%%\" ", gi.stops[0].opacity*100.0, gi.stops[1].opacity*100.0);
1550 output += buf;
1551 output += "/>\n";//draw:border=\"0%\"
1552 }
1553 else
1554 {
1555 g_warning("unsupported gradient style '%s'", gi.style.c_str());
1556 return false;
1557 }
1558 return true;
1559}
1560
1561
1567 SPDocument *doc,
1569{
1570 //# Get the SPItem, if applicable
1571 SPObject *reprobj = doc->getObjectByRepr(node);
1572 if (!reprobj)
1573 {
1574 return true;
1575 }
1576 if (!is<SPItem>(reprobj))
1577 {
1578 return true;
1579 }
1580 auto item = cast<SPItem>(reprobj);
1581
1582 Glib::ustring nodeName = node->name();
1583 Glib::ustring id = getAttribute(node, "id");
1584 Geom::Affine tf = getODFTransform(item);//Get SVG-to-ODF transform
1585 Geom::OptRect bbox = getODFBoundingBox(item);//Get ODF bounding box params for item
1586 if (!bbox) {
1587 return true;
1588 }
1589
1590 double bbox_x = bbox->min()[Geom::X];
1591 double bbox_y = bbox->min()[Geom::Y];
1592 double bbox_width = (*bbox)[Geom::X].extent();
1593 double bbox_height = (*bbox)[Geom::Y].extent();
1594
1595 double rotate;
1596 double xskew;
1597 double yskew;
1598 double xscale;
1599 double yscale;
1600 analyzeTransform(tf, rotate, xskew, yskew, xscale, yscale);
1601
1602 //# Do our stuff
1603
1604 if (nodeName == "svg" || nodeName == "svg:svg")
1605 {
1606 //# Iterate through the children
1608 child ; child = child->next())
1609 {
1610 if (!writeTree(couts, souts, doc, child))
1611 {
1612 return false;
1613 }
1614 }
1615 return true;
1616 }
1617 else if (nodeName == "g" || nodeName == "svg:g")
1618 {
1619 if (!id.empty())
1620 {
1621 couts.printf("<draw:g id=\"%s\">\n", id.c_str());
1622 }
1623 else
1624 {
1625 couts.printf("<draw:g>\n");
1626 }
1627 //# Iterate through the children
1629 child ; child = child->next())
1630 {
1631 if (!writeTree(couts, souts, doc, child))
1632 {
1633 return false;
1634 }
1635 }
1636 if (!id.empty())
1637 {
1638 couts.printf("</draw:g> <!-- id=\"%s\" -->\n", id.c_str());
1639 }
1640 else
1641 {
1642 couts.printf("</draw:g>\n");
1643 }
1644 return true;
1645 }
1646
1647 //# GRADIENT
1648 Glib::ustring gradientNameFill;
1649 Glib::ustring gradientNameStroke;
1650 Glib::ustring outputFill;
1651 Glib::ustring outputStroke;
1652 Glib::ustring outputStyle;
1653
1654 processGradient(item, id, tf, gradientNameFill, outputFill, true);
1655 processGradient(item, id, tf, gradientNameStroke, outputStroke, false);
1656 souts.writeUString(outputFill);
1657 souts.writeUString(outputStroke);
1658
1659 //# STYLE
1660 processStyle(item, id, gradientNameFill, gradientNameStroke, outputStyle);
1661 souts.writeUString(outputStyle);
1662
1663 //# ITEM DATA
1664 if (nodeName == "image" || nodeName == "svg:image")
1665 {
1666 if (!is<SPImage>(item))
1667 {
1668 g_warning("<image> is not an SPImage.");
1669 return false;
1670 }
1671
1672 auto img = cast<SPImage>(item);
1673 double ix = img->x.value;
1674 double iy = img->y.value;
1675 double iwidth = img->width.value;
1676 double iheight = img->height.value;
1677
1678 Geom::Point ibbox_min = Geom::Point(ix, iy) * tf;
1679 ix = ibbox_min.x();
1680 iy = ibbox_min.y();
1681 iwidth = xscale * iwidth;
1682 iheight = yscale * iheight;
1683
1684 Geom::Affine itemTransform = getODFItemTransform(item);
1685
1686 Glib::ustring itemTransformString = formatTransform(itemTransform);
1687
1688 Glib::ustring href = getAttribute(node, "xlink:href");
1689 std::map<Glib::ustring, Glib::ustring>::iterator iter = imageTable.find(href);
1690 if (iter == imageTable.end())
1691 {
1692 g_warning("image '%s' not in table", href.c_str());
1693 return false;
1694 }
1695 Glib::ustring newName = iter->second;
1696
1697 couts.printf("<draw:frame ");
1698 if (!id.empty())
1699 {
1700 couts.printf("id=\"%s\" ", id.c_str());
1701 }
1702 couts.printf("draw:style-name=\"gr1\" draw:text-style-name=\"P1\" draw:layer=\"layout\" ");
1703 //no x or y. make them the translate transform, last one
1704 couts.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
1705 iwidth, iheight);
1706 if (!itemTransformString.empty())
1707 {
1708 couts.printf("draw:transform=\"%s translate(%.3fcm, %.3fcm)\" ",
1709 itemTransformString.c_str(), ix, iy);
1710 }
1711 else
1712 {
1713 couts.printf("draw:transform=\"translate(%.3fcm, %.3fcm)\" ", ix, iy);
1714 }
1715
1716 couts.writeString(">\n");
1717 couts.printf(" <draw:image xlink:href=\"%s\" xlink:type=\"simple\"\n",
1718 newName.c_str());
1719 couts.writeString(" xlink:show=\"embed\" xlink:actuate=\"onLoad\">\n");
1720 couts.writeString(" <text:p/>\n");
1721 couts.writeString(" </draw:image>\n");
1722 couts.writeString("</draw:frame>\n");
1723 return true;
1724 }
1725
1726 auto process_curve = [&, this] (SPCurve const &curve) {
1727 //### Default <path> output
1728 couts.writeString("<draw:path ");
1729 if (!id.empty())
1730 {
1731 couts.printf("id=\"%s\" ", id.c_str());
1732 }
1733
1734 std::map<Glib::ustring, Glib::ustring>::iterator siter;
1735 siter = styleLookupTable.find(id);
1736 if (siter != styleLookupTable.end())
1737 {
1738 Glib::ustring styleName = siter->second;
1739 couts.printf("draw:style-name=\"%s\" ", styleName.c_str());
1740 }
1741
1742 couts.printf("draw:layer=\"layout\" svg:x=\"%.3fcm\" svg:y=\"%.3fcm\" ",
1743 bbox_x, bbox_y);
1744 couts.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
1745 bbox_width, bbox_height);
1746 couts.printf("svg:viewBox=\"0.0 0.0 %.3f %.3f\"",
1747 bbox_width * 1000.0, bbox_height * 1000.0);
1748
1749 couts.printf(" svg:d=\"");
1750 int nrPoints = writePath(couts, curve.get_pathvector(),
1751 tf, bbox_x, bbox_y);
1752 couts.writeString("\"");
1753
1754 couts.writeString(">\n");
1755 couts.printf(" <!-- %d nodes -->\n", nrPoints);
1756 couts.writeString("</draw:path>\n\n");
1757 };
1758
1759 if (auto shape = cast<SPShape>(item)) {
1760 if (shape->curve()) {
1761 process_curve(*shape->curve());
1762 }
1763 } else if (is<SPText>(item) || is<SPFlowtext>(item)) {
1764 process_curve(te_get_layout(item)->convertToCurves());
1765 }
1766
1767 return true;
1768}
1769
1774{
1775 time_t tim;
1776 time(&tim);
1777
1778 outs.writeString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1779 outs.writeString("\n");
1780 outs.writeString("<!--\n");
1781 outs.writeString("*************************************************************************\n");
1782 outs.writeString(" file: styles.xml\n");
1783 outs.printf (" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
1784 outs.writeString(" http://www.inkscape.org\n");
1785 outs.writeString("*************************************************************************\n");
1786 outs.writeString("-->\n");
1787 outs.writeString("\n");
1788 outs.writeString("<office:document-styles\n");
1789 outs.writeString(" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
1790 outs.writeString(" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");
1791 outs.writeString(" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");
1792 outs.writeString(" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");
1793 outs.writeString(" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");
1794 outs.writeString(" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");
1795 outs.writeString(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
1796 outs.writeString(" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
1797 outs.writeString(" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
1798 outs.writeString(" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");
1799 outs.writeString(" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
1800 outs.writeString(" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");
1801 outs.writeString(" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");
1802 outs.writeString(" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");
1803 outs.writeString(" xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");
1804 outs.writeString(" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");
1805 outs.writeString(" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");
1806 outs.writeString(" xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
1807 outs.writeString(" xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");
1808 outs.writeString(" xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");
1809 outs.writeString(" xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");
1810 outs.writeString(" xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");
1811 outs.writeString(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
1812 outs.writeString(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
1813 outs.writeString(" xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
1814 outs.writeString(" xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
1815 outs.writeString(" office:version=\"1.0\">\n");
1816 outs.writeString("\n");
1817 outs.writeString("<!--\n");
1818 outs.writeString("*************************************************************************\n");
1819 outs.writeString(" S T Y L E S\n");
1820 outs.writeString(" Style entries have been pulled from the svg style and\n");
1821 outs.writeString(" representation attributes in the SVG tree. The tree elements\n");
1822 outs.writeString(" then refer to them by name, in the ODF manner\n");
1823 outs.writeString("*************************************************************************\n");
1824 outs.writeString("-->\n");
1825 outs.writeString("\n");
1826 outs.writeString("<office:styles>\n");
1827 outs.writeString("\n");
1828
1829 return true;
1830}
1831
1832
1837{
1838 outs.writeString("\n");
1839 outs.writeString("</office:styles>\n");
1840 outs.writeString("\n");
1841 outs.writeString("<office:automatic-styles>\n");
1842 outs.writeString("<!-- ####### 'Standard' styles ####### -->\n");
1843 outs.writeString("<style:style style:name=\"dp1\" style:family=\"drawing-page\"/>\n");
1844 outs.writeString("<style:style style:name=\"standard\" style:family=\"graphic\">\n");
1845
1847
1848 outs.writeString("</style:style>\n");
1849 outs.writeString("<style:style style:name=\"gr1\" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
1850 outs.writeString(" <style:graphic-properties draw:stroke=\"none\" draw:fill=\"none\"\n");
1851 outs.writeString(" draw:textarea-horizontal-align=\"center\"\n");
1852 outs.writeString(" draw:textarea-vertical-align=\"middle\" draw:color-mode=\"standard\"\n");
1853 outs.writeString(" draw:luminance=\"0%\" draw:contrast=\"0%\" draw:gamma=\"100%\" draw:red=\"0%\"\n");
1854 outs.writeString(" draw:green=\"0%\" draw:blue=\"0%\" fo:clip=\"rect(0cm 0cm 0cm 0cm)\"\n");
1855 outs.writeString(" draw:image-opacity=\"100%\" style:mirror=\"none\"/>\n");
1856 outs.writeString("</style:style>\n");
1857 outs.writeString("<style:style style:name=\"P1\" style:family=\"paragraph\">\n");
1858 outs.writeString(" <style:paragraph-properties fo:text-align=\"center\"/>\n");
1859 outs.writeString("</style:style>\n");
1860 outs.writeString("</office:automatic-styles>\n");
1861 outs.writeString("\n");
1862 outs.writeString("<office:master-styles>\n");
1863 outs.writeString("<draw:layer-set>\n");
1864 outs.writeString(" <draw:layer draw:name=\"layout\"/>\n");
1865 outs.writeString(" <draw:layer draw:name=\"background\"/>\n");
1866 outs.writeString(" <draw:layer draw:name=\"backgroundobjects\"/>\n");
1867 outs.writeString(" <draw:layer draw:name=\"controls\"/>\n");
1868 outs.writeString(" <draw:layer draw:name=\"measurelines\"/>\n");
1869 outs.writeString("</draw:layer-set>\n");
1870 outs.writeString("\n");
1871 outs.writeString("<style:master-page style:name=\"Default\"\n");
1872 outs.writeString(" style:page-master-name=\"PM1\" draw:style-name=\"dp1\"/>\n");
1873 outs.writeString("</office:master-styles>\n");
1874 outs.writeString("\n");
1875 outs.writeString("</office:document-styles>\n");
1876
1877 return true;
1878}
1879
1880
1885{
1886 time_t tim;
1887 time(&tim);
1888
1889 outs.writeString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1890 outs.writeString("\n");
1891 outs.writeString("<!--\n");
1892 outs.writeString("*************************************************************************\n");
1893 outs.writeString(" file: content.xml\n");
1894 outs.printf (" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
1895 outs.writeString(" http://www.inkscape.org\n");
1896 outs.writeString("*************************************************************************\n");
1897 outs.writeString("-->\n");
1898 outs.writeString("\n");
1899 outs.writeString("<office:document-content\n");
1900 outs.writeString(" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
1901 outs.writeString(" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");
1902 outs.writeString(" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");
1903 outs.writeString(" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");
1904 outs.writeString(" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");
1905 outs.writeString(" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");
1906 outs.writeString(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
1907 outs.writeString(" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
1908 outs.writeString(" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
1909 outs.writeString(" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");
1910 outs.writeString(" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
1911 outs.writeString(" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");
1912 outs.writeString(" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");
1913 outs.writeString(" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");
1914 outs.writeString(" xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");
1915 outs.writeString(" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");
1916 outs.writeString(" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");
1917 outs.writeString(" xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
1918 outs.writeString(" xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");
1919 outs.writeString(" xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");
1920 outs.writeString(" xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");
1921 outs.writeString(" xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");
1922 outs.writeString(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
1923 outs.writeString(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
1924 outs.writeString(" xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
1925 outs.writeString(" xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
1926 outs.writeString(" office:version=\"1.0\">\n");
1927 outs.writeString("<office:scripts/>\n");
1928 outs.writeString("\n");
1929 outs.writeString("<!--\n");
1930 outs.writeString("*************************************************************************\n");
1931 outs.writeString(" D R A W I N G\n");
1932 outs.writeString(" This section is the heart of SVG-ODF conversion. We are\n");
1933 outs.writeString(" starting with simple conversions, and will slowly evolve\n");
1934 outs.writeString(" into a 'smarter' translation as time progresses. Any help\n");
1935 outs.writeString(" in improving .odg export is welcome.\n");
1936 outs.writeString("*************************************************************************\n");
1937 outs.writeString("-->\n");
1938 outs.writeString("\n");
1939 outs.writeString("<office:body>\n");
1940 outs.writeString("<office:drawing>\n");
1941 outs.writeString("<draw:page draw:name=\"page1\" draw:style-name=\"dp1\"\n");
1942 outs.writeString(" draw:master-page-name=\"Default\">\n");
1943 outs.writeString("\n");
1944 return true;
1945}
1946
1947
1952{
1953 outs.writeString("\n");
1954 outs.writeString("</draw:page>\n");
1955 outs.writeString("</office:drawing>\n");
1956 outs.writeString("\n");
1957 outs.writeString("<!-- ######### CONVERSION FROM SVG ENDS ######## -->\n");
1958 outs.writeString("\n");
1959 outs.writeString("</office:body>\n");
1960 outs.writeString("</office:document-content>\n");
1961 return true;
1962}
1963
1964
1970{
1971 //Content.xml stream
1972 BufferOutputStream cbouts;
1973 OutputStreamWriter couts(cbouts);
1974
1975 if (!writeContentHeader(couts))
1976 {
1977 return false;
1978 }
1979
1980 //Style.xml stream
1981 BufferOutputStream sbouts;
1982 OutputStreamWriter souts(sbouts);
1983
1984 if (!writeStyleHeader(souts))
1985 {
1986 return false;
1987 }
1988
1989 //# Descend into the tree, doing all of our conversions
1990 //# to both files at the same time
1991 char *oldlocale = g_strdup (setlocale (LC_NUMERIC, nullptr));
1992 setlocale (LC_NUMERIC, "C");
1993 if (!writeTree(couts, souts, doc, doc->getReprRoot()))
1994 {
1995 g_warning("Failed to convert SVG tree");
1996 setlocale (LC_NUMERIC, oldlocale);
1997 g_free (oldlocale);
1998 return false;
1999 }
2000 setlocale (LC_NUMERIC, oldlocale);
2001 g_free (oldlocale);
2002
2003 //# Finish content file
2004 if (!writeContentFooter(couts))
2005 {
2006 return false;
2007 }
2008
2009 ZipEntry *ze = zf.newEntry("content.xml", "ODF master content file");
2010 ze->setUncompressedData(cbouts.getBuffer());
2011 ze->finish();
2012
2013 //# Finish style file
2014 if (!writeStyleFooter(souts))
2015 {
2016 return false;
2017 }
2018
2019 ze = zf.newEntry("styles.xml", "ODF style file");
2020 ze->setUncompressedData(sbouts.getBuffer());
2021 ze->finish();
2022
2023 return true;
2024}
2025
2026
2031{
2032 metadata.clear();
2033 styleTable.clear();
2034 styleLookupTable.clear();
2035 gradientTable.clear();
2036 gradientLookupTable.clear();
2037 imageTable.clear();
2038}
2039
2040
2044void OdfOutput::save(Inkscape::Extension::Output */*mod*/, SPDocument *doc, gchar const *filename)
2045{
2046 reset();
2047
2049
2050 ZipFile zf;
2051 preprocess(zf, doc, doc->getReprRoot());
2052
2053 if (!writeManifest(zf))
2054 {
2055 g_warning("Failed to write manifest");
2056 return;
2057 }
2058
2059 if (!writeContent(zf, doc))
2060 {
2061 g_warning("Failed to write content");
2062 return;
2063 }
2064
2065 if (!writeMeta(zf))
2066 {
2067 g_warning("Failed to write metafile");
2068 return;
2069 }
2070
2071 if (!zf.writeFile(filename))
2072 {
2073 return;
2074 }
2075}
2076
2077
2084{
2085 // clang-format off
2087 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
2088 "<name>" N_("OpenDocument Drawing Output") "</name>\n"
2089 "<id>org.inkscape.output.odf</id>\n"
2090 "<output>\n"
2091 "<extension>.odg</extension>\n"
2092 "<mimetype>text/x-povray-script</mimetype>\n"
2093 "<filetypename>" N_("OpenDocument drawing (*.odg)") "</filetypename>\n"
2094 "<filetypetooltip>" N_("OpenDocument drawing file") "</filetypetooltip>\n"
2095 "</output>\n"
2096 "</inkscape-extension>",
2097 std::make_unique<OdfOutput>());
2098 // clang-format on
2099}
2100
2105{
2106 /* We don't need a Key
2107 if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_POV))
2108 return false;
2109 */
2110
2111 return true;
2112}
2113
2114} //namespace Inkscape::Extension::Internal
2115
2116
2117//########################################################################
2118//# E N D O F F I L E
2119//########################################################################
2120
2121/*
2122 Local Variables:
2123 mode:c++
2124 c-file-style:"stroustrup"
2125 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
2126 indent-tabs-mode:nil
2127 fill-column:99
2128 End:
2129*/
2130// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Abstract curve type.
double scale
Definition aa.cpp:228
3x3 affine transformation matrix.
Lookup dictionary for attributes/properties.
Bezier curve.
Phoebe DOM Implementation.
Hand-rolled LLVM-style RTTI system for class hierarchies where dynamic_cast isn't fast enough.
3x3 matrix representing an affine transformation.
Definition affine.h:70
bool isIdentity(Coord eps=EPSILON) const
Check whether this matrix is an identity matrix.
Definition affine.cpp:109
Affine inverse() const
Compute the inverse matrix.
Definition affine.cpp:388
Bezier curve with compile-time specified order.
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Sequence of subpaths.
Definition pathvector.h:122
Two-dimensional point that doubles as a vector.
Definition point.h:66
constexpr Coord y() const noexcept
Definition point.h:106
constexpr Coord x() const noexcept
Definition point.h:104
Scaling from the origin.
Definition transforms.h:150
Translation by a vector.
Definition transforms.h:115
The object that is the basis for the Extension system.
Definition extension.h:133
std::vector< GradientStop > stops
Definition odf.h:235
bool equals(const GradientInfo &other)
Definition odf.h:194
bool check(Inkscape::Extension::Extension *module) override
Make sure that we are in the database.
Definition odf.cpp:2104
bool writeContentHeader(Writer &outs)
Write the header for the content.xml file.
Definition odf.cpp:1884
std::map< Glib::ustring, Glib::ustring > styleLookupTable
Definition odf.h:281
std::map< Glib::ustring, Glib::ustring > imageTable
Definition odf.h:291
std::map< Glib::ustring, Glib::ustring > gradientLookupTable
Definition odf.h:286
void save(Inkscape::Extension::Output *mod, SPDocument *doc, char const *filename) override
Descends into the SVG tree, mapping things to ODF when appropriate.
Definition odf.cpp:2044
void preprocess(ZipFile &zf, SPDocument *doc, Inkscape::XML::Node *node)
FIRST PASS.
Definition odf.cpp:994
bool writeContentFooter(Writer &outs)
Write the footer for the content.xml file.
Definition odf.cpp:1951
bool processStyle(SPItem *item, const Glib::ustring &id, const Glib::ustring &gradientNameFill, const Glib::ustring &gradientNameStroke, Glib::ustring &output)
Definition odf.cpp:1274
std::vector< GradientInfo > gradientTable
Definition odf.h:288
void reset()
Resets class to its pristine condition, ready to use again.
Definition odf.cpp:2030
bool writeManifest(ZipFile &zf)
Writes the manifest.
Definition odf.cpp:1066
bool writeTree(Writer &couts, Writer &souts, SPDocument *doc, Inkscape::XML::Node *node)
SECOND PASS.
Definition odf.cpp:1566
std::vector< StyleInfo > styleTable
Definition odf.h:283
bool writeMeta(ZipFile &zf)
This writes the document meta information to meta.xml.
Definition odf.cpp:1124
std::map< Glib::ustring, Glib::ustring > metadata
Definition odf.h:272
static void init()
This is the definition of PovRay output.
Definition odf.cpp:2083
bool writeStyleHeader(Writer &outs)
Write the header for the content.xml file.
Definition odf.cpp:1773
bool writeContent(ZipFile &zf, SPDocument *doc)
Write the content.xml file.
Definition odf.cpp:1969
bool processGradient(SPItem *item, const Glib::ustring &id, Geom::Affine &tf, Glib::ustring &gradientName, Glib::ustring &output, bool checkFillGradient=true)
Definition odf.cpp:1400
bool writeStyleFooter(Writer &outs)
Write the footer for the style.xml file.
Definition odf.cpp:1836
bool equals(const StyleInfo &other)
Definition odf.h:85
Writer & printf(char const *fmt,...) override G_GNUC_PRINTF(2
Provide printf()-like formatting.
Writer & writeString(const char *str) override
Writes the specified character string to this output writer.
Writer & writeUString(const Glib::ustring &val) override
Writes the specified unicode string to this output writer.
This class is for sending a stream to a character buffer.
virtual std::vector< unsigned char > & getBuffer()
Class for placing a Writer on an open OutputStream.
void close() override
Close the underlying OutputStream.
This class is for sending a stream to a Glib::ustring.
virtual Glib::ustring & getString()
This interface and its descendants are for unicode character-oriented output.
virtual Writer & printf(char const *fmt,...) G_GNUC_PRINTF(2
virtual Writer & writeString(const char *str)=0
virtual Writer & writeUString(const Glib::ustring &val)=0
Represents an URI as per RFC 2396.
Definition uri.h:36
static URI from_dirname(char const *path)
URI of a local directory.
Definition uri.cpp:197
std::string str(char const *baseuri=nullptr) const
Return the string representation of this URI.
Definition uri.cpp:281
Interface for refcounted XML nodes.
Definition node.h:80
virtual Node * next()=0
Get the next sibling of this node.
virtual char const * name() const =0
Get the name of the element node.
virtual Node * firstChild()=0
Get the first child of this node.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
virtual char const * content() const =0
Get the content of a text or comment node.
virtual NodeType type() const =0
Get the type of the node.
Wrapper around a Geom::PathVector object.
Definition curve.h:26
Typed SVG document implementation.
Definition document.h:102
SPRoot * getRoot()
Returns our SPRoot.
Definition document.h:201
char const * getDocumentBase() const
Definition document.h:234
Inkscape::XML::Node * getReprRoot()
Definition document.h:207
SPObject * getObjectByRepr(Inkscape::XML::Node *repr) const
Gradient.
Definition sp-gradient.h:86
SPStop * getFirstStop()
SPGradient * getVector(bool force_private=false)
Returns private vector of given gradient (the gradient at the end of the href chain which has stops),...
Base class for visual SVG elements.
Definition sp-item.h:109
Geom::OptRect documentVisualBounds() const
Get item's visual bbox in document coordinate system.
Definition sp-item.cpp:1005
Geom::Affine i2doc_affine() const
Returns the accumulated transformation of the item and all its ancestors, including root's viewport.
Definition sp-item.cpp:1803
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
SPDocument * document
Definition sp-object.h:188
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
Definition sp-object.h:248
Gradient stop.
Definition sp-stop.h:31
SPStop * getNextStop()
Virtual write: write object attributes to repr.
Definition sp-stop.cpp:98
An SVG style object.
Definition style.h:45
T< SPAttr::FILL, SPIPaint > fill
fill
Definition style.h:240
T< SPAttr::STROKE, SPIPaint > stroke
stroke
Definition style.h:247
T< SPAttr::STROKE_WIDTH, SPILength > stroke_width
stroke-width
Definition style.h:249
T< SPAttr::FILL_OPACITY, SPIScale24 > fill_opacity
fill-opacity
Definition style.h:242
T< SPAttr::STROKE_OPACITY, SPIScale24 > stroke_opacity
stroke-opacity
Definition style.h:261
Geom::Affine c2p
Definition viewbox.h:43
virtual void finish()
Definition ziptool.cpp:2067
virtual void setUncompressedData(const std::vector< unsigned char > &val)
Definition ziptool.cpp:2028
This class sits over the zlib and gzip code to implement a PKWare or Info-Zip .zip file reader and wr...
Definition ziptool.h:395
virtual bool writeFile(const std::string &fileName)
Definition ziptool.cpp:2437
virtual ZipEntry * newEntry(const std::string &fileNameArg, const std::string &commentArg)
Definition ziptool.cpp:2260
A way to clear the N_ macro, which is defined as an inline function.
Integral and real coordinate types and some basic utilities.
Css & result
double c[8][4]
unsigned int guint32
Inkscape::Extension::Extension: Frontend to certain, possibly pluggable, actions.
Specific curve type functions for Inkscape, not provided by lib2geom.
bool is_straight_curve(Geom::BezierCurve const &c)
Definition geom-curves.h:22
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
T pow(T const &t, int n)
Integer exponentiation for transforms.
Definition transforms.h:98
Geom::PathVector pathv_to_linear_and_cubic_beziers(Geom::PathVector const &pathv)
Definition geom.cpp:588
Specific geometry functions for Inkscape, not provided my lib2geom.
SPItem * item
Inkscape::XML::Node * node
Mini static library that contains the version of Inkscape.
TODO: insert short description here.
void shift(T &a, T &b, T const &c)
SBasisN< n > sqrt(SBasisN< n > const &a, int k)
Inkscape::IO::OutputStreamWriter OutputStreamWriter
Definition odf.cpp:91
static void gatherText(Inkscape::XML::Node *node, Glib::ustring &buf)
Definition odf.cpp:971
static Glib::ustring formatTransform(Geom::Affine &tf)
Definition odf.cpp:890
static int writePath(Writer &outs, Geom::PathVector const &pathv, Geom::Affine const &tf, double xoff, double yoff)
Writes an SVG path as an ODF <draw:path> and returns the number of points written.
Definition odf.cpp:1221
static double svd_hypot(double a, double b)
Definition odf.cpp:344
static void analyzeTransform(Geom::Affine &tf, double &rotate, double &, double &, double &xscale, double &yscale)
Get some fun facts from the transform.
Definition odf.cpp:948
static Geom::Affine getODFItemTransform(const SPItem *item)
Get the transform for an item, including parents, but without root viewBox transformation.
Definition odf.cpp:937
Inkscape::IO::StringOutputStream StringOutputStream
Definition odf.cpp:92
static Geom::Affine getODFTransform(const SPItem *item)
Get the general transform from SVG pixels to ODF cm.
Definition odf.cpp:909
static Glib::ustring getAttribute(Inkscape::XML::Node *node, char const *attrName)
Get the value of a node/attribute pair.
Definition odf.cpp:880
static Geom::OptRect getODFBoundingBox(const SPItem *item)
Get the bounding box of an item, as mapped onto an ODF document, in cm.
Definition odf.cpp:922
Inkscape::IO::BufferOutputStream BufferOutputStream
Definition odf.cpp:90
Extension support.
void build_from_mem(gchar const *buffer, std::unique_ptr< Implementation::Implementation > in_imp)
Create a module from a buffer holding an XML description.
Definition system.cpp:471
Glib::ustring get_file_extension(Glib::ustring const &path)
Definition sys.cpp:214
@ TEXT_NODE
Text node, e.g. "Some text" in <group>Some text</group> is represented by a text node.
char const * version_string
full version string
int n
Definition spiro.cpp:66
OpenDocument (drawing) input and output.
PathVector - a sequence of subpaths.
int size
int buf
Singleton class to access the preferences file in a convenient way.
unsigned long gs
Definition quantize.cpp:38
Ocnode * child[8]
Definition quantize.cpp:33
TODO: insert short description here.
SVG <image> implementation.
Some things pertinent to all visible shapes: SPItem, SPItemView, SPItemCtx.
TODO: insert short description here.
double sum(const double alpha[16], const double &x, const double &y)
TODO: insert short description here.
SPRoot: SVG <svg> implementation.
TODO: insert short description here.
Definition curve.h:24
SPStyle internal: classes that are internal to SPStyle.
SPStyle - a style object for SPItem objects.
int index
Inkscape::Text::Layout const * te_get_layout(SPItem const *item)
Glib::ustring name
Definition toolbars.cpp:55
void init(int argc, char **argv, Toy *t, int width=600, int height=600)
Affine transformation classes.
Interface for XML nodes.
TODO: insert short description here.