diff --git a/src/modules/loaders/loader_ani.c b/src/modules/loaders/loader_ani.c index c946593..00eadfc 100644 --- a/src/modules/loaders/loader_ani.c +++ b/src/modules/loaders/loader_ani.c @@ -23,6 +23,9 @@ #define RIFF_TYPE_INAM T('I', 'N', 'A', 'M') #define RIFF_TYPE_IART T('I', 'A', 'R', 'T') #define RIFF_TYPE_icon T('i', 'c', 'o', 'n') +#define RIFF_TYPE_anih T('a', 'n', 'i', 'h') +#define RIFF_TYPE_rate T('r', 'a', 't', 'e') +#define RIFF_TYPE_seq T('s', 'e', 'q', ' ') #define RIFF_NAME_ACON T('A', 'C', 'O', 'N') @@ -30,8 +33,25 @@ static const char *const _formats[] = { "ani" }; typedef struct { unsigned char nest; + int nframes, nfsteps; + uint32_t *rates, *seq; } riff_ctx_t; +typedef struct { + uint32_t size; // Size of chunk data (=36) + uint32_t frames; // Number of frames in file + uint32_t steps; // Number of steps in animation sequence + uint32_t width; // Image width (raw data only?) + uint32_t height; // Image height (raw data only?) + uint32_t bpp; // Bits per pixel (raw data only?) + uint32_t planes; // N. planes (raw data only?) + uint32_t rate; // Default rate in 1/60s + uint32_t flags; // Flags: ANIH_FLAG_... +} anih_data_t; + +#define ANIH_FLAG_ICO 0x01 // Frames are icons or cursors (otherwiwe raw - bmp?) +#define ANIH_FLAG_SEQ 0x02 // Image contains seq chunk + static int _load_embedded(ImlibImage * im, int load_data, const char *data, unsigned int size) @@ -72,10 +92,15 @@ _riff_parse(ImlibImage * im, riff_ctx_t * ctx, const char *fdata, int rc; unsigned int type; int size, avail; + int fcount, i; + ImlibImageFrame *pf; rc = LOAD_FAIL; ctx->nest += 1; + pf = NULL; + fcount = 0; + for (; rc == 0; fptr += 8 + size) { avail = fdata + fsize - fptr; /* Bytes left in chunk */ @@ -128,8 +153,75 @@ _riff_parse(ImlibImage * im, riff_ctx_t * ctx, const char *fdata, break; case RIFF_TYPE_icon: Dx("\n"); + fcount++; + if (im->frame > 0) + { + i = (ctx->seq) ? + (int)SWAP_LE_32(ctx->seq[im->frame - 1]) + 1 : im->frame; + if (i != fcount) + break; + } + if (pf && ctx->rates) + pf->frame_delay = + (1000 * SWAP_LE_32(ctx->rates[im->frame - 1])) / 60; rc = _load_embedded(im, 1, fptr + 8, size); break; + case RIFF_TYPE_anih: +#define AH ((const anih_data_t*)(fptr + 8)) +/**INDENT-OFF**/ + Dx("sz=%u nf=%u/%u WxH=%ux%u bc=%u np=%u dr=%u fl=%u\n", + SWAP_LE_32(AH->size), SWAP_LE_32(AH->frames), SWAP_LE_32(AH->steps), + SWAP_LE_32(AH->width), SWAP_LE_32(AH->height), + SWAP_LE_32(AH->bpp), SWAP_LE_32(AH->planes), + SWAP_LE_32(AH->rate), SWAP_LE_32(AH->flags)); +/**INDENT-ON**/ + ctx->nframes = SWAP_LE_32(AH->frames); + ctx->nfsteps = SWAP_LE_32(AH->steps); + if (im->frame <= 0) + break; + if (ctx->nfsteps < ctx->nframes) + ctx->nfsteps = ctx->nframes; + if (im->frame > ctx->nfsteps) + return LOAD_BADFRAME; + pf = __imlib_GetFrame(im); + if (!pf) + { + rc = LOAD_OOM; + break; + } + pf->frame_count = ctx->nfsteps; + if (ctx->nframes > 1) + pf->frame_flags = FF_IMAGE_ANIMATED; + pf->frame_delay = (1000 * SWAP_LE_32(AH->rate)) / 60; + break; + case RIFF_TYPE_rate: + ctx->rates = (uint32_t *) (fptr + 8); + if ((int)size != 4 * ctx->nfsteps) + { + D("rate chunk size mismatch: %d != %d\n", size, + 4 * ctx->nfsteps); + break; + } +#if IMLIB2_DEBUG + for (i = 0; i < ctx->nfsteps; i++) + Dx(" %d", SWAP_LE_32(ctx->rates[i])); +#endif + Dx("\n"); + break; + case RIFF_TYPE_seq: + ctx->seq = (uint32_t *) (fptr + 8); + if ((int)size != 4 * ctx->nfsteps) + { + D("seq chunk size mismatch: %d != %d\n", size, + 4 * ctx->nfsteps); + break; + } +#if IMLIB2_DEBUG + for (i = 0; i < ctx->nfsteps; i++) + Dx(" %d", SWAP_LE_32(ctx->seq[i])); +#endif + Dx("\n"); + break; } size = (size + 1) & ~1; }