summaryrefslogtreecommitdiff
path: root/src/modules/evas/vg_savers/svg/evas_vg_save_svg.c
blob: e900432d9aa409d4fe004bb869748712ff466161 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include "vg_common.h"

static int _evas_vg_saver_svg_log_dom = -1;

#ifdef ERR
# undef ERR
#endif
#define ERR(...) EINA_LOG_DOM_ERR(_evas_vg_saver_svg_log_dom, __VA_ARGS__)

#ifdef INF
# undef INF
#endif
#define INF(...) EINA_LOG_DOM_INFO(_evas_vg_saver_svg_log_dom, __VA_ARGS__)

static void
printf_style(Svg_Style_Property *style, Eina_Strbuf *buf)
{
   if ((style->fill.paint.r) || (style->fill.paint.g) || (style->fill.paint.b))
     eina_strbuf_append_printf(buf, " fill=\"#%02X%02X%02X\" ", style->fill.paint.r, style->fill.paint.g, style->fill.paint.b);
   if (style->fill.fill_rule == EFL_GFX_FILL_RULE_ODD_EVEN)
     eina_strbuf_append_printf(buf, " fill-rule=\"evenodd\" ");
   if (style->fill.opacity != 255)
     eina_strbuf_append_printf(buf, " fill-opacity=\"%f\"", style->fill.opacity / 255.0);
   if ((style->stroke.paint.r) || (style->stroke.paint.g) || (style->stroke.paint.b))
     eina_strbuf_append_printf(buf, " stroke=\"#%02X%02X%02X\" ", style->stroke.paint.r, style->stroke.paint.g, style->stroke.paint.b);
   if (style->stroke.width)
     eina_strbuf_append_printf(buf, " stroke-width=\"%f\" ", style->stroke.width);
   if (style->stroke.cap == EFL_GFX_CAP_ROUND)
     eina_strbuf_append_printf(buf, " stroke-linecap=\"round\" ");
   else if (style->stroke.cap == EFL_GFX_CAP_SQUARE)
     eina_strbuf_append_printf(buf, " stroke-linecap=\"square\" ");
}

static void
_svg_node_printf(Svg_Node *parent, Eina_Strbuf *buf)
{
   int i = 0;
   double *points;
   double last_x = 0, last_y = 0;
   Efl_Gfx_Path_Command *commands;
   Eina_List *l;
   Svg_Node *data;

   switch (parent->type)
     {
      case SVG_NODE_DOC:
         eina_strbuf_append_printf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
         eina_strbuf_append_printf(buf, "<svg viewBox=\"%f %f %f %f\" xmlns=\"http://www.w3.org/2000/svg\""
                " xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
                parent->node.doc.vx, parent->node.doc.vy,
                parent->node.doc.vw, parent->node.doc.vh);
         EINA_LIST_FOREACH(parent->child, l, data)
           {
              _svg_node_printf(data, buf);
           }
         eina_strbuf_append_printf(buf, "</svg>\n");
         break;
      case SVG_NODE_G:
         eina_strbuf_append_printf(buf, "<g");
         if (parent->transform)
           eina_strbuf_append_printf(buf,
                                     " transform=\"matrix(%f %f %f %f %f %f)\"",
                                     parent->transform->xx,
                                     parent->transform->yx,
                                     parent->transform->xy,
                                     parent->transform->yy,
                                     parent->transform->xz,
                                     parent->transform->yz);
         eina_strbuf_append_printf(buf, ">\n");
         EINA_LIST_FOREACH(parent->child, l, data)
           {
              _svg_node_printf(data, buf);
           }
         eina_strbuf_append_printf(buf, "</g>\n");
         break;
      case SVG_NODE_CUSTOME_COMMAND:
         points = parent->node.command.points;
         commands = parent->node.command.commands;
         eina_strbuf_append_printf(buf, "<path d=\"");
         for (i = 0; i < parent->node.command.commands_count; i++)
           {
              switch (commands[i])
                {
                 case EFL_GFX_PATH_COMMAND_TYPE_END:
                    eina_strbuf_append_printf(buf, "\"");
                    if (parent->transform)
                      eina_strbuf_append_printf(buf, " transform=\"matrix(%f %f %f %f %f %f)\"",
                             parent->transform->xx,
                             parent->transform->yx,
                             parent->transform->xy,
                             parent->transform->yy,
                             parent->transform->xz,
                             parent->transform->yz);
                    printf_style(parent->style, buf);
                    eina_strbuf_append_printf(buf, "/>\n");
                    break;
                 case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
                    eina_strbuf_append_printf(buf, "m%f,%f ", points[0] - last_x, points[1] - last_y);
                    last_x = points[0];
                    last_y = points[1];
                    points += 2;
                    break;
                 case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
                    eina_strbuf_append_printf(buf, "L%f,%f ", points[0], points[1]);
                    last_x = points[0];
                    last_y = points[1];
                    points += 2;
                    break;
                 case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
                    eina_strbuf_append_printf(buf, "c%f,%f %f,%f %f,%f ",
                           points[0] - last_x, points[1] - last_y,
                           points[2] - last_x, points[3] - last_y,
                           points[4] - last_x, points[5] - last_y);
                    last_x = points[4];
                    last_y = points[5];
                    points += 6;
                    break;
                 case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
                    eina_strbuf_append_printf(buf, " z ");
                    break;
                 case EFL_GFX_PATH_COMMAND_TYPE_LAST:
                 default:
                    break;
                }
           }
         break;
      default:
         break;
     }
}

Evas_Load_Error
evas_vg_save_file_svg(Vg_File_Data *evg_data, const char *file, const char *key EINA_UNUSED, int compress EINA_UNUSED)
{
   Eina_Strbuf *buf = NULL;
   Svg_Node *root;
   FILE *f = fopen(file, "w+");
   if (!f)
     {
        ERR("Cannot open file '%s' for SVG save", file);
        return EVAS_LOAD_ERROR_GENERIC;
     }

   root = vg_common_svg_create_svg_node(evg_data);
   buf = eina_strbuf_new();
   _svg_node_printf(root, buf);
   fprintf(f, "%s\n", eina_strbuf_string_get(buf));
   fclose(f);
   eina_strbuf_free(buf);

   return EVAS_LOAD_ERROR_NONE;
}

static Evas_Vg_Save_Func evas_vg_save_svg_func =
{
   evas_vg_save_file_svg
};

static int
module_open(Evas_Module *em)
{
   if (!em) return 0;
   em->functions = (void *)(&evas_vg_save_svg_func);
   _evas_vg_saver_svg_log_dom = eina_log_domain_register
     ("vg-save-svg", EVAS_DEFAULT_LOG_COLOR);
   if (_evas_vg_saver_svg_log_dom < 0)
     {
        EINA_LOG_ERR("Can not create a module log domain.");
        return 0;
     }
   return 1;
}

static void
module_close(Evas_Module *em EINA_UNUSED)
{
}

static Evas_Module_Api evas_modapi =
{
   EVAS_MODULE_API_VERSION,
   "svg",
   "none",
   {
     module_open,
     module_close
   }
};

EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_VG_SAVER, vg_saver, svg);

#ifndef EVAS_STATIC_BUILD_VG_SVG
EVAS_EINA_MODULE_DEFINE(vg_saver, svg);
#endif