webpdec.h: single-file WebP decoder

libwebp 1.6.0's decode + demux path (lossy VP8, lossless VP8L, VP8X
container, ALPH alpha, and the WebPDemux/WebPAnimDecoder animation API)
amalgamated into one stb-style header, built as portable C99 with all
SIMD, threads and host file I/O disabled.

amalgamate.py regenerates webpdec.h from a pinned, auto-cloned libwebp
checkout; tests/run.sh checks decode output bit-exactly against
reference libwebp.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 03:28:11 +00:00
commit 4da9a48d7c
10 changed files with 22045 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
/* exercises the demux + animation API folded into the single header */
#include <stdio.h>
#include <stdlib.h>
#define WEBPDEC_IMPLEMENTATION
#include "webpdec.h"
static unsigned char* slurp(const char* p, size_t* n){
FILE* f=fopen(p,"rb"); if(!f) return 0;
fseek(f,0,SEEK_END); long L=ftell(f); fseek(f,0,SEEK_SET);
unsigned char* b=malloc(L); if(fread(b,1,L,f)!=(size_t)L){} fclose(f); *n=L; return b;
}
int main(int argc,char**argv){
size_t n; unsigned char* buf=slurp(argv[1],&n);
if(!buf){ printf("no file\n"); return 1; }
WebPData data = { buf, n };
/* --- demux: report canvas + frame/loop count --- */
WebPDemuxer* dmux = WebPDemux(&data);
if(!dmux){ printf("WebPDemux failed\n"); return 1; }
unsigned cw = WebPDemuxGetI(dmux, WEBP_FF_CANVAS_WIDTH);
unsigned ch = WebPDemuxGetI(dmux, WEBP_FF_CANVAS_HEIGHT);
unsigned nf = WebPDemuxGetI(dmux, WEBP_FF_FRAME_COUNT);
unsigned lp = WebPDemuxGetI(dmux, WEBP_FF_LOOP_COUNT);
unsigned fl = WebPDemuxGetI(dmux, WEBP_FF_FORMAT_FLAGS);
printf("demux: canvas=%ux%u frames=%u loop=%u flags=0x%x\n", cw,ch,nf,lp,fl);
WebPDemuxDelete(dmux);
/* --- animation: decode every frame via WebPAnimDecoder --- */
WebPAnimDecoderOptions opt;
WebPAnimDecoderOptionsInit(&opt);
opt.color_mode = MODE_RGBA;
WebPAnimDecoder* adec = WebPAnimDecoderNew(&data, &opt);
if(!adec){ printf("WebPAnimDecoderNew failed\n"); return 1; }
WebPAnimInfo info;
WebPAnimDecoderGetInfo(adec, &info);
printf("anim: %ux%u frames=%u loops=%u bgcolor=0x%08x\n",
info.canvas_width, info.canvas_height, info.frame_count,
info.loop_count, info.bgcolor);
int prev = 0, got = 0;
while (WebPAnimDecoderHasMoreFrames(adec)) {
uint8_t* frgba; int ts;
if (!WebPAnimDecoderGetNext(adec, &frgba, &ts)) { printf("GetNext failed\n"); break; }
long c = ((long)info.canvas_height/2*info.canvas_width + info.canvas_width/2)*4;
printf(" frame %d ts=%dms (+%dms) centerRGBA=%d,%d,%d,%d\n",
got, ts, ts-prev, frgba[c],frgba[c+1],frgba[c+2],frgba[c+3]);
prev = ts; got++;
}
printf("decoded %d/%u frames -> %s\n", got, info.frame_count,
(got==(int)info.frame_count)?"OK":"MISMATCH");
WebPAnimDecoderDelete(adec);
free(buf);
return 0;
}