From 269fb9bca7bef679935001e30dcf60031253bbf9 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Mon, 21 Jan 2019 00:34:01 +0000 Subject: Add rsvg backend --- Makefile | 6 ++- src/backend_rsvg.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/backend_rsvg.h | 9 ++++ src/main.c | 2 + 4 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 src/backend_rsvg.c create mode 100644 src/backend_rsvg.h diff --git a/Makefile b/Makefile index 6a05aa8..ca41af0 100644 --- a/Makefile +++ b/Makefile @@ -8,8 +8,12 @@ CONFIGPREFIX ?= /etc CFLAGS ?= -W -Wall -pedantic -Wmissing-prototypes CFLAGS += -std=c99 +CFLAGS += $(shell pkg-config --cflags librsvg-2.0) CPPFLAGS += $(shell sdl2-config --cflags) -D_XOPEN_SOURCE=700 -LIBS := $(shell sdl2-config --libs) -lfreeimage -lpng -lSDL2_ttf -lfontconfig -lpthread +LIBS := $(shell sdl2-config --libs) +LIBS += -lfreeimage -lpng +LIBS += $(shell pkg-config --libs librsvg-2.0) +LIBS += -lSDL2_ttf -lfontconfig -lpthread BUILDDIR ?= build TARGET := $(BUILDDIR)/imv diff --git a/src/backend_rsvg.c b/src/backend_rsvg.c new file mode 100644 index 0000000..f259e5c --- /dev/null +++ b/src/backend_rsvg.c @@ -0,0 +1,141 @@ +#include "backend_rsvg.h" +#include "backend.h" +#include "source.h" + +#include + +/* Some systems like GNU/Hurd don't define PATH_MAX */ +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +static void source_free(struct imv_source *src) +{ + free(src->name); + src->name = NULL; + + free(src); +} + +static struct imv_bitmap *to_imv_bitmap(GdkPixbuf *bitmap) +{ + struct imv_bitmap *bmp = malloc(sizeof(struct imv_bitmap)); + bmp->width = gdk_pixbuf_get_width(bitmap); + bmp->height = gdk_pixbuf_get_height(bitmap); + bmp->format = IMV_ARGB; + size_t len = bmp->width * bmp->height * 4; + bmp->data = malloc(len); + memcpy(bmp->data, gdk_pixbuf_get_pixels(bitmap), len); + return bmp; +} + +static void report_error(struct imv_source *src) +{ + if (!src->callback) { + fprintf(stderr, "imv_source(%s) has no callback configured. " + "Discarding error.\n", src->name); + return; + } + + struct imv_source_message msg; + msg.source = src; + msg.user_data = src->user_data; + msg.bitmap = NULL; + msg.error = "Internal error"; + + src->callback(&msg); +} + + +static void send_bitmap(struct imv_source *src, GdkPixbuf *bitmap) +{ + if (!src->callback) { + fprintf(stderr, "imv_source(%s) has no callback configured. " + "Discarding result.\n", src->name); + return; + } + + struct imv_source_message msg; + msg.source = src; + msg.user_data = src->user_data; + msg.bitmap = to_imv_bitmap(bitmap); + msg.frametime = 0; + msg.error = NULL; + + src->callback(&msg); +} + +static void load_image(struct imv_source *src) +{ + GError *error; + char path[PATH_MAX+8]; + snprintf(path, sizeof path, "file://%s", src->name); + RsvgHandle *handle = rsvg_handle_new_from_file(path, &error); + if (!handle) { + report_error(src); + return; + } + + RsvgDimensionData dim; + rsvg_handle_get_dimensions(handle, &dim); + src->width = dim.width; + src->height = dim.height; + + GdkPixbuf *buf = rsvg_handle_get_pixbuf(handle); + if (!buf) { + rsvg_handle_close(handle, &error); + report_error(src); + return; + } + + rsvg_handle_close(handle, &error); + send_bitmap(src, buf); +} + +static enum backend_result open_path(const char *path, struct imv_source **src) +{ + /* Look for an tag near the start of the file */ + char header[128]; + FILE *f = fopen(path, "rb"); + if (!f) { + return BACKEND_BAD_PATH; + } + fread(header, 1, sizeof header, f); + fclose(f); + + header[(sizeof header) - 1] = 0; + if (!strstr(header, "name = strdup(path); + + source->width = 1024; + source->height = 1024; + source->num_frames = 1; + source->next_frame = 1; + source->load_first_frame = &load_image; + source->load_next_frame = NULL; + source->free = &source_free; + source->callback = NULL; + source->user_data = NULL; + source->private = NULL; + + *src = source; + return BACKEND_SUCCESS; +} + +static void backend_free(struct imv_backend *backend) +{ + free(backend); +} + +struct imv_backend *imv_backend_rsvg(void) +{ + struct imv_backend *backend = malloc(sizeof(struct imv_backend)); + backend->name = "rsvg (LGPL license)"; + backend->open_path = &open_path; + backend->free = &backend_free; + return backend; +} diff --git a/src/backend_rsvg.h b/src/backend_rsvg.h new file mode 100644 index 0000000..126892a --- /dev/null +++ b/src/backend_rsvg.h @@ -0,0 +1,9 @@ +#ifndef IMV_BACKEND_RSVG_H +#define IMV_BACKEND_RSVG_H + +struct imv_backend; + +/* Create an instance of the rsvg backend */ +struct imv_backend *imv_backend_rsvg(void); + +#endif diff --git a/src/main.c b/src/main.c index 3f96b02..8b88340 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,7 @@ #include "backend.h" #include "backend_freeimage.h" #include "backend_libpng.h" +#include "backend_rsvg.h" int main(int argc, char** argv) { @@ -12,6 +13,7 @@ int main(int argc, char** argv) return 1; } + imv_install_backend(imv, imv_backend_rsvg()); imv_install_backend(imv, imv_backend_freeimage()); imv_install_backend(imv, imv_backend_libpng()); -- cgit v1.2.3