blob: 1005800684bc9e32ce8221647a1f2c47948677f8 [file] [log] [blame]
// After editing this file, run "go generate" in the parent directory.
// Copyright 2017 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ---------------- Images
// wuffs_base__color_u32_argb_premul is an 8 bit per channel premultiplied
// Alpha, Red, Green, Blue color, as a uint32_t value. It is in word order, not
// byte order: its value is always 0xAARRGGBB, regardless of endianness.
typedef uint32_t wuffs_base__color_u32_argb_premul;
// --------
// wuffs_base__pixel_format encodes the format of the bytes that constitute an
// image frame's pixel data. Its bits:
// - bit 31 is reserved.
// - bits 30 .. 28 encodes color (and channel order, in terms of memory).
// - bit 27 is reserved.
// - bits 26 .. 24 encodes transparency.
// - bits 23 .. 21 are reserved.
// - bit 20 indicates big-endian/MSB-first (as opposed to little/LSB).
// - bit 19 indicates floating point (as opposed to integer).
// - bit 18 indicates palette-indexed. The number-of-planes (the next
// field) will be zero, as the format is considered packed,
// but the 8-bit N-BGRA color data is stored in plane 3.
// - bits 17 .. 16 are the number of planes, minus 1. Zero means packed.
// - bits 15 .. 12 encodes the number of bits (depth) in the 3rd channel.
// - bits 11 .. 8 encodes the number of bits (depth) in the 2nd channel.
// - bits 7 .. 4 encodes the number of bits (depth) in the 1st channel.
// - bits 3 .. 0 encodes the number of bits (depth) in the 0th channel.
//
// The bit fields of a wuffs_base__pixel_format are not independent. For
// example, the number of planes should not be greater than the number of
// channels. Similarly, bits 15..4 are unused (and should be zero) if bits
// 31..24 (color and transparency) together imply only 1 channel (gray, no
// alpha) and floating point samples should mean a bit depth of 16, 32 or 64.
//
// Formats hold between 1 and 4 channels. For example: Y (1 channel: gray), YA
// (2 channels: gray and alpha), BGR (3 channels: blue, green, red) or CMYK (4
// channels: cyan, magenta, yellow, black).
//
// For direct formats with N > 1 channels, those channels can be laid out in
// either 1 (packed) or N (planar) planes. For example, RGBA data is usually
// packed, but YCbCr data is usually planar, due to chroma subsampling (for
// details, see the wuffs_base__pixel_subsampling type).
//
// For indexed formats, the palette (always 256 × 4 bytes) holds 8 bits per
// channel non-alpha-premultiplied BGRA color data. There is only 1 plane (for
// the index), as the format is considered packed. Plane 0 holds the per-pixel
// indices. Plane 3 is re-purposed to hold the per-index colors.
//
// The color field is encoded in 3 bits:
// - 0 means A (Alpha).
// - 1 means Y or YA (Gray, Alpha).
// - 2 means YCbCr or YCbCrA (Luma, Chroma-blue, Chroma-red, Alpha).
// - 3 means YCoCg or YCoCgA (Luma, Chroma-orange, Chroma-green, Alpha).
// - 4 means BGR, BGRX or BGRA (Blue, Green, Red, X-padding or Alpha).
// - 5 means RGB, RGBX or RGBA (Red, Green, Blue, X-padding or Alpha).
// - 6 means CMY or CMYK (Cyan, Magenta, Yellow, Black).
// - all other values are reserved.
//
// In Wuffs, channels are given in memory order (also known as byte order),
// regardless of endianness, since the C type for the pixel data is an array of
// bytes, not an array of uint32_t. For example, packed BGRA with 8 bits per
// channel means that the bytes in memory are always Blue, Green, Red then
// Alpha. On big-endian systems, that is the uint32_t 0xBBGGRRAA. On
// little-endian, 0xAARRGGBB.
//
// When the color field (3 bits) encodes multiple options, the transparency
// field (3 bits) distinguishes them:
// - 0 means fully opaque, no extra channels
// - 1 means fully opaque, one extra channel (X or K, padding or black).
// - 5 means one extra alpha channel, other channels are non-premultiplied.
// - 6 means one extra alpha channel, other channels are premultiplied.
// - 7 means one extra alpha channel, binary alpha.
// - all other values are reserved.
//
// Binary alpha means that if a color is not completely opaque, it is
// completely transparent black. As a source pixel format, it can therefore be
// treated as either non-premultiplied or premultiplied.
//
// The zero wuffs_base__pixel_format value is an invalid pixel format, as it is
// invalid to combine the zero color (alpha only) with the zero transparency.
//
// Bit depth is encoded in 4 bits:
// - 0 means the channel or index is unused.
// - x means a bit depth of x, for x in the range 1..8.
// - 9 means a bit depth of 10.
// - 10 means a bit depth of 12.
// - 11 means a bit depth of 16.
// - 12 means a bit depth of 24.
// - 13 means a bit depth of 32.
// - 14 means a bit depth of 48.
// - 15 means a bit depth of 64.
//
// For example, wuffs_base__pixel_format 0x5510BBBB is a natural format for
// decoding a PNG image - network byte order (also known as big-endian),
// packed, non-premultiplied alpha - that happens to be 16-bit-depth truecolor
// with alpha (RGBA). In memory order:
//
// ptr+0 ptr+1 ptr+2 ptr+3 ptr+4 ptr+5 ptr+6 ptr+7
// Rhi Rlo Ghi Glo Bhi Blo Ahi Alo
//
// For example, the value wuffs_base__pixel_format 0x40000565 means BGR with no
// alpha or padding, 5/6/5 bits for blue/green/red, packed 2 bytes per pixel,
// laid out LSB-first in memory order:
//
// ptr+0........... ptr+1...........
// MSB LSB MSB LSB
// G₂G₁G₀B₄B₃B₂B₁B₀ R₄R₃R₂R₁R₀G₅G₄G₃
//
// On little-endian systems (but not big-endian), this Wuffs pixel format value
// (0x40000565) corresponds to the Cairo library's CAIRO_FORMAT_RGB16_565, the
// SDL2 (Simple DirectMedia Layer 2) library's SDL_PIXELFORMAT_RGB565 and the
// Skia library's kRGB_565_SkColorType. Note BGR in Wuffs versus RGB in the
// other libraries.
//
// Regardless of endianness, this Wuffs pixel format value (0x40000565)
// corresponds to the V4L2 (Video For Linux 2) library's V4L2_PIX_FMT_RGB565
// and the Wayland-DRM library's WL_DRM_FORMAT_RGB565.
//
// Different software libraries name their pixel formats (and especially their
// channel order) either according to memory layout or as bits of a native
// integer type like uint32_t. The two conventions differ because of a system's
// endianness. As mentioned earlier, Wuffs pixel formats are always in memory
// order. More detail of other software libraries' naming conventions is in the
// Pixel Format Guide at https://afrantzis.github.io/pixel-format-guide/
//
// Do not manipulate these bits directly; they are private implementation
// details. Use methods such as wuffs_base__pixel_format__num_planes instead.
typedef uint32_t wuffs_base__pixel_format;
// Common 8-bit-depth pixel formats. This list is not exhaustive; not all valid
// wuffs_base__pixel_format values are present.
#define WUFFS_BASE__PIXEL_FORMAT__INVALID ((wuffs_base__pixel_format)0x00000000)
#define WUFFS_BASE__PIXEL_FORMAT__A ((wuffs_base__pixel_format)0x02000008)
#define WUFFS_BASE__PIXEL_FORMAT__Y ((wuffs_base__pixel_format)0x10000008)
#define WUFFS_BASE__PIXEL_FORMAT__YA_NONPREMUL \
((wuffs_base__pixel_format)0x15000008)
#define WUFFS_BASE__PIXEL_FORMAT__YA_PREMUL \
((wuffs_base__pixel_format)0x16000008)
#define WUFFS_BASE__PIXEL_FORMAT__YCBCR ((wuffs_base__pixel_format)0x20020888)
#define WUFFS_BASE__PIXEL_FORMAT__YCBCRK ((wuffs_base__pixel_format)0x21038888)
#define WUFFS_BASE__PIXEL_FORMAT__YCBCRA_NONPREMUL \
((wuffs_base__pixel_format)0x25038888)
#define WUFFS_BASE__PIXEL_FORMAT__YCOCG ((wuffs_base__pixel_format)0x30020888)
#define WUFFS_BASE__PIXEL_FORMAT__YCOCGK ((wuffs_base__pixel_format)0x31038888)
#define WUFFS_BASE__PIXEL_FORMAT__YCOCGA_NONPREMUL \
((wuffs_base__pixel_format)0x35038888)
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL \
((wuffs_base__pixel_format)0x45040008)
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL \
((wuffs_base__pixel_format)0x46040008)
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY \
((wuffs_base__pixel_format)0x47040008)
#define WUFFS_BASE__PIXEL_FORMAT__BGR ((wuffs_base__pixel_format)0x40000888)
#define WUFFS_BASE__PIXEL_FORMAT__BGRX ((wuffs_base__pixel_format)0x41008888)
#define WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL \
((wuffs_base__pixel_format)0x45008888)
#define WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL \
((wuffs_base__pixel_format)0x46008888)
#define WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY \
((wuffs_base__pixel_format)0x47008888)
#define WUFFS_BASE__PIXEL_FORMAT__RGB ((wuffs_base__pixel_format)0x50000888)
#define WUFFS_BASE__PIXEL_FORMAT__RGBX ((wuffs_base__pixel_format)0x51008888)
#define WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL \
((wuffs_base__pixel_format)0x55008888)
#define WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL \
((wuffs_base__pixel_format)0x56008888)
#define WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY \
((wuffs_base__pixel_format)0x57008888)
#define WUFFS_BASE__PIXEL_FORMAT__CMY ((wuffs_base__pixel_format)0x60020888)
#define WUFFS_BASE__PIXEL_FORMAT__CMYK ((wuffs_base__pixel_format)0x61038888)
extern const uint32_t wuffs_base__pixel_format__bits_per_channel[16];
static inline bool //
wuffs_base__pixel_format__is_valid(wuffs_base__pixel_format f) {
return f != 0;
}
// wuffs_base__pixel_format__bits_per_pixel returns, for packed pixel formats,
// the number of bits per pixel. It returns 0 for planar pixel formats.
static inline uint32_t //
wuffs_base__pixel_format__bits_per_pixel(wuffs_base__pixel_format f) {
if (((f >> 16) & 0x03) != 0) {
return 0;
}
return wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 0)] +
wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 4)] +
wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 8)] +
wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 12)];
}
static inline bool //
wuffs_base__pixel_format__is_indexed(wuffs_base__pixel_format f) {
return (f >> 18) & 0x01;
}
static inline bool //
wuffs_base__pixel_format__is_packed(wuffs_base__pixel_format f) {
return ((f >> 16) & 0x03) == 0;
}
static inline bool //
wuffs_base__pixel_format__is_planar(wuffs_base__pixel_format f) {
return ((f >> 16) & 0x03) != 0;
}
static inline uint32_t //
wuffs_base__pixel_format__num_planes(wuffs_base__pixel_format f) {
return ((f >> 16) & 0x03) + 1;
}
#define WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX 4
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__INDEX_PLANE 0
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE 3
// --------
// wuffs_base__pixel_subsampling encodes the mapping of pixel space coordinates
// (x, y) to pixel buffer indices (i, j). That mapping can differ for each
// plane p. For a depth of 8 bits (1 byte), the p'th plane's sample starts at
// (planes[p].ptr + (j * planes[p].stride) + i).
//
// For packed pixel formats, the mapping is trivial: i = x and j = y. For
// planar pixel formats, the mapping can differ due to chroma subsampling. For
// example, consider a three plane YCbCr pixel format with 4:2:2 subsampling.
// For the luma (Y) channel, there is one sample for every pixel, but for the
// chroma (Cb, Cr) channels, there is one sample for every two pixels: pairs of
// horizontally adjacent pixels form one macropixel, i = x / 2 and j == y. In
// general, for a given p:
// - i = (x + bias_x) >> shift_x.
// - j = (y + bias_y) >> shift_y.
// where biases and shifts are in the range 0..3 and 0..2 respectively.
//
// In general, the biases will be zero after decoding an image. However, making
// a sub-image may change the bias, since the (x, y) coordinates are relative
// to the sub-image's top-left origin, but the backing pixel buffers were
// created relative to the original image's origin.
//
// For each plane p, each of those four numbers (biases and shifts) are encoded
// in two bits, which combine to form an 8 bit unsigned integer:
//
// e_p = (bias_x << 6) | (shift_x << 4) | (bias_y << 2) | (shift_y << 0)
//
// Those e_p values (e_0 for the first plane, e_1 for the second plane, etc)
// combine to form a wuffs_base__pixel_subsampling value:
//
// pixsub = (e_3 << 24) | (e_2 << 16) | (e_1 << 8) | (e_0 << 0)
//
// Do not manipulate these bits directly; they are private implementation
// details. Use methods such as wuffs_base__pixel_subsampling__bias_x instead.
typedef uint32_t wuffs_base__pixel_subsampling;
#define WUFFS_BASE__PIXEL_SUBSAMPLING__NONE ((wuffs_base__pixel_subsampling)0)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__444 \
((wuffs_base__pixel_subsampling)0x000000)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__440 \
((wuffs_base__pixel_subsampling)0x010100)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__422 \
((wuffs_base__pixel_subsampling)0x101000)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__420 \
((wuffs_base__pixel_subsampling)0x111100)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__411 \
((wuffs_base__pixel_subsampling)0x202000)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__410 \
((wuffs_base__pixel_subsampling)0x212100)
static inline uint32_t //
wuffs_base__pixel_subsampling__bias_x(wuffs_base__pixel_subsampling s,
uint32_t plane) {
uint32_t shift = ((plane & 0x03) * 8) + 6;
return (s >> shift) & 0x03;
}
static inline uint32_t //
wuffs_base__pixel_subsampling__shift_x(wuffs_base__pixel_subsampling s,
uint32_t plane) {
uint32_t shift = ((plane & 0x03) * 8) + 4;
return (s >> shift) & 0x03;
}
static inline uint32_t //
wuffs_base__pixel_subsampling__bias_y(wuffs_base__pixel_subsampling s,
uint32_t plane) {
uint32_t shift = ((plane & 0x03) * 8) + 2;
return (s >> shift) & 0x03;
}
static inline uint32_t //
wuffs_base__pixel_subsampling__shift_y(wuffs_base__pixel_subsampling s,
uint32_t plane) {
uint32_t shift = ((plane & 0x03) * 8) + 0;
return (s >> shift) & 0x03;
}
// --------
typedef struct {
// Do not access the private_impl's fields directly. There is no API/ABI
// compatibility or safety guarantee if you do so.
struct {
wuffs_base__pixel_format pixfmt;
wuffs_base__pixel_subsampling pixsub;
uint32_t width;
uint32_t height;
} private_impl;
#ifdef __cplusplus
inline void set(wuffs_base__pixel_format pixfmt,
wuffs_base__pixel_subsampling pixsub,
uint32_t width,
uint32_t height);
inline void invalidate();
inline bool is_valid() const;
inline wuffs_base__pixel_format pixel_format() const;
inline wuffs_base__pixel_subsampling pixel_subsampling() const;
inline wuffs_base__rect_ie_u32 bounds() const;
inline uint32_t width() const;
inline uint32_t height() const;
inline uint64_t pixbuf_len() const;
#endif // __cplusplus
} wuffs_base__pixel_config;
static inline wuffs_base__pixel_config //
wuffs_base__null_pixel_config() {
wuffs_base__pixel_config ret;
ret.private_impl.pixfmt = 0;
ret.private_impl.pixsub = 0;
ret.private_impl.width = 0;
ret.private_impl.height = 0;
return ret;
}
// TODO: Should this function return bool? An error type?
static inline void //
wuffs_base__pixel_config__set(wuffs_base__pixel_config* c,
wuffs_base__pixel_format pixfmt,
wuffs_base__pixel_subsampling pixsub,
uint32_t width,
uint32_t height) {
if (!c) {
return;
}
if (pixfmt) {
uint64_t wh = ((uint64_t)width) * ((uint64_t)height);
// TODO: handle things other than 1 byte per pixel.
if (wh <= ((uint64_t)SIZE_MAX)) {
c->private_impl.pixfmt = pixfmt;
c->private_impl.pixsub = pixsub;
c->private_impl.width = width;
c->private_impl.height = height;
return;
}
}
c->private_impl.pixfmt = 0;
c->private_impl.pixsub = 0;
c->private_impl.width = 0;
c->private_impl.height = 0;
}
static inline void //
wuffs_base__pixel_config__invalidate(wuffs_base__pixel_config* c) {
if (c) {
c->private_impl.pixfmt = 0;
c->private_impl.pixsub = 0;
c->private_impl.width = 0;
c->private_impl.height = 0;
}
}
static inline bool //
wuffs_base__pixel_config__is_valid(const wuffs_base__pixel_config* c) {
return c && c->private_impl.pixfmt;
}
static inline wuffs_base__pixel_format //
wuffs_base__pixel_config__pixel_format(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.pixfmt : 0;
}
static inline wuffs_base__pixel_subsampling //
wuffs_base__pixel_config__pixel_subsampling(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.pixsub : 0;
}
static inline wuffs_base__rect_ie_u32 //
wuffs_base__pixel_config__bounds(const wuffs_base__pixel_config* c) {
if (c) {
wuffs_base__rect_ie_u32 ret;
ret.min_incl_x = 0;
ret.min_incl_y = 0;
ret.max_excl_x = c->private_impl.width;
ret.max_excl_y = c->private_impl.height;
return ret;
}
wuffs_base__rect_ie_u32 ret;
ret.min_incl_x = 0;
ret.min_incl_y = 0;
ret.max_excl_x = 0;
ret.max_excl_y = 0;
return ret;
}
static inline uint32_t //
wuffs_base__pixel_config__width(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.width : 0;
}
static inline uint32_t //
wuffs_base__pixel_config__height(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.height : 0;
}
// TODO: this is the right API for planar (not packed) pixbufs? Should it allow
// decoding into a color model different from the format's intrinsic one? For
// example, decoding a JPEG image straight to RGBA instead of to YCbCr?
static inline uint64_t //
wuffs_base__pixel_config__pixbuf_len(const wuffs_base__pixel_config* c) {
if (!c) {
return 0;
}
if (wuffs_base__pixel_format__is_planar(c->private_impl.pixfmt)) {
// TODO: support planar pixel formats, concious of pixel subsampling.
return 0;
}
uint32_t bits_per_pixel =
wuffs_base__pixel_format__bits_per_pixel(c->private_impl.pixfmt);
if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {
// TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?
return 0;
}
uint64_t bytes_per_pixel = bits_per_pixel / 8;
uint64_t n =
((uint64_t)c->private_impl.width) * ((uint64_t)c->private_impl.height);
if (n > (UINT64_MAX / bytes_per_pixel)) {
return 0;
}
n *= bytes_per_pixel;
if (wuffs_base__pixel_format__is_indexed(c->private_impl.pixfmt)) {
if (n > (UINT64_MAX - 1024)) {
return 0;
}
n += 1024;
}
return n;
}
#ifdef __cplusplus
inline void //
wuffs_base__pixel_config::set(wuffs_base__pixel_format pixfmt,
wuffs_base__pixel_subsampling pixsub,
uint32_t width,
uint32_t height) {
wuffs_base__pixel_config__set(this, pixfmt, pixsub, width, height);
}
inline void //
wuffs_base__pixel_config::invalidate() {
wuffs_base__pixel_config__invalidate(this);
}
inline bool //
wuffs_base__pixel_config::is_valid() const {
return wuffs_base__pixel_config__is_valid(this);
}
inline wuffs_base__pixel_format //
wuffs_base__pixel_config::pixel_format() const {
return wuffs_base__pixel_config__pixel_format(this);
}
inline wuffs_base__pixel_subsampling //
wuffs_base__pixel_config::pixel_subsampling() const {
return wuffs_base__pixel_config__pixel_subsampling(this);
}
inline wuffs_base__rect_ie_u32 //
wuffs_base__pixel_config::bounds() const {
return wuffs_base__pixel_config__bounds(this);
}
inline uint32_t //
wuffs_base__pixel_config::width() const {
return wuffs_base__pixel_config__width(this);
}
inline uint32_t //
wuffs_base__pixel_config::height() const {
return wuffs_base__pixel_config__height(this);
}
inline uint64_t //
wuffs_base__pixel_config::pixbuf_len() const {
return wuffs_base__pixel_config__pixbuf_len(this);
}
#endif // __cplusplus
// --------
typedef struct {
wuffs_base__pixel_config pixcfg;
// Do not access the private_impl's fields directly. There is no API/ABI
// compatibility or safety guarantee if you do so.
struct {
uint64_t first_frame_io_position;
bool first_frame_is_opaque;
wuffs_base__color_u32_argb_premul background_color;
} private_impl;
#ifdef __cplusplus
inline void set(wuffs_base__pixel_format pixfmt,
wuffs_base__pixel_subsampling pixsub,
uint32_t width,
uint32_t height,
uint64_t first_frame_io_position,
bool first_frame_is_opaque,
wuffs_base__color_u32_argb_premul background_color);
inline void invalidate();
inline bool is_valid() const;
inline uint64_t first_frame_io_position() const;
inline bool first_frame_is_opaque() const;
inline wuffs_base__color_u32_argb_premul background_color() const;
#endif // __cplusplus
} wuffs_base__image_config;
static inline wuffs_base__image_config //
wuffs_base__null_image_config() {
wuffs_base__image_config ret;
ret.pixcfg = wuffs_base__null_pixel_config();
ret.private_impl.first_frame_io_position = 0;
ret.private_impl.first_frame_is_opaque = false;
return ret;
}
// TODO: Should this function return bool? An error type?
static inline void //
wuffs_base__image_config__set(
wuffs_base__image_config* c,
wuffs_base__pixel_format pixfmt,
wuffs_base__pixel_subsampling pixsub,
uint32_t width,
uint32_t height,
uint64_t first_frame_io_position,
bool first_frame_is_opaque,
wuffs_base__color_u32_argb_premul background_color) {
if (!c) {
return;
}
if (wuffs_base__pixel_format__is_valid(pixfmt)) {
c->pixcfg.private_impl.pixfmt = pixfmt;
c->pixcfg.private_impl.pixsub = pixsub;
c->pixcfg.private_impl.width = width;
c->pixcfg.private_impl.height = height;
c->private_impl.first_frame_io_position = first_frame_io_position;
c->private_impl.first_frame_is_opaque = first_frame_is_opaque;
c->private_impl.background_color = background_color;
return;
}
c->pixcfg.private_impl.pixfmt = 0;
c->pixcfg.private_impl.pixsub = 0;
c->pixcfg.private_impl.width = 0;
c->pixcfg.private_impl.height = 0;
c->private_impl.first_frame_io_position = 0;
c->private_impl.first_frame_is_opaque = 0;
c->private_impl.background_color = 0;
}
static inline void //
wuffs_base__image_config__invalidate(wuffs_base__image_config* c) {
if (c) {
c->pixcfg.private_impl.pixfmt = 0;
c->pixcfg.private_impl.pixsub = 0;
c->pixcfg.private_impl.width = 0;
c->pixcfg.private_impl.height = 0;
c->private_impl.first_frame_io_position = 0;
c->private_impl.first_frame_is_opaque = 0;
c->private_impl.background_color = 0;
}
}
static inline bool //
wuffs_base__image_config__is_valid(const wuffs_base__image_config* c) {
return c && wuffs_base__pixel_config__is_valid(&(c->pixcfg));
}
static inline uint64_t //
wuffs_base__image_config__first_frame_io_position(
const wuffs_base__image_config* c) {
return c ? c->private_impl.first_frame_io_position : 0;
}
static inline bool //
wuffs_base__image_config__first_frame_is_opaque(
const wuffs_base__image_config* c) {
return c ? c->private_impl.first_frame_is_opaque : false;
}
static inline wuffs_base__color_u32_argb_premul //
wuffs_base__image_config__background_color(const wuffs_base__image_config* c) {
return c ? c->private_impl.background_color : 0;
}
#ifdef __cplusplus
inline void //
wuffs_base__image_config::set(
wuffs_base__pixel_format pixfmt,
wuffs_base__pixel_subsampling pixsub,
uint32_t width,
uint32_t height,
uint64_t first_frame_io_position,
bool first_frame_is_opaque,
wuffs_base__color_u32_argb_premul background_color) {
wuffs_base__image_config__set(this, pixfmt, pixsub, width, height,
first_frame_io_position, first_frame_is_opaque,
background_color);
}
inline void //
wuffs_base__image_config::invalidate() {
wuffs_base__image_config__invalidate(this);
}
inline bool //
wuffs_base__image_config::is_valid() const {
return wuffs_base__image_config__is_valid(this);
}
inline uint64_t //
wuffs_base__image_config::first_frame_io_position() const {
return wuffs_base__image_config__first_frame_io_position(this);
}
inline bool //
wuffs_base__image_config::first_frame_is_opaque() const {
return wuffs_base__image_config__first_frame_is_opaque(this);
}
inline wuffs_base__color_u32_argb_premul //
wuffs_base__image_config::background_color() const {
return wuffs_base__image_config__background_color(this);
}
#endif // __cplusplus
// --------
// wuffs_base__animation_blend encodes, for an animated image, how to blend the
// transparent pixels of this frame with the existing canvas. In Porter-Duff
// compositing operator terminology:
// - 0 means the frame may be transparent, and should be blended "src over
// dst", also known as just "over".
// - 1 means the frame may be transparent, and should be blended "src".
// - 2 means the frame is completely opaque, so that "src over dst" and "src"
// are equivalent.
//
// These semantics are conservative. It is valid for a completely opaque frame
// to have a blend value other than 2.
typedef uint8_t wuffs_base__animation_blend;
#define WUFFS_BASE__ANIMATION_BLEND__SRC_OVER_DST \
((wuffs_base__animation_blend)0)
#define WUFFS_BASE__ANIMATION_BLEND__SRC ((wuffs_base__animation_blend)1)
#define WUFFS_BASE__ANIMATION_BLEND__OPAQUE ((wuffs_base__animation_blend)2)
// --------
// wuffs_base__animation_disposal encodes, for an animated image, how to
// dispose of a frame after displaying it:
// - None means to draw the next frame on top of this one.
// - Restore Background means to clear the frame's dirty rectangle to "the
// background color" (in practice, this means transparent black) before
// drawing the next frame.
// - Restore Previous means to undo the current frame, so that the next frame
// is drawn on top of the previous one.
typedef uint8_t wuffs_base__animation_disposal;
#define WUFFS_BASE__ANIMATION_DISPOSAL__NONE ((wuffs_base__animation_disposal)0)
#define WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_BACKGROUND \
((wuffs_base__animation_disposal)1)
#define WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS \
((wuffs_base__animation_disposal)2)
// --------
typedef struct {
// Do not access the private_impl's fields directly. There is no API/ABI
// compatibility or safety guarantee if you do so.
struct {
wuffs_base__rect_ie_u32 bounds;
wuffs_base__flicks duration;
uint64_t index;
uint64_t io_position;
wuffs_base__animation_blend blend;
wuffs_base__animation_disposal disposal;
wuffs_base__color_u32_argb_premul background_color;
} private_impl;
#ifdef __cplusplus
inline void update(wuffs_base__rect_ie_u32 bounds,
wuffs_base__flicks duration,
uint64_t index,
uint64_t io_position,
wuffs_base__animation_blend blend,
wuffs_base__animation_disposal disposal,
wuffs_base__color_u32_argb_premul background_color);
inline wuffs_base__rect_ie_u32 bounds() const;
inline uint32_t width() const;
inline uint32_t height() const;
inline wuffs_base__flicks duration() const;
inline uint64_t index() const;
inline uint64_t io_position() const;
inline wuffs_base__animation_blend blend() const;
inline wuffs_base__animation_disposal disposal() const;
inline wuffs_base__color_u32_argb_premul background_color() const;
#endif // __cplusplus
} wuffs_base__frame_config;
static inline wuffs_base__frame_config //
wuffs_base__null_frame_config() {
wuffs_base__frame_config ret;
ret.private_impl.bounds = wuffs_base__make_rect_ie_u32(0, 0, 0, 0);
ret.private_impl.duration = 0;
ret.private_impl.index = 0;
ret.private_impl.io_position = 0;
ret.private_impl.blend = 0;
ret.private_impl.disposal = 0;
return ret;
}
static inline void //
wuffs_base__frame_config__update(
wuffs_base__frame_config* c,
wuffs_base__rect_ie_u32 bounds,
wuffs_base__flicks duration,
uint64_t index,
uint64_t io_position,
wuffs_base__animation_blend blend,
wuffs_base__animation_disposal disposal,
wuffs_base__color_u32_argb_premul background_color) {
if (!c) {
return;
}
c->private_impl.bounds = bounds;
c->private_impl.duration = duration;
c->private_impl.index = index;
c->private_impl.io_position = io_position;
c->private_impl.blend = blend;
c->private_impl.disposal = disposal;
c->private_impl.background_color = background_color;
}
static inline wuffs_base__rect_ie_u32 //
wuffs_base__frame_config__bounds(const wuffs_base__frame_config* c) {
if (c) {
return c->private_impl.bounds;
}
wuffs_base__rect_ie_u32 ret;
ret.min_incl_x = 0;
ret.min_incl_y = 0;
ret.max_excl_x = 0;
ret.max_excl_y = 0;
return ret;
}
static inline uint32_t //
wuffs_base__frame_config__width(const wuffs_base__frame_config* c) {
return c ? wuffs_base__rect_ie_u32__width(&c->private_impl.bounds) : 0;
}
static inline uint32_t //
wuffs_base__frame_config__height(const wuffs_base__frame_config* c) {
return c ? wuffs_base__rect_ie_u32__height(&c->private_impl.bounds) : 0;
}
// wuffs_base__frame_config__duration returns the amount of time to display
// this frame. Zero means to display forever - a still (non-animated) image.
static inline wuffs_base__flicks //
wuffs_base__frame_config__duration(const wuffs_base__frame_config* c) {
return c ? c->private_impl.duration : 0;
}
// wuffs_base__frame_config__index returns the index of this frame. The first
// frame in an image has index 0, the second frame has index 1, and so on.
static inline uint64_t //
wuffs_base__frame_config__index(const wuffs_base__frame_config* c) {
return c ? c->private_impl.index : 0;
}
// wuffs_base__frame_config__io_position returns the I/O stream position before
// the frame config.
static inline uint64_t //
wuffs_base__frame_config__io_position(const wuffs_base__frame_config* c) {
return c ? c->private_impl.io_position : 0;
}
// wuffs_base__frame_config__blend returns, for an animated image, how to blend
// the transparent pixels of this frame with the existing canvas.
static inline wuffs_base__animation_blend //
wuffs_base__frame_config__blend(const wuffs_base__frame_config* c) {
return c ? c->private_impl.blend : 0;
}
// wuffs_base__frame_config__disposal returns, for an animated image, how to
// dispose of this frame after displaying it.
static inline wuffs_base__animation_disposal //
wuffs_base__frame_config__disposal(const wuffs_base__frame_config* c) {
return c ? c->private_impl.disposal : 0;
}
static inline wuffs_base__color_u32_argb_premul //
wuffs_base__frame_config__background_color(const wuffs_base__frame_config* c) {
return c ? c->private_impl.background_color : 0;
}
#ifdef __cplusplus
inline void //
wuffs_base__frame_config::update(
wuffs_base__rect_ie_u32 bounds,
wuffs_base__flicks duration,
uint64_t index,
uint64_t io_position,
wuffs_base__animation_blend blend,
wuffs_base__animation_disposal disposal,
wuffs_base__color_u32_argb_premul background_color) {
wuffs_base__frame_config__update(this, bounds, duration, index, io_position,
blend, disposal, background_color);
}
inline wuffs_base__rect_ie_u32 //
wuffs_base__frame_config::bounds() const {
return wuffs_base__frame_config__bounds(this);
}
inline uint32_t //
wuffs_base__frame_config::width() const {
return wuffs_base__frame_config__width(this);
}
inline uint32_t //
wuffs_base__frame_config::height() const {
return wuffs_base__frame_config__height(this);
}
inline wuffs_base__flicks //
wuffs_base__frame_config::duration() const {
return wuffs_base__frame_config__duration(this);
}
inline uint64_t //
wuffs_base__frame_config::index() const {
return wuffs_base__frame_config__index(this);
}
inline uint64_t //
wuffs_base__frame_config::io_position() const {
return wuffs_base__frame_config__io_position(this);
}
inline wuffs_base__animation_blend //
wuffs_base__frame_config::blend() const {
return wuffs_base__frame_config__blend(this);
}
inline wuffs_base__animation_disposal //
wuffs_base__frame_config::disposal() const {
return wuffs_base__frame_config__disposal(this);
}
inline wuffs_base__color_u32_argb_premul //
wuffs_base__frame_config::background_color() const {
return wuffs_base__frame_config__background_color(this);
}
#endif // __cplusplus
// --------
typedef struct {
wuffs_base__pixel_config pixcfg;
// Do not access the private_impl's fields directly. There is no API/ABI
// compatibility or safety guarantee if you do so.
struct {
wuffs_base__table_u8 planes[WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX];
// TODO: color spaces.
} private_impl;
#ifdef __cplusplus
inline wuffs_base__status set_from_slice(wuffs_base__pixel_config* pixcfg,
wuffs_base__slice_u8 pixbuf_memory);
inline wuffs_base__slice_u8 palette();
inline wuffs_base__pixel_format pixel_format() const;
inline wuffs_base__table_u8 plane(uint32_t p);
#endif // __cplusplus
} wuffs_base__pixel_buffer;
static inline wuffs_base__pixel_buffer //
wuffs_base__null_pixel_buffer() {
wuffs_base__pixel_buffer ret;
ret.pixcfg = wuffs_base__null_pixel_config();
ret.private_impl.planes[0] = wuffs_base__null_table_u8();
ret.private_impl.planes[1] = wuffs_base__null_table_u8();
ret.private_impl.planes[2] = wuffs_base__null_table_u8();
ret.private_impl.planes[3] = wuffs_base__null_table_u8();
return ret;
}
static inline wuffs_base__status //
wuffs_base__pixel_buffer__set_from_slice(wuffs_base__pixel_buffer* b,
wuffs_base__pixel_config* pixcfg,
wuffs_base__slice_u8 pixbuf_memory) {
if (!b) {
return wuffs_base__error__bad_receiver;
}
memset(b, 0, sizeof(*b));
if (!pixcfg) {
return wuffs_base__error__bad_argument;
}
if (wuffs_base__pixel_format__is_planar(pixcfg->private_impl.pixfmt)) {
// TODO: support planar pixel formats, concious of pixel subsampling.
return wuffs_base__error__bad_argument;
}
uint32_t bits_per_pixel =
wuffs_base__pixel_format__bits_per_pixel(pixcfg->private_impl.pixfmt);
if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {
return wuffs_base__error__bad_argument;
}
uint64_t bytes_per_pixel = bits_per_pixel / 8;
uint8_t* ptr = pixbuf_memory.ptr;
uint64_t len = pixbuf_memory.len;
if (wuffs_base__pixel_format__is_indexed(pixcfg->private_impl.pixfmt)) {
// Split a 1024 byte chunk (256 palette entries × 4 bytes per entry) from
// the start of pixbuf_memory. We split from the start, not the end, so
// that the both chunks' pointers have the same alignment as the original
// pointer, up to an alignment of 1024.
if (len < 1024) {
return wuffs_base__error__bad_argument_length_too_short;
}
wuffs_base__table_u8* tab =
&b->private_impl.planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];
tab->ptr = ptr;
tab->width = 1024;
tab->height = 1;
tab->stride = 1024;
ptr += 1024;
len -= 1024;
}
uint64_t wh = ((uint64_t)pixcfg->private_impl.width) *
((uint64_t)pixcfg->private_impl.height);
size_t width = (size_t)(pixcfg->private_impl.width);
if ((wh > (UINT64_MAX / bytes_per_pixel)) ||
(width > (SIZE_MAX / bytes_per_pixel))) {
return wuffs_base__error__bad_argument;
}
wh *= bytes_per_pixel;
width *= bytes_per_pixel;
if (wh > len) {
return wuffs_base__error__bad_argument_length_too_short;
}
b->pixcfg = *pixcfg;
wuffs_base__table_u8* tab = &b->private_impl.planes[0];
tab->ptr = ptr;
tab->width = width;
tab->height = pixcfg->private_impl.height;
tab->stride = width;
return NULL;
}
// wuffs_base__pixel_buffer__palette returns the palette color data. If
// non-empty, it will have length 1024.
static inline wuffs_base__slice_u8 //
wuffs_base__pixel_buffer__palette(wuffs_base__pixel_buffer* b) {
if (b &&
wuffs_base__pixel_format__is_indexed(b->pixcfg.private_impl.pixfmt)) {
wuffs_base__table_u8* tab =
&b->private_impl.planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];
if ((tab->width == 1024) && (tab->height == 1)) {
return wuffs_base__make_slice_u8(tab->ptr, 1024);
}
}
return wuffs_base__make_slice_u8(NULL, 0);
}
static inline wuffs_base__pixel_format //
wuffs_base__pixel_buffer__pixel_format(const wuffs_base__pixel_buffer* b) {
if (b) {
return b->pixcfg.private_impl.pixfmt;
}
return WUFFS_BASE__PIXEL_FORMAT__INVALID;
}
static inline wuffs_base__table_u8 //
wuffs_base__pixel_buffer__plane(wuffs_base__pixel_buffer* b, uint32_t p) {
if (b && (p < WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX)) {
return b->private_impl.planes[p];
}
wuffs_base__table_u8 ret;
ret.ptr = NULL;
ret.width = 0;
ret.height = 0;
ret.stride = 0;
return ret;
}
#ifdef __cplusplus
inline wuffs_base__status //
wuffs_base__pixel_buffer::set_from_slice(wuffs_base__pixel_config* pixcfg,
wuffs_base__slice_u8 pixbuf_memory) {
return wuffs_base__pixel_buffer__set_from_slice(this, pixcfg, pixbuf_memory);
}
inline wuffs_base__slice_u8 //
wuffs_base__pixel_buffer::palette() {
return wuffs_base__pixel_buffer__palette(this);
}
inline wuffs_base__pixel_format //
wuffs_base__pixel_buffer::pixel_format() const {
return wuffs_base__pixel_buffer__pixel_format(this);
}
inline wuffs_base__table_u8 //
wuffs_base__pixel_buffer::plane(uint32_t p) {
return wuffs_base__pixel_buffer__plane(this, p);
}
#endif // __cplusplus
// --------
typedef struct {
// Do not access the private_impl's fields directly. There is no API/ABI
// compatibility or safety guarantee if you do so.
struct {
uint8_t TODO;
} private_impl;
#ifdef __cplusplus
#endif // __cplusplus
} wuffs_base__decode_frame_options;
#ifdef __cplusplus
#endif // __cplusplus
// --------
typedef struct {
// Do not access the private_impl's fields directly. There is no API/ABI
// compatibility or safety guarantee if you do so.
struct {
// TODO: should the func type take restrict pointers?
uint64_t (*func)(wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 dst_palette,
wuffs_base__slice_u8 src);
} private_impl;
#ifdef __cplusplus
inline void prepare(wuffs_base__pixel_format dst_format,
wuffs_base__slice_u8 dst_palette,
wuffs_base__pixel_format src_format,
wuffs_base__slice_u8 src_palette);
inline uint64_t swizzle_packed(wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 dst_palette,
wuffs_base__slice_u8 src) const;
#endif // __cplusplus
} wuffs_base__pixel_swizzler;
// TODO: should prepare (both the C and C++ methods) return a status?
void //
wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
wuffs_base__pixel_format dst_format,
wuffs_base__slice_u8 dst_palette,
wuffs_base__pixel_format src_format,
wuffs_base__slice_u8 src_palette);
uint64_t //
wuffs_base__pixel_swizzler__swizzle_packed(const wuffs_base__pixel_swizzler* p,
wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 dst_palette,
wuffs_base__slice_u8 src);
#ifdef __cplusplus
inline void //
wuffs_base__pixel_swizzler::prepare(wuffs_base__pixel_format dst_format,
wuffs_base__slice_u8 dst_palette,
wuffs_base__pixel_format src_format,
wuffs_base__slice_u8 src_palette) {
wuffs_base__pixel_swizzler__prepare(this, dst_format, dst_palette, src_format,
src_palette);
}
uint64_t //
wuffs_base__pixel_swizzler::swizzle_packed(wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 dst_palette,
wuffs_base__slice_u8 src) const {
return wuffs_base__pixel_swizzler__swizzle_packed(this, dst, dst_palette,
src);
}
#endif // __cplusplus