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
|
#include <config.h>
#ifdef ENABLE_SVG
#include <stdlib.h> /* For abort() */
#include "msg.h"
#include "image.hh"
#include "cache.h"
#include "dicache.h"
#define NANOSVG_ALL_COLOR_KEYWORDS
#define NANOSVG_IMPLEMENTATION
#include "nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvgrast.h"
typedef struct {
DilloImage *Image; /* Image meta data */
DilloUrl *url; /* Primary Key for the dicache */
int version; /* Secondary Key for the dicache */
int bgcolor; /* Parent widget background color */
} DilloSvg;
/*
* Free up the resources for this image.
*/
static void Svg_free(DilloSvg *svg)
{
_MSG("Svg_free: svg=%p\n", svg);
dFree(svg);
}
/*
* Finish the decoding process (and free the memory)
*/
static void Svg_close(DilloSvg *svg, CacheClient_t *Client)
{
_MSG("Svg_close\n");
/* Let dicache know decoding is over */
a_Dicache_close(svg->url, svg->version, Client);
Svg_free(svg);
}
/*
* Receive and process new chunks of SVG image data
*/
static void Svg_write(DilloSvg *svg, void *Buf, uint_t BufSize)
{
uint_t i, j, width, height;
static NSVGrasterizer *rasterizer = NULL;
if (!rasterizer)
rasterizer = nsvgCreateRasterizer();
dReturn_if_fail ( Buf != NULL && BufSize > 0 );
dReturn_if_fail (strstr(Buf, "</svg>"));
char *str = dStrndup(Buf, BufSize); /* 1. nsvg is said to modify the string. 2. it needs it null-terminated, and I don't remember right now whether Buf happens to be */
/* TODO: Use FLTK reported DPI value */
NSVGimage *nimg = nsvgParse(str, "px", 96);
dFree(str);
/* guess what? The height and width values that come back can be nonintegral */
width = ceil(nimg->width);
height = ceil(nimg->height);
if (width == 0 || height == 0 || width > IMAGE_MAX_AREA / height) {
MSG_WARN("Svg_write: suspicious image size request %u x %u\n", width, height);
nsvgDelete(nimg);
return;
}
const DilloImgType type = DILLO_IMG_TYPE_RGB;
const uint_t stride = width * 4;
a_Dicache_set_parms(svg->url, svg->version, svg->Image, width, height,
type, 1 / 2.2);
/* is there any sort of gamma to deal with at all? Not aware of any. */
unsigned char *dest = dNew(unsigned char, height * stride);
nsvgRasterizeXY(rasterizer, nimg, 0, 0, 1, 1, dest, width, height, stride);
uint_t bg_blue = (svg->bgcolor) & 0xFF;
uint_t bg_green = (svg->bgcolor>>8) & 0xFF;
uint_t bg_red = (svg->bgcolor>>16) & 0xFF;
unsigned char *line = dNew(unsigned char, width * 3);
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
uchar_t r = dest[i * stride + 4 * j];
uchar_t g = dest[i * stride + 4 * j + 1];
uchar_t b = dest[i * stride + 4 * j + 2];
uchar_t alpha = dest[i * stride + 4 * j + 3];
if (i * stride + 4 * j + 3 >= height * stride) {
MSG_ERR("height %f i %d width %f j %d stride %d size %d here %d\n", nimg->height, i, nimg->width, j, stride, height * stride, i * stride + 4 * j + 3);
}
line[3 * j] = (r * alpha + (bg_red * (0xFF - alpha))) / 0xFF;
line[3 * j + 1] = (g * alpha + (bg_green * (0xFF - alpha))) / 0xFF;
line[3 * j + 2] = (b * alpha + (bg_blue * (0xFF - alpha))) / 0xFF;
}
a_Dicache_write(svg->url, svg->version, line, i);
}
dFree(dest);
dFree(line);
nsvgDelete(nimg);
}
void a_Svg_callback(int Op, void *data)
{
if (Op == CA_Send) {
CacheClient_t *Client = data;
Svg_write(Client->CbData, Client->Buf, Client->BufSize);
} else if (Op == CA_Close) {
CacheClient_t *Client = data;
Svg_close(Client->CbData, Client);
} else if (Op == CA_Abort) {
Svg_free(data);
}
}
/*
* Create the image state data that must be kept between calls
*/
void *a_Svg_new(DilloImage *Image, DilloUrl *url, int version)
{
DilloSvg *svg = dNew0(DilloSvg, 1);
_MSG("a_Svg_new: svg=%p\n", svg);
svg->Image = Image;
svg->url = url;
svg->version = version;
svg->bgcolor = Image->bg_color;
return svg;
}
#else /* ENABLE_SVG */
void *a_Svg_new() { return 0; }
void a_Svg_callback() { return; }
#endif /* ENABLE_SVG */
|