aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarry Jeffery <harry@exec64.co.uk>2019-01-21 00:34:01 +0000
committerHarry Jeffery <harry@exec64.co.uk>2019-01-29 22:26:22 +0000
commit269fb9bca7bef679935001e30dcf60031253bbf9 (patch)
tree1294f6f67106e339d64d21dc9af286971d1a107d
parent91eb7306b94187dbb989ac647cd79426790bf3c5 (diff)
downloadimv-269fb9bca7bef679935001e30dcf60031253bbf9.tar.gz
Add rsvg backend
-rw-r--r--Makefile6
-rw-r--r--src/backend_rsvg.c141
-rw-r--r--src/backend_rsvg.h9
-rw-r--r--src/main.c2
4 files changed, 157 insertions, 1 deletions
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 <librsvg/rsvg.h>
+
+/* 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 <SVG> 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, "<SVG") && !strstr(header, "<svg")) {
+ return BACKEND_UNSUPPORTED;
+ }
+
+ struct imv_source *source = calloc(1, sizeof(struct imv_source));
+ source->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());