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
|
/* See LICENSE file for copyright and license details. */
#include "common.h"
#include <string.h>
static uint8_t
unpremultiply(double colour, double alpha)
{
if (colour <= 0.04045)
colour = colour / 12.92;
else
colour = pow((colour + 0.055) / 1.055, 2.4);
colour /= alpha;
if (colour <= 0.0031308)
colour = 12.92 * colour;
else
colour = fma(1.055, pow(colour, 1.0 / 2.4), -0.055);
colour = fma(255.0, colour, 0.5);
if (colour <= 0.0)
return 0u;
if (colour >= 255.0)
return 255u;
return (uint8_t)colour;
}
GdkPixbuf *
rasterise(RsvgHandle *vector, int width, int height)
{
RsvgRectangle viewport = {0.0, 0.0, width, height};
cairo_surface_t *surface = NULL;
cairo_t *cr = NULL;
GdkPixbuf *image;
int x, y, sstride, dstride;
const uint8_t *s, *sy;
uint8_t *d, *dy;
double a, r, g, b;
uint32_t pixel;
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
goto fail;
cr = cairo_create(surface);
if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
goto fail;
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
if (!rsvg_handle_render_document(vector, cr, &viewport, NULL))
goto fail;
cairo_destroy(cr);
cr = NULL;
image = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 1, 8, width, height);
if (!image)
goto fail;
/* TODO accelerate */
cairo_surface_flush(surface);
sy = s = cairo_image_surface_get_data(surface);
dy = d = gdk_pixbuf_get_pixels(image);
sstride = cairo_image_surface_get_stride(surface);
dstride = gdk_pixbuf_get_rowstride(image);
for (y = 0; y < height; y++, sy = s = &s[sstride], dy = d = &d[dstride]) {
for (x = 0; x < width; x++, sy = &sy[4u], dy = &dy[4u]) {
memcpy(&pixel, sy, 4u);
if ((uint8_t)(pixel >> 24)) {
a = (double)(uint8_t)(pixel >> 24) / 255.0;
r = (double)(uint8_t)(pixel >> 16) / 255.0;
g = (double)(uint8_t)(pixel >> 8) / 255.0;
b = (double)(uint8_t)(pixel >> 0) / 255.0;
dy[0] = unpremultiply(r, a);
dy[1] = unpremultiply(g, a);
dy[2] = unpremultiply(b, a);
dy[3] = (uint8_t)(pixel >> 24);
} else {
dy[0] = dy[1] = dy[2] = dy[3] = 0u;
}
}
}
cairo_surface_destroy(surface);
return image;
fail:
if (cr)
cairo_destroy(cr);
if (surface)
cairo_surface_destroy(surface);
return NULL;
}
void
paint_image(cairo_t *cr, struct image *image)
{
RsvgRectangle viewport = {0.0, 0.0, image->width, image->height};
int rendered;
if (image->vector) {
cairo_save(cr);
if (image->has_transformer)
cairo_transform(cr, &image->transformer);
rendered = rsvg_handle_render_document(image->vector, cr, &viewport, NULL);
cairo_restore(cr);
if (rendered)
return;
}
if (image->raster) {
gdk_cairo_set_source_pixbuf(cr, image->raster, 0.0, 0.0);
cairo_paint(cr);
}
}
|