diff options
Diffstat (limited to 'host/gif.c')
-rw-r--r-- | host/gif.c | 190 |
1 files changed, 0 insertions, 190 deletions
diff --git a/host/gif.c b/host/gif.c deleted file mode 100644 index c62a5e2..0000000 --- a/host/gif.c +++ /dev/null @@ -1,190 +0,0 @@ - -#include "gif.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -typedef struct { - uint8_t *data; - unsigned int index; - unsigned int length; -} readBuffer_t; - -int gif_buffer_input (GifFileType *gif, GifByteType *dest, int n){ - readBuffer_t *rb = gif->UserData; - if(rb->index+n > rb->length) - n = rb->length - rb->index; - memcpy(dest, rb->data + rb->index, n); - rb->index += n; - return n; -} - -struct _gifAnimationState { - int idx; - GifFileType *gif; - framebuffer_t *frame; -}; - -void color_fill(color_t *dest, color_t src, size_t size){ - /* Some magic to reduce the amount of calls to small-block memcpys */ - dest[0] = src; - size_t i = 1; - size_t j = 2; - while(j < size){ - memcpy(dest+i, dest, i*sizeof(color_t)); - i = j; - j *= 2; - } - memcpy(dest+i, dest, (size-i)*sizeof(color_t)); -} - -gifAnimationState_t *gif_read(uint8_t *buf, size_t buflength){ - color_t *fb = 0; - gifAnimationState_t *st = malloc(sizeof(gifAnimationState_t)); - if(!st){ - fprintf(stderr, "Failed to allocate %lu bytes\n", sizeof(*st)); - return 0; - } - - readBuffer_t readBuf = {buf, 0, buflength}; - int err = 0; - GifFileType *gif = DGifOpen(&readBuf, gif_buffer_input, &err); - if(err){ - fprintf(stderr, "Could not open GIF: %s\n", GifErrorString(err)); - goto error; - } - - err = DGifSlurp(gif); - if(err){ - fprintf(stderr, "Could not read GIF data: %s\n", GifErrorString(err)); - goto error; - } - - unsigned int framesize = gif->SWidth*gif->SHeight; - if(framesize == 0){ /* Can this actually happen? */ - fprintf(stderr, "Invalid 0*0px gif\n"); - goto error; - } - fb = calloc(framesize, sizeof(color_t)); - if(!fb){ - fprintf(stderr, "Failed to allocate framebuffer for GIF (%lu bytes)\n", framesize*sizeof(color_t)); - goto error; - } - if(gif->SColorMap){ /* Initially fill framebuffer with background color */ - GifColorType *col = gif->SColorMap[gif->SBackGroundColor].Colors; - color_t c = {col->Red, col->Green, col->Blue, 255}; - color_fill(fb, c, framesize); - }else{ - /* Set all pixels to a transparent black */ - memset(fb, 0, framesize*sizeof(color_t)); - } - - st->gif = gif; - st->idx = 0; - st->frame = malloc(sizeof(framebuffer_t)); - if(!st->frame){ - fprintf(stderr, "Failed to allocate %lu bytes\n", sizeof(framebuffer_t)); - goto error; - } - st->frame->data = fb; - st->frame->w = gif->SWidth; - st->frame->h = gif->SHeight; - return st; -error: - free(fb); - free(st); - return 0; -} - -void gifAnimationState_free(gifAnimationState_t *st){ - if(st) - framebuffer_free(st->frame); - free(st); -} - -/* buf ⇜ input data - * state ⇜ internal state, initialize as NULL - * delay ⇜ is filled with this frame's delay value in milliseconds (if it is not NULL). -1 means "No delay given". - * Small note: I mean, rendering a GIF in python is not quite trivial, either (about 20loc). But come on, this is just ridiculous. */ -framebuffer_t *framebuffer_render_gif(uint8_t *buf, size_t buflength, gifAnimationState_t **state, int *delay){ - gifAnimationState_t *st; - if(*state == NULL){ - /* On first invocation, parse gif and store it in the state struct */ - st = gif_read(buf, buflength); - if(!st) - goto error; - *state = st; - }else{ - st = *state; - } - - GifFileType *gif = st->gif; - - /* Find this image's color map */ - SavedImage *img = gif->SavedImages + st->idx; - ColorMapObject *cmo = img->ImageDesc.ColorMap; - if(!cmo){ - cmo = gif->SColorMap; - if(!cmo){ - fprintf(stderr, "Missing color table for GIF frame %d\n", st->idx); - goto error; - } - } - - /* Extract and validate image's bounds*/ - unsigned int ix = img->ImageDesc.Left; - unsigned int iy = img->ImageDesc.Top; - unsigned int iw = img->ImageDesc.Width; - unsigned int ih = img->ImageDesc.Height; - if((iy+ih)*gif->SWidth + ix+iw > st->frame->w*st->frame->h){ - fprintf(stderr, "Invalid gif: Image %d (x %d y %d w %d h %d) out of bounds (w %d h %d)\n", - st->idx, ix, iy, iw, ih, gif->SWidth, gif->SHeight); - goto error; - } - - /* Find and parse this image's GCB (if it exists) */ - int transparent = -1; - int disposal = DISPOSAL_UNSPECIFIED; - if(delay) - *delay = -1; /* in milliseconds */ - for(unsigned int i=0; i<img->ExtensionBlockCount; i++){ - ExtensionBlock *eb = img->ExtensionBlocks + i; - if(eb->Function == GRAPHICS_EXT_FUNC_CODE){ - GraphicsControlBlock *gcb = (GraphicsControlBlock *)eb->Bytes; - transparent = gcb->TransparentColor; - disposal = gcb->DisposalMode; - if(delay) - *delay = gcb->DelayTime * 10; /* 10ms → 1ms */ - } - } - - color_t *fb = st->frame->data; - if(disposal == DISPOSE_BACKGROUND || disposal == DISPOSAL_UNSPECIFIED){ - GifColorType *gc = gif->SColorMap[gif->SBackGroundColor].Colors; - color_t c = {gc->Red, gc->Green, gc->Blue, 255}; - color_fill(fb, c, st->frame->w*st->frame->h); - } - /* FIXME DISPOSE_PREVIOUS is currently unhandled. */ - - /* Render gif bitmap to RGB */ - uint8_t *p = img->RasterBits; - for(unsigned int y = iy; y < iy+ih; y++){ - for(unsigned int x = ix; x < ix+iw; x++){ - int c = *p++; - if(c != transparent){ - GifColorType *col = cmo[c].Colors; - color_t ct = {col->Red, col->Green, col->Blue, 255}; - fb[y*st->frame->w + x] = ct; - } - } - } - - st->idx++; - if(st->idx >= gif->ImageCount) - st->idx = 0; - return st->frame; -error: - gifAnimationState_free(st); - return 0; -} - |