Dillo v3.1.1-99-gf3103cc4
Loading...
Searching...
No Matches
svg.c
Go to the documentation of this file.
1/*
2 * File: svg.c
3 *
4 * Copyright (C) 2024 Rodrigo Arias Mallo <rodarima@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <config.h>
13
14#ifdef ENABLE_SVG
15
16#include <stdlib.h> /* For abort() */
17
18#include "msg.h"
19#include "image.hh"
20#include "cache.h"
21#include "dicache.h"
22
23#define NANOSVG_ALL_COLOR_KEYWORDS
24#define NANOSVG_IMPLEMENTATION
25#include "nanosvg.h"
26#define NANOSVGRAST_IMPLEMENTATION
27#include "nanosvgrast.h"
28
29typedef struct {
30 DilloImage *Image; /* Image meta data */
31 DilloUrl *url; /* Primary Key for the dicache */
32 int version; /* Secondary Key for the dicache */
33 int bgcolor; /* Parent widget background color */
34 int fgcolor; /* Parent widget foreground color */
35} DilloSvg;
36
37/*
38 * Free up the resources for this image.
39 */
40static void Svg_free(DilloSvg *svg)
41{
42 _MSG("Svg_free: svg=%p\n", svg);
43
44 dFree(svg);
45}
46
47/*
48 * Finish the decoding process (and free the memory)
49 */
50static void Svg_close(DilloSvg *svg, CacheClient_t *Client)
51{
52 _MSG("Svg_close\n");
53 /* Let dicache know decoding is over */
54 a_Dicache_close(svg->url, svg->version, Client);
55 Svg_free(svg);
56}
57
58/*
59 * Receive and process new chunks of SVG image data
60 */
61static void Svg_write(DilloSvg *svg, void *Buf, uint_t BufSize)
62{
63 static NSVGrasterizer *rasterizer = NULL;
64
65 if (!rasterizer)
66 rasterizer = nsvgCreateRasterizer();
67
68 if (Buf == NULL || BufSize <= 0)
69 return;
70
71 /* SVG image not finished yet */
72 if (strstr(Buf, "</svg>") == NULL)
73 return;
74
75 /* Use foreground as the current color, but transform to
76 * nanosvg color format (BGR). */
77 unsigned fg_r = (svg->fgcolor >> 16) & 0xff;
78 unsigned fg_g = (svg->fgcolor >> 8) & 0xff;
79 unsigned fg_b = (svg->fgcolor >> 0) & 0xff;
80 unsigned curcolor = NSVG_RGB(fg_r, fg_g, fg_b);
81
82 /* NULL-terminate Buf */
83 char *str = dStrndup(Buf, BufSize);
84 NSVGimage *nimg = nsvgParse(str, "px", svg->Image->dpi, curcolor);
85 dFree(str);
86
87 if (nimg == NULL) {
88 MSG_ERR("Svg_write: cannot parse SVG image\n");
89 return;
90 }
91
92 /* The height and width values can be nonintegral */
93 unsigned width = nimg->width;
94 unsigned height = nimg->height;
95
96 if (width == 0 || height == 0 || width > IMAGE_MAX_AREA / height) {
97 MSG_WARN("Svg_write: suspicious image size request %u x %u\n", width, height);
98 nsvgDelete(nimg);
99 return;
100 }
101
103 unsigned stride = width * 4;
104
105 a_Dicache_set_parms(svg->url, svg->version, svg->Image,
106 width, height, type, 1 / 2.2);
107
108 unsigned char *dest = dNew(unsigned char, height * stride);
109
110 nsvgRasterizeXY(rasterizer, nimg, 0, 0, 1, 1, dest, width, height, stride);
111
112 unsigned bg_blue = (svg->bgcolor) & 0xFF;
113 unsigned bg_green = (svg->bgcolor >> 8) & 0xFF;
114 unsigned bg_red = (svg->bgcolor >> 16) & 0xFF;
115
116 unsigned char *line = dNew(unsigned char, width * 3);
117 for (unsigned i = 0; i < height; i++) {
118 for (unsigned j = 0; j < width; j++) {
119 unsigned r = dest[i * stride + 4 * j];
120 unsigned g = dest[i * stride + 4 * j + 1];
121 unsigned b = dest[i * stride + 4 * j + 2];
122 unsigned alpha = dest[i * stride + 4 * j + 3];
123
124 line[3 * j + 0] = (r * alpha + (bg_red * (0xFF - alpha))) / 0xFF;
125 line[3 * j + 1] = (g * alpha + (bg_green * (0xFF - alpha))) / 0xFF;
126 line[3 * j + 2] = (b * alpha + (bg_blue * (0xFF - alpha))) / 0xFF;
127 }
128 a_Dicache_write(svg->url, svg->version, line, i);
129 }
130 dFree(dest);
131 dFree(line);
132 nsvgDelete(nimg);
133}
134
135void a_Svg_callback(int Op, void *data)
136{
137 if (Op == CA_Send) {
138 CacheClient_t *Client = data;
139 Svg_write(Client->CbData, Client->Buf, Client->BufSize);
140 } else if (Op == CA_Close) {
141 CacheClient_t *Client = data;
142 Svg_close(Client->CbData, Client);
143 } else if (Op == CA_Abort) {
144 Svg_free(data);
145 }
146}
147
148/*
149 * Create the image state data that must be kept between calls
150 */
151void *a_Svg_new(DilloImage *Image, DilloUrl *url, int version)
152{
153 DilloSvg *svg = dNew0(DilloSvg, 1);
154 _MSG("a_Svg_new: svg=%p\n", svg);
155
156 svg->Image = Image;
157 svg->url = url;
158 svg->version = version;
159 svg->bgcolor = Image->bg_color;
160 svg->fgcolor = Image->fg_color;
161
162 return svg;
163}
164
165#else /* ENABLE_SVG */
166
167void *a_Svg_new() { return 0; }
168void a_Svg_callback() { return; }
169
170#endif /* ENABLE_SVG */
#define _MSG(...)
Definition bookmarks.c:45
#define CA_Send
Definition cache.h:15
#define CA_Abort
Definition cache.h:17
#define CA_Close
Definition cache.h:16
unsigned int uint_t
Definition d_size.h:20
void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image, uint_t width, uint_t height, DilloImgType type, double gamma)
Set image's width, height & type.
Definition dicache.c:228
void a_Dicache_close(DilloUrl *url, int version, CacheClient_t *Client)
Implement the close method of the decoding process.
Definition dicache.c:329
void a_Dicache_write(DilloUrl *url, int version, const uchar_t *buf, uint_t Y)
Implement the write method (Write a scan line into the Dicache entry) buf: row buffer Y : row number.
Definition dicache.c:309
void dFree(void *mem)
Definition dlib.c:68
char * dStrndup(const char *s, size_t sz)
Definition dlib.c:88
#define dNew0(type, count)
Definition dlib.h:51
#define dNew(type, count)
Definition dlib.h:49
#define MSG_ERR(...)
Definition dpid_common.h:23
#define IMAGE_MAX_AREA
Definition fltkimgbuf.cc:27
#define MSG_WARN(...)
Definition msg.h:26
NSVGimage * nsvgParse(char *input, const char *units, float dpi, unsigned current_color)
void nsvgDelete(NSVGimage *image)
NSVGrasterizer * nsvgCreateRasterizer(void)
void nsvgRasterizeXY(NSVGrasterizer *r, NSVGimage *image, float tx, float ty, float sx, float sy, unsigned char *dst, int w, int h, int stride)
struct NSVGrasterizer NSVGrasterizer
Definition nanosvgrast.h:43
DilloImgType
Definition image.hh:42
@ DILLO_IMG_TYPE_RGB
Definition image.hh:44
Data structure for cache clients.
Definition cache.h:48
void * CbData
Client function data.
Definition cache.h:55
uint_t BufSize
Valid size of cache-data.
Definition cache.h:53
void * Buf
Pointer to cache-data.
Definition cache.h:52
Definition url.h:88
float width
Definition nanosvg.h:166
float height
Definition nanosvg.h:167
int32_t fg_color
Foreground color.
Definition image.hh:69
int32_t bg_color
Background color.
Definition image.hh:68
void a_Svg_callback()
Definition svg.c:168
void * a_Svg_new()
Definition svg.c:167