graphgif/guile-cgif.c

78 lines
2.4 KiB
C
Raw Normal View History

2024-10-16 13:48:22 -05:00
#include <stdlib.h>
#include <libguile.h>
#include <cgif.h>
#include <cairo.h>
const uint8_t PALETTE[] = {
0xFF, 0xFF, 0xFF, // WHITE
0x00, 0x00, 0x00, // BLACK
0xFF, 0x00, 0x00 // RED
};
#define CAIRO_RED 0x00FF0000
#define CAIRO_BLACK 0x00FFFFFF
void encode_frame(cairo_surface_t *surface, CGIF_FrameConfig *frameconfig) {
// TODO pull colors from cairo
size_t size = cairo_image_surface_get_width(surface) * cairo_image_surface_get_height(surface);
frameconfig->pLocalPalette = (uint8_t*) &PALETTE;
frameconfig->numLocalPaletteEntries = 3;
frameconfig->pImageData = (uint8_t*)calloc(size, sizeof(uint8_t));
if (cairo_image_surface_get_format(surface) == CAIRO_FORMAT_RGB24) {
unsigned char* pen = cairo_image_surface_get_data(surface);
for (size_t i = 0; i < size; i++) {
uint32_t cairo_color = (uint32_t)(*(pen + i * sizeof(uint32_t) * cairo_image_surface_get_stride(surface)));
switch (cairo_color) {
case CAIRO_BLACK:
frameconfig->pImageData[i] = 1;
break;
case CAIRO_RED:
frameconfig->pImageData[i] = 2;
break;
}
}
}
}
void make_gif_inner(cairo_surface_t *frames[], size_t n_frames, const char* path) {
CGIF_Config cgif_config;
cgif_config.path = path;
cgif_config.attrFlags = CGIF_ATTR_IS_ANIMATED | CGIF_ATTR_NO_GLOBAL_TABLE;
cgif_config.width = cairo_image_surface_get_width(frames[0]);
cgif_config.height = cairo_image_surface_get_height(frames[0]);
CGIF *cgif = cgif_newgif(&cgif_config);
for (size_t i = 0; i < n_frames; i++) {
cairo_surface_t *frame = frames[i];
// Flush pending writes
cairo_surface_flush(frame);
CGIF_FrameConfig cgif_frameconfig;
cgif_frameconfig.attrFlags = CGIF_FRAME_ATTR_USE_LOCAL_TABLE;
cgif_frameconfig.delay = 100;
encode_frame(frame, &cgif_frameconfig);
cgif_addframe(cgif, &cgif_frameconfig);
}
cgif_close(cgif);
}
void make_gif(SCM frames, SCM path) {
size_t c_length = scm_c_array_length(frames);
scm_t_array_handle c_array;
scm_array_get_handle(frames, &c_array);
cairo_surface_t **c_frames = scm_array_handle_uniform_elements(&c_array);
const char* c_path = scm_to_locale_string(path);
make_gif_inner(c_frames, c_length, c_path);
scm_array_handle_release(&c_array);
}
void init_cgif() {
scm_c_define_gsubr("make-gif", 2, 0, 0, &make_gif);
}