blob: 41adfbe67582e8829fa1883b3668391597d3b8b9 [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).
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
Images can also contain metadata (e.g. color profiles, time stamps). By
default, Wuffs' image decoders skip over metadata, but calling
`set_report_metadata` will opt in to having `decode_image_config` return early
when encountering metadata in the file. Calling `set_report_metadata` can be
done multiple times, each with a different
[FourCC](/doc/note/base38-and-fourcc.md) code such as `0x49434350` "ICCP" or
`0x584D5020` "XMP ", to indicate what sorts of metadata the caller is
interested in. Conversely, when the parser encounters metadata (and returns a
"@metadata reported" [status](/doc/note/statuses.md)), call `metadata_fourcc`
to see what sort of metadata it is.
Embedded metadata needs to be processed by a separate parser. For example,
processing XMP metadata usually involves some sort of XML parser, regardless of
what particular image format that XMP metadata was embedded in. That metadata
might also be in multiple (non-contiguous) chunks. The caller needs to loop,
repeatedly calling `metadata_chunk_length`, advancing the `io_buffer` by that
many bytes (after diverting those bytes to the separate parser) and calling
`ack_metadata_chunk`. If the latter returns "@metadata reported", then repeat
the loop. If it returns ok, then the metadata was completely consumed, and the
caller can go back to the `decode_image_config` method.
## Implementations
- [std/bmp](/std/bmp)
- [std/gif](/std/gif)
- [std/nie](/std/nie)
- [std/png](/std/png)
- [std/wbmp](/std/wbmp)
## Examples
- [example/convert-to-nia](/example/convert-to-nia)
- [example/gifplayer](/example/gifplayer)
- [example/imageviewer](/example/imageviewer)
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).