libxputty 0.1
Loading...
Searching...
No Matches
xsvgloader.c
Go to the documentation of this file.
1#include <assert.h>
2
3#include <stdio.h>
4#include <string.h>
5#include <math.h>
6
7#include "cairo/cairo.h"
8
9#define NANOSVG_ALL_COLOR_KEYWORDS
10#define NANOSVG_IMPLEMENTATION
11#include "nanosvg.h"
12#include "xsvgloader.h"
13#include "b64_encode.h"
14
15#ifndef min
16#define min(x, y) (((x) < (y)) ? (x) : (y))
17#endif
18
19
20static inline void to_rgba(double*a, unsigned int const c) {
21 a[0] = (c & 0xff) / 255.;
22 a[1] = ((c >> 8) & 0xff) / 255.;
23 a[2] = ((c >> 16) & 0xff) / 255.;
24 a[3] = ((c >> 24) & 0xff) / 255.;
25}
26
27static inline void inverse(double*a, float const* const t) {
28 double const invdet = (1. / ((double)(t[0]) * t[3] - (double)(t[2]) * t[1]));
29
30 a[0] = t[3] * invdet;
31 a[1] = -t[1] * invdet;
32 a[2] = -t[2] * invdet;
33 a[3] = t[0] * invdet;
34 a[4] = ((double)(t[2]) * t[5] - (double)(t[3]) * t[4]) * invdet;
35 a[5] = ((double)(t[1]) * t[4] - (double)(t[0]) * t[5]) * invdet;
36}
37
38static inline void draw_stroke(struct NSVGshape* const shape, cairo_t* const cr) {
39 switch (shape->stroke.type) {
40 case NSVG_PAINT_NONE:
41 break;
42
44 {
45 double c[4]= {0};
46 to_rgba(c, shape->stroke.color);
47 cairo_set_source_rgba(cr, c[0], c[1], c[2], shape->opacity * c[3]);
48
49 int const count = shape->strokeDashCount;
50 if (count) {
51 double dashes[sizeof(shape->strokeDashArray) / sizeof(*shape->strokeDashArray)];
52 memcpy(dashes, shape->strokeDashArray, sizeof(*shape->strokeDashArray + count));
53 cairo_set_dash(cr, dashes, shape->strokeDashCount, shape->strokeDashOffset);
54 }
55 }
56
57 switch (shape->strokeLineCap) {
58 case NSVG_CAP_BUTT:
59 cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
60 break;
61
62 case NSVG_CAP_ROUND:
63 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
64 break;
65
66 case NSVG_CAP_SQUARE:
67 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
68 break;
69
70 default:
71 cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
72 break;
73 //assert(0);
74 }
75
76 switch (shape->strokeLineJoin) {
77 case NSVG_JOIN_MITER:
78 cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
79 cairo_set_miter_limit(cr, shape->miterLimit);
80 break;
81
82 case NSVG_JOIN_ROUND:
83 cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
84 break;
85
86 case NSVG_JOIN_BEVEL:
87 cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL);
88 break;
89
90 default:
91 cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
92 cairo_set_miter_limit(cr, shape->miterLimit);
93 break;
94 //assert(0);
95 }
96 cairo_set_line_width(cr, shape->strokeWidth);
97 cairo_stroke_preserve(cr);
98 break;
99
100 default:
101 break;
102 //assert(0);
103 }
104}
105
106static inline void draw_svg_shape(cairo_t* const cr, struct NSVGshape* const shape) {
107 cairo_new_path(cr);
108
109 NSVGpath* path = shape->paths;
110 for (; path; path = path->next) {
111 float* p = path->pts;
112 //cairo_new_sub_path(cr);
113 cairo_move_to(cr, p[0], p[1]);
114 float* const end = (p + 2 * path->npts);
115 for (p += 2; end != p; p += 6) {
116 cairo_curve_to(cr, p[0], p[1], p[2], p[3], p[4], p[5]);
117 }
118 if (path->closed) {
119 cairo_close_path(cr);
120 }
121 }
122
123 // fill
124 int const type = shape->fill.type;
125 switch (type) {
126 case NSVG_PAINT_NONE:
127 break;
128
129 case NSVG_PAINT_COLOR:
132 {
133 switch (shape->fillRule) {
135 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
136 break;
137
139 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
140 break;
141
142 default:
143 assert(0);
144 }
145 cairo_pattern_t* pat = {0};
146
147 switch (type) {
148 case NSVG_PAINT_COLOR:
149 {
150 double c[4] = {0};
151 to_rgba(c, shape->fill.color);
152 cairo_set_source_rgba(cr, c[0], c[1], c[2], shape->opacity * c[3]);
153 cairo_fill_preserve(cr);
154 draw_stroke(shape, cr);
155 return;
156 }
157
159 {
160 double t[6] = {0};
161 inverse(t, shape->fill.gradient->xform);
162 pat = cairo_pattern_create_linear(t[4], t[5], t[4] + t[2], t[5] + t[3]);
163 break;
164 }
165
167 {
168 NSVGgradient* g = shape->fill.gradient;
169 double t[6] = {0};
170 inverse(t, g->xform);
171 double const r = t[0];
172 pat = cairo_pattern_create_radial(g->fx * -r, g->fy * -r, 0., t[4], t[5], r);
173 break;
174 }
175
176 default:
177 assert(0);
178 }
179
180 assert(pat);
181 NSVGgradient* g = shape->fill.gradient;
182
183 switch (g->spread) {
184 case NSVG_SPREAD_PAD:
185 cairo_pattern_set_extend(pat, CAIRO_EXTEND_PAD);
186 break;
187
189 cairo_pattern_set_extend(pat, CAIRO_EXTEND_REFLECT);
190 break;
191
193 cairo_pattern_set_extend(pat, CAIRO_EXTEND_REPEAT);
194 break;
195
196 default:
197 assert(0);
198 }
199
200 int const ns = g->nstops;
201 for (int i = 0; ns != i; ++i) {
202 NSVGgradientStop stop = g->stops[i];
203 double c[4] = {0};
204 to_rgba(c, stop.color);
205 cairo_pattern_add_color_stop_rgba(pat, stop.offset,
206 c[0], c[1], c[2], shape->opacity * c[3]);
207 }
208 cairo_set_source(cr, pat);
209 cairo_fill_preserve(cr);
210 cairo_pattern_destroy(pat);
211 break;
212 }
213
214 default:
215 assert(0);
216 }
217 draw_stroke(shape, cr);
218}
219
220static void draw_svg_image(cairo_t* const cr, struct NSVGimage* const image,
221 double const w, double const h) {
222 double const sm = (min(w / image->width, h / image->height));
223 cairo_translate(cr, .5 * (w - sm * image->width), .5 * (h - sm * image->height));
224 cairo_scale(cr, sm, sm);
225 // draw shapes
226 NSVGshape* shape = image->shapes;
227 for (; shape; shape = shape->next) {
228 draw_svg_shape(cr, shape);
229 }
230}
231
232void draw_svg_image_to_pos(cairo_t* const cr, struct NSVGimage* const image,
233 double const x, double const y, double const w, double const h) {
234 cairo_save(cr);
235 double const sm = (min(w / image->width, h / image->height));
236 cairo_translate(cr, x + .5 * (w - sm * image->width), y + .5 * (h - sm * image->height));
237 cairo_scale(cr, sm, sm);
238 // draw shapes
239 NSVGshape* shape = image->shapes;
240 for (; shape; shape = shape->next) {
241 if (NSVG_FLAGS_VISIBLE & shape->flags) {
242 draw_svg_shape(cr, shape);
243 }
244 }
245 cairo_restore(cr);
246}
247
248void widget_get_svg(Widget_t *w, const char* name) {
249 char* b64dst;
250 b64dst = (char*)malloc((strlen(name)+1) * sizeof(char));
251 b64_decode((char*)name, b64dst);
252 struct NSVGimage* const image = nsvgParse(b64dst, "px", 96);
253
254 if (!image) return;
255 int width_t = image->width;
256 int height_t = image->height;
257 cairo_surface_destroy(w->image);
258 w->image = NULL;
259
260 w->image = cairo_surface_create_similar (w->surface,
261 CAIRO_CONTENT_COLOR_ALPHA, width_t, height_t);
262 cairo_t *cri = cairo_create (w->image);
263 draw_svg_image(cri, image, width_t, height_t);
264 nsvgDelete(image);
265 free(b64dst);
266 cairo_destroy(cri);
267}
268
269void widget_get_scaled_svg(Widget_t *w, const char* name) {
270 char* b64dst;
271 b64dst = (char*)malloc((strlen(name)+1) * sizeof(char));
272 b64_decode((char*)name, b64dst);
273 struct NSVGimage* const image = nsvgParse(b64dst, "px", 96);
274
275 if (!image) return;
276 int width = image->width;
277 int height = image->height;
278 int width_t = w->scale.init_width;
279 int height_t = w->scale.init_height;
280 double x = (double)width_t/(double)width;
281 double y = (double)height_t/(double)height;
282
283 cairo_surface_t *getsvg = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, width, height);
284 cairo_t *cris = cairo_create (getsvg);
285 draw_svg_image(cris, image, width, height);
286
287 cairo_surface_destroy(w->image);
288 w->image = NULL;
289 w->image = cairo_surface_create_similar (w->surface,
290 CAIRO_CONTENT_COLOR_ALPHA, width_t, height_t);
291 cairo_t *cri = cairo_create (w->image);
292
293 cairo_scale(cri, x,y);
294 cairo_set_source_surface (cri, getsvg,0,0);
295 cairo_paint (cri);
296
297 cairo_destroy(cris);
298 cairo_surface_destroy(getsvg);
299 nsvgDelete(image);
300 free(b64dst);
301 cairo_destroy(cri);
302}
303
304void widget_get_svg_from_file(Widget_t *w, const char* filename) {
305 struct NSVGimage* const image = nsvgParseFromFile(filename, "px", 96);
306
307 if (!image) return;
308 int width_t = w->scale.init_width;
309 int height_t = w->scale.init_height;
310 cairo_surface_destroy(w->image);
311 w->image = NULL;
312
313 w->image = cairo_surface_create_similar (w->surface,
314 CAIRO_CONTENT_COLOR_ALPHA, width_t, height_t);
315 cairo_t *cri = cairo_create (w->image);
316 draw_svg_image(cri, image, width_t, height_t);
317 nsvgDelete(image);
318 cairo_destroy(cri);
319}
320
321void widget_get_scaled_svg_from_file(Widget_t *w, const char* filename, int width_t, int height_t) {
322 struct NSVGimage* const image = nsvgParseFromFile(filename, "px", 96);
323
324 if (!image) return;
325 cairo_surface_destroy(w->image);
326 w->image = NULL;
327
328 w->image = cairo_surface_create_similar (w->surface,
329 CAIRO_CONTENT_COLOR_ALPHA, width_t, height_t);
330 cairo_t *cri = cairo_create (w->image);
331 draw_svg_image(cri, image, width_t, height_t);
332 nsvgDelete(image);
333 cairo_destroy(cri);
334}
335
336cairo_surface_t *cairo_image_surface_create_from_svg ( const char* filename) {
337 struct NSVGimage* const image = nsvgParseFromFile(filename, "px", 96);
338
339 if (!image) return NULL;
340 int width_t = image->width;
341 int height_t = image->height;
342
343 cairo_surface_t *getsvg = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, width_t, height_t);
344 cairo_t *cri = cairo_create (getsvg);
345 draw_svg_image(cri, image, width_t, height_t);
346 nsvgDelete(image);
347 return getsvg;
348}
void b64_decode(char *b64src, char *clrdst)
b64_decode - decode to a b64 based char
Definition b64_encode.c:26
NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic ...
NSVGimage * nsvgParseFromFile(const char *filename, const char *units, float dpi)
Definition nanosvg.h:2934
@ NSVG_FILLRULE_NONZERO
Definition nanosvg.h:101
@ NSVG_FILLRULE_EVENODD
Definition nanosvg.h:102
@ NSVG_CAP_SQUARE
Definition nanosvg.h:97
@ NSVG_CAP_BUTT
Definition nanosvg.h:95
@ NSVG_CAP_ROUND
Definition nanosvg.h:96
@ NSVG_FLAGS_VISIBLE
Definition nanosvg.h:106
@ NSVG_PAINT_NONE
Definition nanosvg.h:76
@ NSVG_PAINT_COLOR
Definition nanosvg.h:77
@ NSVG_PAINT_RADIAL_GRADIENT
Definition nanosvg.h:79
@ NSVG_PAINT_LINEAR_GRADIENT
Definition nanosvg.h:78
NSVGimage * nsvgParse(char *input, const char *units, float dpi)
Definition nanosvg.h:2910
void nsvgDelete(NSVGimage *image)
Definition nanosvg.h:2993
@ NSVG_SPREAD_REPEAT
Definition nanosvg.h:85
@ NSVG_SPREAD_PAD
Definition nanosvg.h:83
@ NSVG_SPREAD_REFLECT
Definition nanosvg.h:84
@ NSVG_JOIN_BEVEL
Definition nanosvg.h:91
@ NSVG_JOIN_ROUND
Definition nanosvg.h:90
@ NSVG_JOIN_MITER
Definition nanosvg.h:89
unsigned int color
Definition nanosvg.h:110
NSVGgradientStop stops[1]
Definition nanosvg.h:119
char spread
Definition nanosvg.h:116
float xform[6]
Definition nanosvg.h:115
float height
Definition nanosvg.h:162
NSVGshape * shapes
Definition nanosvg.h:163
float width
Definition nanosvg.h:161
NSVGgradient * gradient
Definition nanosvg.h:126
unsigned int color
Definition nanosvg.h:125
char type
Definition nanosvg.h:123
int npts
Definition nanosvg.h:133
char closed
Definition nanosvg.h:134
float * pts
Definition nanosvg.h:132
struct NSVGpath * next
Definition nanosvg.h:136
char strokeDashCount
Definition nanosvg.h:148
struct NSVGshape * next
Definition nanosvg.h:156
float miterLimit
Definition nanosvg.h:151
float opacity
Definition nanosvg.h:144
unsigned char flags
Definition nanosvg.h:153
char fillRule
Definition nanosvg.h:152
float strokeDashOffset
Definition nanosvg.h:146
NSVGpath * paths
Definition nanosvg.h:155
char strokeLineCap
Definition nanosvg.h:150
NSVGpaint stroke
Definition nanosvg.h:143
float strokeDashArray[8]
Definition nanosvg.h:147
char strokeLineJoin
Definition nanosvg.h:149
NSVGpaint fill
Definition nanosvg.h:142
float strokeWidth
Definition nanosvg.h:145
int init_height
Definition xwidget.h:355
int init_width
Definition xwidget.h:353
Widget_t - struct to hold the basic Widget_t info.
Definition xwidget.h:457
Resize_t scale
Definition xwidget.h:525
cairo_surface_t * image
Definition xwidget.h:491
cairo_surface_t * surface
Definition xwidget.h:483
void widget_get_scaled_svg(Widget_t *w, const char *name)
widget_get_scaled_svg - read svg scaled into Widget_t xlib surface
Definition xsvgloader.c:269
void widget_get_scaled_svg_from_file(Widget_t *w, const char *filename, int width_t, int height_t)
widget_get_scaled_svg_from_file - read svg into Widget_t xlib surface
Definition xsvgloader.c:321
cairo_surface_t * cairo_image_surface_create_from_svg(const char *filename)
Definition xsvgloader.c:336
void widget_get_svg_from_file(Widget_t *w, const char *filename)
widget_get_svg_from_file - read svg into Widget_t xlib surface
Definition xsvgloader.c:304
void draw_svg_image_to_pos(cairo_t *const cr, struct NSVGimage *const image, double const x, double const y, double const w, double const h)
Definition xsvgloader.c:232
void widget_get_svg(Widget_t *w, const char *name)
widget_get_svg - read svg into Widget_t xlib surface
Definition xsvgloader.c:248