/* Compile with: gcc -o gif2png-gdk-pixbuf gif2png-gdk-pixbuf.c `pkg-config cairo gdk-2.0 gdk-pixbuf-2.0 --cflags --libs` */ #include #include #include #include #include #include #define TARGET_WIDTH 2000 #define TARGET_HEIGHT 2000 #define BUFFER_SIZE 4096 #ifndef MIN # define MIN(a,b) ((a)<(b)?(a):(b)) #endif typedef struct{ GdkPixbufAnimation *animation; }image_t; typedef struct{ image_t *image; GdkPixbuf *pixbuf; }frame_t; image_t * testcase_load(const char *filename){ image_t *image = (image_t*)malloc(sizeof(image_t)); FILE* f; GdkPixbufLoader *loader; f = fopen(filename, "r"); if(!f) return NULL; loader = gdk_pixbuf_loader_new_with_mime_type ("image/gif", NULL); if(!loader) return NULL; for(;;){ guchar buffer[BUFFER_SIZE]; ssize_t read_bytes; read_bytes = fread(buffer, 1, BUFFER_SIZE, f); if (read_bytes < 0) return NULL; if(0 == read_bytes) break; if(!gdk_pixbuf_loader_write(loader, buffer, read_bytes, NULL)) return NULL; } /* Loading complete, transaction should not be free-ed */ gdk_pixbuf_loader_close(loader, NULL); fclose(f); image->animation = gdk_pixbuf_loader_get_animation(loader); return image; } frame_t * testcase_frame(image_t *image,int nr){ frame_t *frame = (frame_t*)malloc(sizeof(frame_t)); GdkPixbufAnimationIter *iter; frame->image = image; iter = gdk_pixbuf_animation_get_iter(image->animation, NULL); while(nr-->0){ /* Here the frame number could be advanced but that is too complicated to bother with here. */ } frame->pixbuf = gdk_pixbuf_animation_iter_get_pixbuf(iter); return frame; } void testcase_draw(frame_t *frame,cairo_t *cr){ int width; int height; double x_offset; double y_offset; double scale; /* Calculate scale */ width = gdk_pixbuf_animation_get_width(frame->image->animation); height = gdk_pixbuf_animation_get_height(frame->image->animation); scale = MIN((double)TARGET_WIDTH/width,(double)TARGET_HEIGHT/height); x_offset = (TARGET_WIDTH - scale*width)/2; y_offset = (TARGET_HEIGHT - scale*height)/2; cairo_translate(cr, x_offset, y_offset); cairo_scale(cr, scale, scale); gdk_cairo_set_source_pixbuf(cr, frame->pixbuf, 0, 0); cairo_paint(cr); } static clock_t start; static void measuretime_start(){ start = clock(); } static double measuretime_point(){ clock_t now = clock(); return (double) (now - start) / CLOCKS_PER_SEC; } int main(int argc,char **argv){ cairo_surface_t *surface; cairo_t *cr; image_t *image; frame_t *frame; if(argc<2){ fprintf(stderr,"Usage: %s []\n",argv[0]); return 1; } /* Create a surface to render the image on */ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,TARGET_WIDTH,TARGET_HEIGHT); cr = cairo_create(surface); /* Load the image */ measuretime_start(); image = testcase_load(argv[1]); if(!image){ fprintf(stderr,"Failed to load GIF image %s\n",argv[1]); return 1; } printf("Loading the image took %f seconds\n",measuretime_point()); /* Get a frame */ measuretime_start(); frame = testcase_frame(image,0); printf("Getting a frame took %f seconds\n",measuretime_point()); /* Render the frame (scaled) */ measuretime_start(); testcase_draw(frame,cr); printf("Rendering the frame took %f seconds\n",measuretime_point()); /* Optionally save the result */ if(argc>=3) cairo_surface_write_to_png(surface,argv[2]); return 0; }