aboutsummaryrefslogtreecommitdiffstats
path: root/render.c
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-10-13 23:00:56 +0200
committerMattias Andrée <m@maandree.se>2026-10-13 23:00:56 +0200
commit0476071164c36b41de5b19e3e8a768feb422f27f (patch)
tree09d16e177042b14020a48030176d99e9024bea66 /render.c
parentThird commit (diff)
downloadgbild-0476071164c36b41de5b19e3e8a768feb422f27f.tar.gz
gbild-0476071164c36b41de5b19e3e8a768feb422f27f.tar.bz2
gbild-0476071164c36b41de5b19e3e8a768feb422f27f.tar.xz
Fourth commit
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
-rw-r--r--render.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/render.c b/render.c
new file mode 100644
index 0000000..fdc2f0c
--- /dev/null
+++ b/render.c
@@ -0,0 +1,118 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+#include <string.h>
+
+static uint8_t
+unpremultiply(double colour, double alpha)
+{
+ if (colour <= 0.04045)
+ colour = colour / 12.92;
+ else
+ colour = pow((colour + 0.055) / 1.055, 2.4);
+
+ colour /= alpha;
+
+ if (colour <= 0.0031308)
+ colour = 12.92 * colour;
+ else
+ colour = fma(1.055, pow(colour, 1.0 / 2.4), -0.055);
+
+ colour = fma(255.0, colour, 0.5);
+ if (colour <= 0.0)
+ return 0u;
+ if (colour >= 255.0)
+ return 255u;
+ return (uint8_t)colour;
+}
+
+GdkPixbuf *
+rasterise(RsvgHandle *vector, int width, int height)
+{
+ RsvgRectangle viewport = {0.0, 0.0, width, height};
+ cairo_surface_t *surface = NULL;
+ cairo_t *cr = NULL;
+ GdkPixbuf *image;
+ int x, y, sstride, dstride;
+ const uint8_t *s, *sy;
+ uint8_t *d, *dy;
+ double a, r, g, b;
+ uint32_t pixel;
+
+ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+ if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
+ goto fail;
+
+ cr = cairo_create(surface);
+ if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
+ goto fail;
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
+ cairo_paint(cr);
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ if (!rsvg_handle_render_document(vector, cr, &viewport, NULL))
+ goto fail;
+ cairo_destroy(cr);
+ cr = NULL;
+
+ image = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 1, 8, width, height);
+ if (!image)
+ goto fail;
+
+ /* TODO accelerate */
+ cairo_surface_flush(surface);
+ sy = s = cairo_image_surface_get_data(surface);
+ dy = d = gdk_pixbuf_get_pixels(image);
+ sstride = cairo_image_surface_get_stride(surface);
+ dstride = gdk_pixbuf_get_rowstride(image);
+ for (y = 0; y < height; y++, sy = s = &s[sstride], dy = d = &d[dstride]) {
+ for (x = 0; x < width; x++, sy = &sy[4u], dy = &dy[4u]) {
+ memcpy(&pixel, sy, 4u);
+ if ((uint8_t)(pixel >> 24)) {
+ a = (double)(uint8_t)(pixel >> 24) / 255.0;
+ r = (double)(uint8_t)(pixel >> 16) / 255.0;
+ g = (double)(uint8_t)(pixel >> 8) / 255.0;
+ b = (double)(uint8_t)(pixel >> 0) / 255.0;
+ dy[0] = unpremultiply(r, a);
+ dy[1] = unpremultiply(g, a);
+ dy[2] = unpremultiply(b, a);
+ dy[3] = (uint8_t)(pixel >> 24);
+ } else {
+ dy[0] = dy[1] = dy[2] = dy[3] = 0u;
+ }
+ }
+ }
+
+ cairo_surface_destroy(surface);
+ return image;
+
+fail:
+ if (cr)
+ cairo_destroy(cr);
+ if (surface)
+ cairo_surface_destroy(surface);
+ return NULL;
+}
+
+void
+paint_image(cairo_t *cr, struct image *image)
+{
+ RsvgRectangle viewport = {0.0, 0.0, image->width, image->height};
+ int rendered;
+
+ if (image->vector) {
+ cairo_save(cr);
+ if (image->has_transformer)
+ cairo_transform(cr, &image->transformer);
+ rendered = rsvg_handle_render_document(image->vector, cr, &viewport, NULL);
+ cairo_restore(cr);
+ if (rendered)
+ return;
+ }
+
+ if (image->raster) {
+ gdk_cairo_set_source_pixbuf(cr, image->raster, 0.0, 0.0);
+ cairo_paint(cr);
+ }
+}