blob: 63698d511b09438b0822d4a6c02599da06a10668 [file] [log] [blame] [view]
# Image Decoders
Regardless of the file format (GIF, JPEG, PNG, etc), every Wuffs image decoder
has a similar API. This document gives `wuffs_gif__decoder__foo_bar` examples,
but the `gif` could be replaced by `jpeg`, `png`, etc.
Some image formats (GIF) are animated, consisting of an image header and then N
frames. The image header gives e.g. the overall image's width and height. Each
frame consists of a frame header (e.g. frame rectangle bounds, display
duration) and a payload (the pixels).
In general, there is one `wuffs_base__image_config` and then N pairs of
(`wuffs_base__frame_config`, frame). Non-animated (still) image formats are
treated the same way: that their N is 1 and their single frame's bounds equals
the overall image bounds.
To decode everything (without knowing N in advance) sequentially:
```
wuffs_base__io_buffer src = etc;
wuffs_gif__decoder* dec = etc;
wuffs_base__image_config ic;
wuffs_base__status status = wuffs_gif__decoder__decode_image_config(dec, &ic, &src);
// Error checking (inspecting the status variable) is not shown, for brevity.
// See the example programs, listed below, for how to handle errors.
// Allocate the pixel buffer, based on ic's width and height, etc.
wuffs_base__pixel_buffer pb = etc;
while (true) {
wuffs_base__frame_config fc;
status = wuffs_gif__decoder__decode_frame_config(dec, &fc, &src);
if (status.repr == wuffs_base__note__end_of_data) {
break;
}
// Ditto re error checking.
status = wuffs_gif__decoder__decode_frame(dec, &pb, &etc);
// Ditto re error checking.
}
```
The second argument to each `decode_xxx` method (`&ic`, `&fc` or `&pb`), is the
destination data structure to store the decoded information.
For random (instead of sequential) access to an image's frames, call
`wuffs_gif__decoder__restart_frame(dec, i, io_pos)` to prepare to decode the
i'th frame. Essentially, it restores the state to be at the top of the while
loop above. The `wuffs_base__io_buffer`'s reader position will also need to be
set to the `io_pos` position in the source data stream. The position for the
i'th frame is calculated by the i'th `decode_frame_config` call and saved in
the `frame_config`. You can only call `restart_frame` after
`decode_image_config` is called, explicitly or implicitly (see below), as
decoding a single frame might require for-all-frames information like the
overall image dimensions and the global palette.
All of those `decode_xxx` calls are optional. For example, if
`decode_image_config` is not called, then the first `decode_frame_config` call
will implicitly parse and verify the image header, before parsing the first
frame's header. Similarly, you can call only `decode_frame` N times, without
calling `decode_image_config` or `decode_frame_config`, if you already know
metadata like N and each frame's rectangle bounds by some other means (e.g.
this is a first party, statically known image). The [Image Decoders Call
Sequence](./image-decoders-call-sequence.md) document has more implementation
information.
Specifically, starting with an unknown (but re-windable) animated image, if you
want to just find N (i.e. count the number of frames), you can loop calling
only the `decode_frame_config` method and avoid calling the more expensive
`decode_frame` method. For GIF, in terms of the underlying wire format, this
will skip over (instead of decompress) the LZW-encoded pixel data, which is
faster.
Those `decode_xxx` methods are also suspendible
[coroutines](/doc/note/coroutines.md). They will return early (with a status
code that `is_suspendible` and therefore isn't `is_complete`) if there isn't
enough source data to complete the operation: an incremental decode. Calling
`decode_xxx` again with additional source data will resume the previous
operation instead of starting a new one. Calling `decode_yyy` whilst
`decode_xxx` is suspended will result in an error.
Once an error is encountered, whether from invalid source data or from a
programming error, such as calling `decode_yyy` while suspended in
`decode_xxx`, all subsequent calls will be no-ops that return an error. To
reset the decoder into something that does productive work,
[re-initialize](/doc/note/initialization.md) and then, in order to be able to
call `restart_frame`, call `decode_image_config`. The `io_buffer` and its
associated stream will also need to be rewound.
## Metadata
The [Metadata](./metadata.md) document has more API information, applicable to
Wuffs' decoders but not specific to Wuffs' image decoders.
## API Listing
In Wuffs syntax, the `base.image_decoder` methods are:
- `decode_frame?(dst: ptr pixel_buffer, src: io_reader, blend: pixel_blend, workbuf: slice u8, opts: nptr decode_frame_options)`
- `decode_frame_config?(dst: nptr frame_config, src: io_reader)`
- `decode_image_config?(dst: nptr image_config, src: io_reader)`
- `frame_dirty_rect() rect_ie_u32`
- `num_animation_loops() u32`
- `num_decoded_frame_configs() u64`
- `num_decoded_frames() u64`
- `restart_frame!(index: u64, io_position: u64) status`
- `set_quirk_enabled!(quirk: u32, enabled: bool)`
- `set_report_metadata!(fourcc: u32, report: bool)`
- `tell_me_more?(dst: io_writer, minfo: nptr more_information, src: io_reader)`
- `workbuf_len() range_ii_u64`
## Implementations
- [std/bmp](/std/bmp)
- [std/gif](/std/gif)
- [std/nie](/std/nie)
- [std/png](/std/png)
- [std/tga](/std/tga)
- [std/wbmp](/std/wbmp)
## Examples
- [example/convert-to-nia](/example/convert-to-nia)
- [example/gifplayer](/example/gifplayer)
- [example/imageviewer](/example/imageviewer)
- [example/sdl-imageviewer](/example/sdl-imageviewer)
- [script/print-average-pixel](/script/print-average-pixel.cc)
- [script/print-image-metadata](/script/print-image-metadata.cc)
Examples in other repositories:
- [Skia](https://skia.googlesource.com/skia/+/refs/heads/master/src/codec/SkWuffsCodec.cpp),
a 2-D graphics library used by the Android operating system and the Chromium
web browser.
## [Quirks](/doc/note/quirks.md)
- [GIF decoder quirks](/std/gif/decode_quirks.wuffs)
## Related Documentation
- [I/O (Input / Output)](/doc/note/io-input-output.md)
- [Pixel Formats](/doc/note/pixel-formats.md)
- [Pixel Subsampling](/doc/note/pixel-subsampling.md)
- [Ranges and Rects](/doc/note/ranges-and-rects.md)
See also the general remarks on [Wuffs' standard library](/doc/std/README.md).