aboutsummaryrefslogtreecommitdiff
path: root/svg.c
diff options
context:
space:
mode:
Diffstat (limited to 'svg.c')
-rw-r--r--svg.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/svg.c b/svg.c
new file mode 100644
index 0000000..b5fa4b3
--- /dev/null
+++ b/svg.c
@@ -0,0 +1,82 @@
+#include "svg.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <nanosvgrast.h>
+
+#define LOG_MODULE "svg"
+#define LOG_ENABLE_DBG 0
+#include "log.h"
+#include "stride.h"
+
+pixman_image_t *
+svg_load(FILE *fp, const char *path)
+{
+ pixman_image_t *pix = NULL;
+ uint8_t *data = NULL;
+ int width, height, stride;
+ bool ok = false;
+ struct NSVGimage *image = NULL;
+ struct NSVGrasterizer *rast = NULL;
+
+ image = nsvgParseFromFile(path, "px", 96);
+ width = image->width;
+ height = image->height;
+ if (width == 0 || height == 0) {
+ LOG_ERR("%s: width and/or heigth is zero, not a SVG?", path);
+ nsvgDelete(image);
+ return NULL;
+ }
+ stride = stride_for_format_and_width(PIXMAN_a8b8g8r8, image->width);
+
+ if (!(data = calloc(1, height * stride)))
+ goto out;
+
+ if (!(rast = nsvgCreateRasterizer()))
+ goto out;
+
+ nsvgRasterize(rast, image, 0, 0, 1, data, width, height, stride);
+
+ ok = NULL != (pix = pixman_image_create_bits_no_clear(
+ PIXMAN_a8b8g8r8, width, height, (uint32_t *)data, stride));
+
+ if (!ok) {
+ LOG_ERR("%s: failed to instanciate pixman image", path);
+ goto out;
+ }
+
+ /* Copied from fuzzel */
+ /* Nanosvg produces non-premultiplied ABGR, while pixman expects
+ * premultiplied */
+ for (uint32_t *abgr = (uint32_t *)data;
+ abgr < (uint32_t *)(data + (size_t)image->width * (size_t)image->height * 4);
+ abgr++) {
+ uint8_t alpha = (*abgr >> 24) & 0xff;
+ uint8_t blue = (*abgr >> 16) & 0xff;
+ uint8_t green = (*abgr >> 8) & 0xff;
+ uint8_t red = (*abgr >> 0) & 0xff;
+
+ if (alpha == 0xff)
+ continue;
+
+ if (alpha == 0x00)
+ blue = green = red = 0x00;
+ else {
+ blue = blue * alpha / 0xff;
+ green = green * alpha / 0xff;
+ red = red * alpha / 0xff;
+ }
+
+ *abgr = (uint32_t)alpha << 24 | blue << 16 | green << 8 | red;
+ }
+
+out:
+ if (image)
+ nsvgDelete(image);
+ if (rast)
+ nsvgDeleteRasterizer(rast);
+
+ if (!ok)
+ free(data);
+ return pix;
+}