#include #include #include #include const uint8_t PALETTE[] = { 0xFF, 0xFF, 0xFF, // WHITE 0x00, 0x00, 0x00, // BLACK 0xFF, 0x00, 0x00 // RED }; #define CAIRO_RED 0x00FF0000 #define CAIRO_BLACK 0x00000000 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) { uint32_t* pen = (uint32_t*) cairo_image_surface_get_data(surface); for (size_t i = 0; i < size; i++) { uint32_t cairo_color = pen[i]; switch (cairo_color & 0x00FFFFFF) { 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; memset(&cgif_config, 0, sizeof(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; memset(&cgif_frameconfig, 0, sizeof(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); } SCM make_gif(SCM frames, SCM path) { size_t n_frames = scm_to_size_t(scm_length(frames)); cairo_surface_t **c_frames = (cairo_surface_t **) malloc(sizeof(cairo_surface_t*) * n_frames); for (size_t i = 0; i < n_frames; i++) { c_frames[i] = scm_to_cairo_surface(scm_list_ref(frames, scm_from_size_t(i))); } const char* c_path = scm_to_locale_string(path); make_gif_inner(c_frames, n_frames, c_path); return SCM_UNSPECIFIED; } void init_cgif() { scm_c_define_gsubr("make-gif", 2, 0, 0, &make_gif); }