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:
@@ -0,0 +1,114 @@
|
||||
# webpdec.h — single-file WebP decoder
|
||||
|
||||
A standalone, dependency-free **WebP decoder** in one C header, in the spirit of
|
||||
the [stb](https://github.com/nothings/stb) libraries. It is libwebp's decode +
|
||||
demux path — *not* a reimplementation — amalgamated into a single file and built
|
||||
as portable C99 with **all SIMD, threads and host file I/O disabled**. So it is
|
||||
as correct as upstream libwebp (it *is* libwebp) while staying trivial to drop
|
||||
into any project.
|
||||
|
||||
Handles everything real WebP files use:
|
||||
|
||||
- **Lossy** (VP8) and **lossless** (VP8L)
|
||||
- The **VP8X** extended container
|
||||
- The **ALPH** alpha chunk (transparency on lossy images)
|
||||
- **Animation** + metadata via the demux API (`WebPDemux`, `WebPAnimDecoder`)
|
||||
|
||||
## Usage
|
||||
|
||||
In exactly **one** translation unit:
|
||||
|
||||
```c
|
||||
#define WEBPDEC_IMPLEMENTATION
|
||||
#include "webpdec.h"
|
||||
```
|
||||
|
||||
Everywhere else, just `#include "webpdec.h"`. The public API is the standard
|
||||
libwebp decode + demux API.
|
||||
|
||||
Still image:
|
||||
|
||||
```c
|
||||
int w, h;
|
||||
uint8_t *rgba = WebPDecodeRGBA(data, len, &w, &h); /* R,G,B,A, top-to-bottom */
|
||||
if (rgba) {
|
||||
/* ... w*h*4 bytes ... */
|
||||
WebPFree(rgba);
|
||||
}
|
||||
```
|
||||
|
||||
Animation (all frames, with blending/disposal handled for you):
|
||||
|
||||
```c
|
||||
WebPData wd = { data, len };
|
||||
WebPAnimDecoderOptions opt; WebPAnimDecoderOptionsInit(&opt);
|
||||
opt.color_mode = MODE_RGBA;
|
||||
WebPAnimDecoder *dec = WebPAnimDecoderNew(&wd, &opt);
|
||||
WebPAnimInfo info; WebPAnimDecoderGetInfo(dec, &info); /* canvas, frame_count */
|
||||
while (WebPAnimDecoderHasMoreFrames(dec)) {
|
||||
uint8_t *rgba; int timestamp_ms;
|
||||
WebPAnimDecoderGetNext(dec, &rgba, ×tamp_ms); /* rgba owned by dec */
|
||||
}
|
||||
WebPAnimDecoderDelete(dec);
|
||||
```
|
||||
|
||||
`WebPGetInfo`, `WebPDecodeRGB/BGRA/ARGB`, the advanced `WebPDecode` +
|
||||
`WebPDecoderConfig` path (including decode-time downscaling via
|
||||
`config.options.use_scaling`), and the full `WebPDemux*` chunk/metadata
|
||||
iterator are all available — see the declarations near the top of `webpdec.h`.
|
||||
|
||||
Link with `-lm` (libwebp uses `pow()` for gamma tables). That's the only
|
||||
dependency.
|
||||
|
||||
## What's not included
|
||||
|
||||
Encoding and the mux (assembly/write) API — this is decode-only, by design.
|
||||
|
||||
## Portability
|
||||
|
||||
`webpdec.h` defines `HAVE_CONFIG_H` and bakes in an empty `config.h`, which is
|
||||
libwebp's own switch for "no detected SIMD": every architecture dispatcher falls
|
||||
back to the reference C path. This works even on SIMD-capable targets — e.g. on
|
||||
ARMv8 where the toolchain defines `__ARM_NEON`, NEON still stays off. No
|
||||
pthreads, no `<stdio.h>` file calls. Tested decoding bit-exactly against
|
||||
upstream libwebp on x86-64 and aarch64.
|
||||
|
||||
## Repo layout
|
||||
|
||||
```
|
||||
webpdec.h the single-file library (committed; this is all you need)
|
||||
amalgamate.py regenerates webpdec.h from libwebp
|
||||
UPSTREAM_COMMIT the exact pinned libwebp revision
|
||||
LICENSE, PATENTS upstream BSD-style license + patent grant
|
||||
tests/ test_decode.c, test_demux.c, run.sh
|
||||
libwebp/ upstream checkout (git-ignored; fetched on demand)
|
||||
```
|
||||
|
||||
## Regenerating
|
||||
|
||||
```sh
|
||||
python3 amalgamate.py # writes webpdec.h (+ refreshes UPSTREAM_COMMIT)
|
||||
```
|
||||
|
||||
With no `libwebp/` present it shallow-clones libwebp at the pinned commit, so a
|
||||
fresh checkout just works — no submodules, no manual steps. The amalgamation is
|
||||
`LIBWEBPDECODER_OBJS` + `DEMUX_OBJS` minus every `*_sse2/_neon/_msa/...` SIMD
|
||||
translation unit; the few single-TU symbol clashes are namespaced by the script
|
||||
(the upstream tree is left pristine, so regeneration is byte-for-byte
|
||||
reproducible).
|
||||
|
||||
## Tests
|
||||
|
||||
```sh
|
||||
sh tests/run.sh
|
||||
```
|
||||
|
||||
With [Pillow](https://python-pillow.org/) installed it generates lossy /
|
||||
lossless / alpha / animated samples and checks decode output **bit-exactly**
|
||||
against reference libwebp; otherwise pass it `.webp` paths to decode.
|
||||
|
||||
## License
|
||||
|
||||
BSD-style, identical to libwebp. See `LICENSE` and `PATENTS`. Copyright Google
|
||||
LLC and the WebM project authors; this file only mechanically concatenates their
|
||||
sources.
|
||||
Reference in New Issue
Block a user