Add pixel_buffer.set_color_u32_fill_rect
diff --git a/example/imageviewer/imageviewer.cc b/example/imageviewer/imageviewer.cc
index 4a8fc07..3e6e2c4 100644
--- a/example/imageviewer/imageviewer.cc
+++ b/example/imageviewer/imageviewer.cc
@@ -89,42 +89,6 @@
wuffs_base__slice_u8 g_pixbuf_mem_slice = {0};
uint32_t g_background_color_index = 0;
-class Callbacks : public wuffs_aux::DecodeImageCallbacks {
- DecodeImageCallbacks::AllocResult //
- OnImageConfig(const wuffs_base__image_config& image_config) override {
- uint32_t w = image_config.pixcfg.width();
- uint32_t h = image_config.pixcfg.height();
- if ((w == 0) || (h == 0)) {
- return DecodeImageCallbacks::AllocResult("");
- }
- uint64_t len = image_config.pixcfg.pixbuf_len();
- if ((len == 0) || (SIZE_MAX < len)) {
- return DecodeImageCallbacks::AllocResult(
- wuffs_aux::DecodeImage_UnsupportedPixelConfiguration);
- }
- void* ptr = malloc((size_t)len);
- if (!ptr) {
- return DecodeImageCallbacks::AllocResult(
- wuffs_aux::DecodeImage_OutOfMemory);
- }
-
- // Fill in the background color. The default OnImageConfig implementation
- // fills with zeroes (transparent black).
- wuffs_base__color_u32_argb_premul color =
- g_background_colors[g_background_color_index];
- uint8_t* p4 = (uint8_t*)ptr;
- size_t n4 = ((size_t)len) / 4;
- for (size_t i = 0; i < n4; i++) {
- wuffs_base__poke_u32le__no_bounds_check(p4, color);
- p4 += 4;
- }
-
- return DecodeImageCallbacks::AllocResult(
- wuffs_aux::MemOwner(ptr, &free),
- wuffs_base__make_slice_u8((uint8_t*)ptr, (size_t)len));
- }
-};
-
bool //
load_image(const char* filename) {
FILE* file = stdin;
@@ -144,13 +108,14 @@
g_pixbuf_mem_owner.reset();
g_pixbuf_mem_slice = wuffs_base__empty_slice_u8();
- Callbacks callbacks;
+ wuffs_aux::DecodeImageCallbacks callbacks;
wuffs_aux::sync_io::FileInput input(file);
wuffs_aux::DecodeImageResult res = wuffs_aux::DecodeImage(
callbacks, input, WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL,
// Use PIXEL_BLEND__SRC_OVER, not the default PIXEL_BLEND__SRC, because
- // we override OnImageConfig to fill in the background color.
- WUFFS_BASE__PIXEL_BLEND__SRC_OVER, MAX_INCL_DIMENSION);
+ // we also pass a background color.
+ WUFFS_BASE__PIXEL_BLEND__SRC_OVER,
+ g_background_colors[g_background_color_index], MAX_INCL_DIMENSION);
if (filename) {
fclose(file);
}
diff --git a/internal/cgen/auxiliary/image.cc b/internal/cgen/auxiliary/image.cc
index bbc133b..fded2ef 100644
--- a/internal/cgen/auxiliary/image.cc
+++ b/internal/cgen/auxiliary/image.cc
@@ -87,7 +87,8 @@
DecodeImageCallbacks::AllocResult //
DecodeImageCallbacks::OnImageConfig(
- const wuffs_base__image_config& image_config) {
+ const wuffs_base__image_config& image_config,
+ bool allow_uninitialized_memory) {
uint32_t w = image_config.pixcfg.width();
uint32_t h = image_config.pixcfg.height();
if ((w == 0) || (h == 0)) {
@@ -97,28 +98,29 @@
if ((len == 0) || (SIZE_MAX < len)) {
return AllocResult(DecodeImage_UnsupportedPixelConfiguration);
}
- void* ptr = calloc((size_t)len, 1);
- if (!ptr) {
- return AllocResult(DecodeImage_OutOfMemory);
- }
- return AllocResult(MemOwner(ptr, &free),
- wuffs_base__make_slice_u8((uint8_t*)ptr, (size_t)len));
+ void* ptr =
+ allow_uninitialized_memory ? malloc((size_t)len) : calloc((size_t)len, 1);
+ return ptr ? AllocResult(
+ MemOwner(ptr, &free),
+ wuffs_base__make_slice_u8((uint8_t*)ptr, (size_t)len))
+ : AllocResult(DecodeImage_OutOfMemory);
}
DecodeImageCallbacks::AllocResult //
-DecodeImageCallbacks::AllocWorkbuf(wuffs_base__range_ii_u64 len) {
- if (len.max_incl == 0) {
- return DecodeImageCallbacks::AllocResult("");
- } else if (SIZE_MAX < len.max_incl) {
- return DecodeImageCallbacks::AllocResult(DecodeImage_OutOfMemory);
+DecodeImageCallbacks::AllocWorkbuf(wuffs_base__range_ii_u64 len_range,
+ bool allow_uninitialized_memory) {
+ uint64_t len = len_range.max_incl;
+ if (len == 0) {
+ return AllocResult("");
+ } else if (SIZE_MAX < len) {
+ return AllocResult(DecodeImage_OutOfMemory);
}
- void* p = calloc((size_t)len.max_incl, 1);
- if (!p) {
- return DecodeImageCallbacks::AllocResult(DecodeImage_OutOfMemory);
- }
- return DecodeImageCallbacks::AllocResult(
- MemOwner(p, &free),
- wuffs_base__make_slice_u8((uint8_t*)p, (size_t)len.max_incl));
+ void* ptr =
+ allow_uninitialized_memory ? malloc((size_t)len) : calloc((size_t)len, 1);
+ return ptr ? AllocResult(
+ MemOwner(ptr, &free),
+ wuffs_base__make_slice_u8((uint8_t*)ptr, (size_t)len))
+ : AllocResult(DecodeImage_OutOfMemory);
}
void //
@@ -186,6 +188,7 @@
wuffs_base__io_buffer& io_buf,
uint32_t override_pixel_format_repr,
wuffs_base__pixel_blend pixel_blend,
+ wuffs_base__color_u32_argb_premul background_color,
uint32_t max_incl_dimension) {
// Check args.
switch (override_pixel_format_repr) {
@@ -234,7 +237,7 @@
wuffs_base__more_information minfo = wuffs_base__empty_more_information();
wuffs_base__status tmm_status =
image_decoder->tell_me_more(&empty, &minfo, &io_buf);
- if (!tmm_status.is_ok()) {
+ if (tmm_status.repr != nullptr) {
return DecodeImageResult(tmm_status.message());
}
if (minfo.flavor != WUFFS_BASE__MORE_INFORMATION__FLAVOR__IO_REDIRECT) {
@@ -265,7 +268,7 @@
while (true) {
wuffs_base__status id_dic_status =
image_decoder->decode_image_config(&image_config, &io_buf);
- if (id_dic_status.repr == NULL) {
+ if (id_dic_status.repr == nullptr) {
break;
} else if (id_dic_status.repr == wuffs_base__note__i_o_redirect) {
if (redirected) {
@@ -305,8 +308,10 @@
return DecodeImageResult(DecodeImage_UnsupportedPixelFormat);
}
}
+ bool valid_background_color =
+ wuffs_base__color_u32_argb_premul__is_valid(background_color);
DecodeImageCallbacks::AllocResult oic_result =
- callbacks.OnImageConfig(image_config);
+ callbacks.OnImageConfig(image_config, valid_background_color);
if (!oic_result.error_message.empty()) {
return DecodeImageResult(std::move(oic_result.error_message));
} else if (oic_result.mem_slice.len < pixbuf_len_min_incl) {
@@ -318,11 +323,19 @@
if (!pb_sfs_status.is_ok()) {
return DecodeImageResult(pb_sfs_status.message());
}
+ if (valid_background_color) {
+ wuffs_base__status pb_scufr_status = pixel_buffer.set_color_u32_fill_rect(
+ pixel_buffer.pixcfg.bounds(), background_color);
+ if (pb_scufr_status.repr != nullptr) {
+ return DecodeImageResult(pb_scufr_status.message());
+ }
+ }
- // Allocate the work buffer.
+ // Allocate the work buffer. Wuffs' decoders conventionally assume that this
+ // can be uninitialized memory.
wuffs_base__range_ii_u64 workbuf_len = image_decoder->workbuf_len();
DecodeImageCallbacks::AllocResult alloc_workbuf_result =
- callbacks.AllocWorkbuf(workbuf_len);
+ callbacks.AllocWorkbuf(workbuf_len, true);
if (!alloc_workbuf_result.error_message.empty()) {
return DecodeImageResult(std::move(alloc_workbuf_result.error_message));
} else if (alloc_workbuf_result.mem_slice.len < workbuf_len.min_incl) {
@@ -334,7 +347,7 @@
while (true) {
wuffs_base__status id_dfc_status =
image_decoder->decode_frame_config(&frame_config, &io_buf);
- if (id_dfc_status.repr == NULL) {
+ if (id_dfc_status.repr == nullptr) {
break;
} else if (id_dfc_status.repr != wuffs_base__suspension__short_read) {
return DecodeImageResult(id_dfc_status.message());
@@ -360,8 +373,8 @@
while (true) {
wuffs_base__status id_df_status =
image_decoder->decode_frame(&pixel_buffer, &io_buf, pixel_blend,
- alloc_workbuf_result.mem_slice, NULL);
- if (id_df_status.repr == NULL) {
+ alloc_workbuf_result.mem_slice, nullptr);
+ if (id_df_status.repr == nullptr) {
break;
} else if (id_df_status.repr != wuffs_base__suspension__short_read) {
message = id_df_status.message();
@@ -389,6 +402,7 @@
sync_io::Input& input,
uint32_t override_pixel_format_repr,
wuffs_base__pixel_blend pixel_blend,
+ wuffs_base__color_u32_argb_premul background_color,
uint32_t max_incl_dimension) {
wuffs_base__io_buffer* io_buf = input.BringsItsOwnIOBuffer();
wuffs_base__io_buffer fallback_io_buf = wuffs_base__empty_io_buffer();
@@ -401,9 +415,9 @@
}
wuffs_base__image_decoder::unique_ptr image_decoder(nullptr, &free);
- DecodeImageResult result =
- DecodeImage0(image_decoder, callbacks, input, *io_buf,
- override_pixel_format_repr, pixel_blend, max_incl_dimension);
+ DecodeImageResult result = DecodeImage0(
+ image_decoder, callbacks, input, *io_buf, override_pixel_format_repr,
+ pixel_blend, background_color, max_incl_dimension);
callbacks.Done(result, input, *io_buf, std::move(image_decoder));
return result;
}
diff --git a/internal/cgen/auxiliary/image.hh b/internal/cgen/auxiliary/image.hh
index 35f5b63..458cf49 100644
--- a/internal/cgen/auxiliary/image.hh
+++ b/internal/cgen/auxiliary/image.hh
@@ -82,18 +82,26 @@
// OnImageConfig allocates the pixel buffer.
//
- // The default OnImageConfig implementation allocates zeroed memory.
+ // allow_uninitialized_memory will be true if a valid background_color was
+ // passed to DecodeImage, since the pixel buffer's contents will be
+ // overwritten with that color after OnImageConfig returns.
+ //
+ // The default OnImageConfig implementation allocates either uninitialized or
+ // zeroed memory. Zeroed memory typically corresponds to filling with opaque
+ // black or transparent black, depending on the pixel format.
virtual AllocResult //
- OnImageConfig(const wuffs_base__image_config& image_config);
+ OnImageConfig(const wuffs_base__image_config& image_config,
+ bool allow_uninitialized_memory);
// AllocWorkbuf allocates the work buffer. The allocated buffer's length
- // should be at least len.min_incl, but larger allocations (up to
- // len.max_incl) may have better performance (by using more memory).
+ // should be at least len_range.min_incl, but larger allocations (up to
+ // len_range.max_incl) may have better performance (by using more memory).
//
- // The default AllocWorkbuf implementation allocates len.max_incl bytes of
- // zeroed memory.
+ // The default AllocWorkbuf implementation allocates len_range.max_incl bytes
+ // of either uninitialized or zeroed memory.
virtual AllocResult //
- AllocWorkbuf(wuffs_base__range_ii_u64 len);
+ AllocWorkbuf(wuffs_base__range_ii_u64 len_range,
+ bool allow_uninitialized_memory);
// Done is always the last Callback method called by DecodeImage, whether or
// not parsing the input encountered an error. Even when successful, trailing
@@ -167,6 +175,15 @@
// - WUFFS_BASE__PIXEL_BLEND__SRC
// - WUFFS_BASE__PIXEL_BLEND__SRC_OVER
//
+// The background_color is used to fill the pixel buffer after
+// callbacks.OnImageConfig returns, if it is valid in the
+// wuffs_base__color_u32_argb_premul__is_valid sense. The default value,
+// 0x0000_0001, is not valid since its Blue channel value (0x01) is greater
+// than its Alpha channel value (0x00). A valid background_color will typically
+// be overwritten when pixel_blend is WUFFS_BASE__PIXEL_BLEND__SRC, but might
+// still be visible on partial (not total) success or when pixel_blend is
+// WUFFS_BASE__PIXEL_BLEND__SRC_OVER and the decoded image is not fully opaque.
+//
// Decoding fails (with DecodeImage_MaxInclDimensionExceeded) if the image's
// width or height is greater than max_incl_dimension.
DecodeImageResult //
@@ -174,6 +191,7 @@
sync_io::Input& input,
uint32_t override_pixel_format_repr,
wuffs_base__pixel_blend pixel_blend = WUFFS_BASE__PIXEL_BLEND__SRC,
+ wuffs_base__color_u32_argb_premul background_color = 1, // Invalid.
uint32_t max_incl_dimension = 1048575); // 0x000F_FFFF
} // namespace wuffs_aux
diff --git a/internal/cgen/base/image-public.h b/internal/cgen/base/image-public.h
index 92ab7be..70f3492 100644
--- a/internal/cgen/base/image-public.h
+++ b/internal/cgen/base/image-public.h
@@ -21,6 +21,20 @@
// 0xAARRGGBB (Alpha most significant, Blue least), regardless of endianness.
typedef uint32_t wuffs_base__color_u32_argb_premul;
+// wuffs_base__color_u32_argb_premul__is_valid returns whether c's Red, Green
+// and Blue channels are all less than or equal to its Alpha channel. c uses
+// premultiplied alpha, so 50% opaque 100% saturated red is 0x7F7F_0000 and a
+// value like 0x7F80_0000 is invalid.
+static inline bool //
+wuffs_base__color_u32_argb_premul__is_valid(
+ wuffs_base__color_u32_argb_premul c) {
+ uint32_t a = 0xFF & (c >> 24);
+ uint32_t r = 0xFF & (c >> 16);
+ uint32_t g = 0xFF & (c >> 8);
+ uint32_t b = 0xFF & (c >> 0);
+ return (a >= r) && (a >= g) && (a >= b);
+}
+
static inline uint16_t //
wuffs_base__color_u32_argb_premul__as__color_u16_rgb_565(
wuffs_base__color_u32_argb_premul c) {
@@ -1103,6 +1117,9 @@
uint32_t x,
uint32_t y,
wuffs_base__color_u32_argb_premul color);
+ inline wuffs_base__status set_color_u32_fill_rect(
+ wuffs_base__rect_ie_u32 rect,
+ wuffs_base__color_u32_argb_premul color);
#endif // __cplusplus
} wuffs_base__pixel_buffer;
@@ -1283,6 +1300,12 @@
uint32_t y,
wuffs_base__color_u32_argb_premul color);
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
+wuffs_base__pixel_buffer__set_color_u32_fill_rect(
+ wuffs_base__pixel_buffer* pb,
+ wuffs_base__rect_ie_u32 rect,
+ wuffs_base__color_u32_argb_premul color);
+
#ifdef __cplusplus
inline wuffs_base__status //
@@ -1326,6 +1349,12 @@
return wuffs_base__pixel_buffer__color_u32_at(this, x, y);
}
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
+wuffs_base__pixel_buffer__set_color_u32_fill_rect(
+ wuffs_base__pixel_buffer* pb,
+ wuffs_base__rect_ie_u32 rect,
+ wuffs_base__color_u32_argb_premul color);
+
inline wuffs_base__status //
wuffs_base__pixel_buffer::set_color_u32_at(
uint32_t x,
@@ -1334,6 +1363,13 @@
return wuffs_base__pixel_buffer__set_color_u32_at(this, x, y, color);
}
+inline wuffs_base__status //
+wuffs_base__pixel_buffer::set_color_u32_fill_rect(
+ wuffs_base__rect_ie_u32 rect,
+ wuffs_base__color_u32_argb_premul color) {
+ return wuffs_base__pixel_buffer__set_color_u32_fill_rect(this, rect, color);
+}
+
#endif // __cplusplus
// --------
diff --git a/internal/cgen/base/pixconv-submodule.c b/internal/cgen/base/pixconv-submodule.c
index 1e8fb69..72cf03e 100644
--- a/internal/cgen/base/pixconv-submodule.c
+++ b/internal/cgen/base/pixconv-submodule.c
@@ -217,6 +217,87 @@
// --------
+static inline void //
+wuffs_base__pixel_buffer__set_color_u32_fill_rect__xxxx(
+ wuffs_base__pixel_buffer* pb,
+ wuffs_base__rect_ie_u32 rect,
+ uint32_t color) {
+ size_t stride = pb->private_impl.planes[0].stride;
+ uint32_t width = wuffs_base__rect_ie_u32__width(&rect);
+ if (((stride & 3) == 0) && ((stride >> 2) == width) &&
+ (rect.min_incl_x == 0)) {
+ uint8_t* ptr =
+ pb->private_impl.planes[0].ptr + (stride * ((size_t)rect.min_incl_y));
+ uint32_t height = wuffs_base__rect_ie_u32__height(&rect);
+ size_t n;
+ for (n = ((size_t)width) * ((size_t)height); n > 0; n--) {
+ wuffs_base__poke_u32le__no_bounds_check(ptr, color);
+ ptr += 4;
+ }
+ return;
+ }
+
+ uint32_t y;
+ for (y = rect.min_incl_y; y < rect.max_excl_y; y++) {
+ uint8_t* ptr = pb->private_impl.planes[0].ptr + (stride * ((size_t)y)) +
+ (4 * ((size_t)rect.min_incl_x));
+ uint32_t n;
+ for (n = width; n > 0; n--) {
+ wuffs_base__poke_u32le__no_bounds_check(ptr, color);
+ ptr += 4;
+ }
+ }
+}
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
+wuffs_base__pixel_buffer__set_color_u32_fill_rect(
+ wuffs_base__pixel_buffer* pb,
+ wuffs_base__rect_ie_u32 rect,
+ wuffs_base__color_u32_argb_premul color) {
+ if (!pb) {
+ return wuffs_base__make_status(wuffs_base__error__bad_receiver);
+ } else if (wuffs_base__rect_ie_u32__is_empty(&rect)) {
+ return wuffs_base__make_status(NULL);
+ }
+ wuffs_base__rect_ie_u32 bounds =
+ wuffs_base__pixel_config__bounds(&pb->pixcfg);
+ if (!wuffs_base__rect_ie_u32__contains_rect(&bounds, rect)) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+
+ if (wuffs_base__pixel_format__is_planar(&pb->pixcfg.private_impl.pixfmt)) {
+ // TODO: support planar formats.
+ return wuffs_base__make_status(wuffs_base__error__unsupported_option);
+ }
+
+ switch (pb->pixcfg.private_impl.pixfmt.repr) {
+ case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
+ wuffs_base__pixel_buffer__set_color_u32_fill_rect__xxxx(
+ pb, rect,
+ wuffs_base__color_u32_argb_premul__as__color_u32_argb_nonpremul(
+ color));
+ return wuffs_base__make_status(NULL);
+
+ case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:
+ case WUFFS_BASE__PIXEL_FORMAT__BGRX:
+ wuffs_base__pixel_buffer__set_color_u32_fill_rect__xxxx(pb, rect, color);
+ return wuffs_base__make_status(NULL);
+
+ // TODO: fast paths for other formats.
+ }
+
+ uint32_t y;
+ for (y = rect.min_incl_y; y < rect.max_excl_y; y++) {
+ uint32_t x;
+ for (x = rect.min_incl_x; x < rect.max_excl_x; x++) {
+ wuffs_base__pixel_buffer__set_color_u32_at(pb, x, y, color);
+ }
+ }
+ return wuffs_base__make_status(NULL);
+}
+
+// --------
+
WUFFS_BASE__MAYBE_STATIC uint8_t //
wuffs_base__pixel_palette__closest_element(
wuffs_base__slice_u8 palette_slice,
diff --git a/internal/cgen/data/data.go b/internal/cgen/data/data.go
index 1bfb326..3d4114f 100644
--- a/internal/cgen/data/data.go
+++ b/internal/cgen/data/data.go
@@ -136,13 +136,13 @@
""
const BaseImagePublicH = "" +
- "// ---------------- Images\n\n// wuffs_base__color_u32_argb_premul is an 8 bit per channel premultiplied\n// Alpha, Red, Green, Blue color, as a uint32_t value. Its value is always\n// 0xAARRGGBB (Alpha most significant, Blue least), regardless of endianness.\ntypedef uint32_t wuffs_base__color_u32_argb_premul;\n\nstatic inline uint16_t //\nwuffs_base__color_u32_argb_premul__as__color_u16_rgb_565(\n wuffs_base__color_u32_argb_premul c) {\n uint32_t r5 = 0xF800 & (c >> 8);\n uint32_t g6 = 0x07E0 & (c >> 5);\n uint32_t b5 = 0x001F & (c >> 3);\n return (uint16_t)(r5 | g6 | b5);\n}\n\nstatic inline wuffs_base__color_u32_argb_premul //\nwuffs_base__color_u16_rgb_565__as__color_u32_argb_premul(uint16_t rgb_565) {\n uint32_t b5 = 0x1F & (rgb_565 >> 0);\n uint32_t b = (b5 << 3) | (b5 >> 2);\n uint32_t g6 = 0x3F & (rgb_565 >> 5);\n uint32_t g = (g6 << 2) | (g6 >> 4);\n uint32_t r5 = 0x1F & (rgb_565 >> 11);\n uint32_t r = (r5 << 3) | (r5 >> 2);\n return 0xFF000000 | (r << 16) | (g << 8) | (b << 0);\n}\n\nstatic inline uint8_t //" +
- "\nwuffs_base__color_u32_argb_premul__as__color_u8_gray(\n wuffs_base__color_u32_argb_premul c) {\n // Work in 16-bit color.\n uint32_t cr = 0x101 * (0xFF & (c >> 16));\n uint32_t cg = 0x101 * (0xFF & (c >> 8));\n uint32_t cb = 0x101 * (0xFF & (c >> 0));\n\n // These coefficients (the fractions 0.299, 0.587 and 0.114) are the same\n // as those given by the JFIF specification.\n //\n // Note that 19595 + 38470 + 7471 equals 65536, also known as (1 << 16). We\n // shift by 24, not just by 16, because the return value is 8-bit color, not\n // 16-bit color.\n uint32_t weighted_average = (19595 * cr) + (38470 * cg) + (7471 * cb) + 32768;\n return (uint8_t)(weighted_average >> 24);\n}\n\nstatic inline uint16_t //\nwuffs_base__color_u32_argb_premul__as__color_u16_gray(\n wuffs_base__color_u32_argb_premul c) {\n // Work in 16-bit color.\n uint32_t cr = 0x101 * (0xFF & (c >> 16));\n uint32_t cg = 0x101 * (0xFF & (c >> 8));\n uint32_t cb = 0x101 * (0xFF & (c >> 0));\n\n // These coefficients (the fractions 0.299, 0.587 a" +
- "nd 0.114) are the same\n // as those given by the JFIF specification.\n //\n // Note that 19595 + 38470 + 7471 equals 65536, also known as (1 << 16).\n uint32_t weighted_average = (19595 * cr) + (38470 * cg) + (7471 * cb) + 32768;\n return (uint16_t)(weighted_average >> 16);\n}\n\n// wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul converts\n// from non-premultiplied alpha to premultiplied alpha.\nstatic inline wuffs_base__color_u32_argb_premul //\nwuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul(\n uint32_t argb_nonpremul) {\n // Multiplying by 0x101 (twice, once for alpha and once for color) converts\n // from 8-bit to 16-bit color. Shifting right by 8 undoes that.\n //\n // Working in the higher bit depth can produce slightly different (and\n // arguably slightly more accurate) results. For example, given 8-bit blue\n // and alpha of 0x80 and 0x81:\n //\n // - ((0x80 * 0x81 ) / 0xFF ) = 0x40 = 0x40\n // - ((0x8080 * 0x8181) / 0xFFFF) >> 8 = 0x4101 >> 8 = 0x41\n " +
- "uint32_t a = 0xFF & (argb_nonpremul >> 24);\n uint32_t a16 = a * (0x101 * 0x101);\n\n uint32_t r = 0xFF & (argb_nonpremul >> 16);\n r = ((r * a16) / 0xFFFF) >> 8;\n uint32_t g = 0xFF & (argb_nonpremul >> 8);\n g = ((g * a16) / 0xFFFF) >> 8;\n uint32_t b = 0xFF & (argb_nonpremul >> 0);\n b = ((b * a16) / 0xFFFF) >> 8;\n\n return (a << 24) | (r << 16) | (g << 8) | (b << 0);\n}\n\n// wuffs_base__color_u32_argb_premul__as__color_u32_argb_nonpremul converts\n// from premultiplied alpha to non-premultiplied alpha.\nstatic inline uint32_t //\nwuffs_base__color_u32_argb_premul__as__color_u32_argb_nonpremul(\n wuffs_base__color_u32_argb_premul c) {\n uint32_t a = 0xFF & (c >> 24);\n if (a == 0xFF) {\n return c;\n } else if (a == 0) {\n return 0;\n }\n uint32_t a16 = a * 0x101;\n\n uint32_t r = 0xFF & (c >> 16);\n r = ((r * (0x101 * 0xFFFF)) / a16) >> 8;\n uint32_t g = 0xFF & (c >> 8);\n g = ((g * (0x101 * 0xFFFF)) / a16) >> 8;\n uint32_t b = 0xFF & (c >> 0);\n b = ((b * (0x101 * 0xFFFF)) / a16) >> 8;\n\n return (a << 24)" +
- " | (r << 16) | (g << 8) | (b << 0);\n}\n\n// wuffs_base__color_u64_argb_nonpremul__as__color_u32_argb_premul converts\n// from 4x16LE non-premultiplied alpha to 4x8 premultiplied alpha.\nstatic inline wuffs_base__color_u32_argb_premul //\nwuffs_base__color_u64_argb_nonpremul__as__color_u32_argb_premul(\n uint64_t argb_nonpremul) {\n uint32_t a16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 48)));\n\n uint32_t r16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 32)));\n r16 = (r16 * a16) / 0xFFFF;\n uint32_t g16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 16)));\n g16 = (g16 * a16) / 0xFFFF;\n uint32_t b16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 0)));\n b16 = (b16 * a16) / 0xFFFF;\n\n return ((a16 >> 8) << 24) | ((r16 >> 8) << 16) | ((g16 >> 8) << 8) |\n ((b16 >> 8) << 0);\n}\n\n// wuffs_base__color_u32_argb_premul__as__color_u64_argb_nonpremul converts\n// from 4x8 premultiplied alpha to 4x16LE non-premultiplied alpha.\nstatic inline uint64_t //\nwuffs_base__color_u32_argb_premul__as__color_u64_argb_nonpremul(\n wuffs_" +
- "base__color_u32_argb_premul c) {\n uint32_t a = 0xFF & (c >> 24);\n if (a == 0xFF) {\n uint64_t r16 = 0x101 * (0xFF & (c >> 16));\n uint64_t g16 = 0x101 * (0xFF & (c >> 8));\n uint64_t b16 = 0x101 * (0xFF & (c >> 0));\n return 0xFFFF000000000000u | (r16 << 32) | (g16 << 16) | (b16 << 0);\n } else if (a == 0) {\n return 0;\n }\n uint64_t a16 = a * 0x101;\n\n uint64_t r = 0xFF & (c >> 16);\n uint64_t r16 = (r * (0x101 * 0xFFFF)) / a16;\n uint64_t g = 0xFF & (c >> 8);\n uint64_t g16 = (g * (0x101 * 0xFFFF)) / a16;\n uint64_t b = 0xFF & (c >> 0);\n uint64_t b16 = (b * (0x101 * 0xFFFF)) / a16;\n\n return (a16 << 48) | (r16 << 32) | (g16 << 16) | (b16 << 0);\n}\n\nstatic inline uint64_t //\nwuffs_base__color_u32__as__color_u64(uint32_t c) {\n uint64_t a16 = 0x101 * (0xFF & (c >> 24));\n uint64_t r16 = 0x101 * (0xFF & (c >> 16));\n uint64_t g16 = 0x101 * (0xFF & (c >> 8));\n uint64_t b16 = 0x101 * (0xFF & (c >> 0));\n return (a16 << 48) | (r16 << 32) | (g16 << 16) | (b16 << 0);\n}\n\nstatic inline uint32_t //\nwuf" +
- "fs_base__color_u64__as__color_u32(uint64_t c) {\n uint32_t a = ((uint32_t)(0xFF & (c >> 56)));\n uint32_t r = ((uint32_t)(0xFF & (c >> 40)));\n uint32_t g = ((uint32_t)(0xFF & (c >> 24)));\n uint32_t b = ((uint32_t)(0xFF & (c >> 8)));\n return (a << 24) | (r << 16) | (g << 8) | (b << 0);\n}\n\n" +
+ "// ---------------- Images\n\n// wuffs_base__color_u32_argb_premul is an 8 bit per channel premultiplied\n// Alpha, Red, Green, Blue color, as a uint32_t value. Its value is always\n// 0xAARRGGBB (Alpha most significant, Blue least), regardless of endianness.\ntypedef uint32_t wuffs_base__color_u32_argb_premul;\n\n// wuffs_base__color_u32_argb_premul__is_valid returns whether c's Red, Green\n// and Blue channels are all less than or equal to its Alpha channel. c uses\n// premultiplied alpha, so 50% opaque 100% saturated red is 0x7F7F_0000 and a\n// value like 0x7F80_0000 is invalid.\nstatic inline bool //\nwuffs_base__color_u32_argb_premul__is_valid(\n wuffs_base__color_u32_argb_premul c) {\n uint32_t a = 0xFF & (c >> 24);\n uint32_t r = 0xFF & (c >> 16);\n uint32_t g = 0xFF & (c >> 8);\n uint32_t b = 0xFF & (c >> 0);\n return (a >= r) && (a >= g) && (a >= b);\n}\n\nstatic inline uint16_t //\nwuffs_base__color_u32_argb_premul__as__color_u16_rgb_565(\n wuffs_base__color_u32_argb_premul c) {\n uint32_t r5 = 0xF800 & (c >" +
+ "> 8);\n uint32_t g6 = 0x07E0 & (c >> 5);\n uint32_t b5 = 0x001F & (c >> 3);\n return (uint16_t)(r5 | g6 | b5);\n}\n\nstatic inline wuffs_base__color_u32_argb_premul //\nwuffs_base__color_u16_rgb_565__as__color_u32_argb_premul(uint16_t rgb_565) {\n uint32_t b5 = 0x1F & (rgb_565 >> 0);\n uint32_t b = (b5 << 3) | (b5 >> 2);\n uint32_t g6 = 0x3F & (rgb_565 >> 5);\n uint32_t g = (g6 << 2) | (g6 >> 4);\n uint32_t r5 = 0x1F & (rgb_565 >> 11);\n uint32_t r = (r5 << 3) | (r5 >> 2);\n return 0xFF000000 | (r << 16) | (g << 8) | (b << 0);\n}\n\nstatic inline uint8_t //\nwuffs_base__color_u32_argb_premul__as__color_u8_gray(\n wuffs_base__color_u32_argb_premul c) {\n // Work in 16-bit color.\n uint32_t cr = 0x101 * (0xFF & (c >> 16));\n uint32_t cg = 0x101 * (0xFF & (c >> 8));\n uint32_t cb = 0x101 * (0xFF & (c >> 0));\n\n // These coefficients (the fractions 0.299, 0.587 and 0.114) are the same\n // as those given by the JFIF specification.\n //\n // Note that 19595 + 38470 + 7471 equals 65536, also known as (1 << 16). We\n //" +
+ " shift by 24, not just by 16, because the return value is 8-bit color, not\n // 16-bit color.\n uint32_t weighted_average = (19595 * cr) + (38470 * cg) + (7471 * cb) + 32768;\n return (uint8_t)(weighted_average >> 24);\n}\n\nstatic inline uint16_t //\nwuffs_base__color_u32_argb_premul__as__color_u16_gray(\n wuffs_base__color_u32_argb_premul c) {\n // Work in 16-bit color.\n uint32_t cr = 0x101 * (0xFF & (c >> 16));\n uint32_t cg = 0x101 * (0xFF & (c >> 8));\n uint32_t cb = 0x101 * (0xFF & (c >> 0));\n\n // These coefficients (the fractions 0.299, 0.587 and 0.114) are the same\n // as those given by the JFIF specification.\n //\n // Note that 19595 + 38470 + 7471 equals 65536, also known as (1 << 16).\n uint32_t weighted_average = (19595 * cr) + (38470 * cg) + (7471 * cb) + 32768;\n return (uint16_t)(weighted_average >> 16);\n}\n\n// wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul converts\n// from non-premultiplied alpha to premultiplied alpha.\nstatic inline wuffs_base__color_u32_argb_premul //\nwuf" +
+ "fs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul(\n uint32_t argb_nonpremul) {\n // Multiplying by 0x101 (twice, once for alpha and once for color) converts\n // from 8-bit to 16-bit color. Shifting right by 8 undoes that.\n //\n // Working in the higher bit depth can produce slightly different (and\n // arguably slightly more accurate) results. For example, given 8-bit blue\n // and alpha of 0x80 and 0x81:\n //\n // - ((0x80 * 0x81 ) / 0xFF ) = 0x40 = 0x40\n // - ((0x8080 * 0x8181) / 0xFFFF) >> 8 = 0x4101 >> 8 = 0x41\n uint32_t a = 0xFF & (argb_nonpremul >> 24);\n uint32_t a16 = a * (0x101 * 0x101);\n\n uint32_t r = 0xFF & (argb_nonpremul >> 16);\n r = ((r * a16) / 0xFFFF) >> 8;\n uint32_t g = 0xFF & (argb_nonpremul >> 8);\n g = ((g * a16) / 0xFFFF) >> 8;\n uint32_t b = 0xFF & (argb_nonpremul >> 0);\n b = ((b * a16) / 0xFFFF) >> 8;\n\n return (a << 24) | (r << 16) | (g << 8) | (b << 0);\n}\n\n// wuffs_base__color_u32_argb_premul__as__color_u32_argb_nonpremul converts\n// from premul" +
+ "tiplied alpha to non-premultiplied alpha.\nstatic inline uint32_t //\nwuffs_base__color_u32_argb_premul__as__color_u32_argb_nonpremul(\n wuffs_base__color_u32_argb_premul c) {\n uint32_t a = 0xFF & (c >> 24);\n if (a == 0xFF) {\n return c;\n } else if (a == 0) {\n return 0;\n }\n uint32_t a16 = a * 0x101;\n\n uint32_t r = 0xFF & (c >> 16);\n r = ((r * (0x101 * 0xFFFF)) / a16) >> 8;\n uint32_t g = 0xFF & (c >> 8);\n g = ((g * (0x101 * 0xFFFF)) / a16) >> 8;\n uint32_t b = 0xFF & (c >> 0);\n b = ((b * (0x101 * 0xFFFF)) / a16) >> 8;\n\n return (a << 24) | (r << 16) | (g << 8) | (b << 0);\n}\n\n// wuffs_base__color_u64_argb_nonpremul__as__color_u32_argb_premul converts\n// from 4x16LE non-premultiplied alpha to 4x8 premultiplied alpha.\nstatic inline wuffs_base__color_u32_argb_premul //\nwuffs_base__color_u64_argb_nonpremul__as__color_u32_argb_premul(\n uint64_t argb_nonpremul) {\n uint32_t a16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 48)));\n\n uint32_t r16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 32)));\n r16 =" +
+ " (r16 * a16) / 0xFFFF;\n uint32_t g16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 16)));\n g16 = (g16 * a16) / 0xFFFF;\n uint32_t b16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 0)));\n b16 = (b16 * a16) / 0xFFFF;\n\n return ((a16 >> 8) << 24) | ((r16 >> 8) << 16) | ((g16 >> 8) << 8) |\n ((b16 >> 8) << 0);\n}\n\n// wuffs_base__color_u32_argb_premul__as__color_u64_argb_nonpremul converts\n// from 4x8 premultiplied alpha to 4x16LE non-premultiplied alpha.\nstatic inline uint64_t //\nwuffs_base__color_u32_argb_premul__as__color_u64_argb_nonpremul(\n wuffs_base__color_u32_argb_premul c) {\n uint32_t a = 0xFF & (c >> 24);\n if (a == 0xFF) {\n uint64_t r16 = 0x101 * (0xFF & (c >> 16));\n uint64_t g16 = 0x101 * (0xFF & (c >> 8));\n uint64_t b16 = 0x101 * (0xFF & (c >> 0));\n return 0xFFFF000000000000u | (r16 << 32) | (g16 << 16) | (b16 << 0);\n } else if (a == 0) {\n return 0;\n }\n uint64_t a16 = a * 0x101;\n\n uint64_t r = 0xFF & (c >> 16);\n uint64_t r16 = (r * (0x101 * 0xFFFF)) / a16;\n uint64_t g = 0xFF" +
+ " & (c >> 8);\n uint64_t g16 = (g * (0x101 * 0xFFFF)) / a16;\n uint64_t b = 0xFF & (c >> 0);\n uint64_t b16 = (b * (0x101 * 0xFFFF)) / a16;\n\n return (a16 << 48) | (r16 << 32) | (g16 << 16) | (b16 << 0);\n}\n\nstatic inline uint64_t //\nwuffs_base__color_u32__as__color_u64(uint32_t c) {\n uint64_t a16 = 0x101 * (0xFF & (c >> 24));\n uint64_t r16 = 0x101 * (0xFF & (c >> 16));\n uint64_t g16 = 0x101 * (0xFF & (c >> 8));\n uint64_t b16 = 0x101 * (0xFF & (c >> 0));\n return (a16 << 48) | (r16 << 32) | (g16 << 16) | (b16 << 0);\n}\n\nstatic inline uint32_t //\nwuffs_base__color_u64__as__color_u32(uint64_t c) {\n uint32_t a = ((uint32_t)(0xFF & (c >> 56)));\n uint32_t r = ((uint32_t)(0xFF & (c >> 40)));\n uint32_t g = ((uint32_t)(0xFF & (c >> 24)));\n uint32_t b = ((uint32_t)(0xFF & (c >> 8)));\n return (a << 24) | (r << 16) | (g << 8) | (b << 0);\n}\n\n" +
"" +
"// --------\n\ntypedef uint8_t wuffs_base__pixel_blend;\n\n// wuffs_base__pixel_blend encodes how to blend source and destination pixels,\n// accounting for transparency. It encompasses the Porter-Duff compositing\n// operators as well as the other blending modes defined by PDF.\n//\n// TODO: implement the other modes.\n#define WUFFS_BASE__PIXEL_BLEND__SRC ((wuffs_base__pixel_blend)0)\n#define WUFFS_BASE__PIXEL_BLEND__SRC_OVER ((wuffs_base__pixel_blend)1)\n\n" +
"" +
@@ -184,15 +184,15 @@
"ase__frame_config::index() const {\n return wuffs_base__frame_config__index(this);\n}\n\ninline uint64_t //\nwuffs_base__frame_config::io_position() const {\n return wuffs_base__frame_config__io_position(this);\n}\n\ninline wuffs_base__animation_disposal //\nwuffs_base__frame_config::disposal() const {\n return wuffs_base__frame_config__disposal(this);\n}\n\ninline bool //\nwuffs_base__frame_config::opaque_within_bounds() const {\n return wuffs_base__frame_config__opaque_within_bounds(this);\n}\n\ninline bool //\nwuffs_base__frame_config::overwrite_instead_of_blend() const {\n return wuffs_base__frame_config__overwrite_instead_of_blend(this);\n}\n\ninline wuffs_base__color_u32_argb_premul //\nwuffs_base__frame_config::background_color() const {\n return wuffs_base__frame_config__background_color(this);\n}\n\n#endif // __cplusplus\n\n" +
"" +
"// --------\n\ntypedef struct wuffs_base__pixel_buffer__struct {\n wuffs_base__pixel_config pixcfg;\n\n // Do not access the private_impl's fields directly. There is no API/ABI\n // compatibility or safety guarantee if you do so.\n struct {\n wuffs_base__table_u8 planes[WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX];\n // TODO: color spaces.\n } private_impl;\n\n#ifdef __cplusplus\n inline wuffs_base__status set_from_slice(\n const wuffs_base__pixel_config* pixcfg,\n wuffs_base__slice_u8 pixbuf_memory);\n inline wuffs_base__status set_from_table(\n const wuffs_base__pixel_config* pixcfg,\n wuffs_base__table_u8 pixbuf_memory);\n inline wuffs_base__slice_u8 palette();\n inline wuffs_base__slice_u8 palette_or_else(wuffs_base__slice_u8 fallback);\n inline wuffs_base__pixel_format pixel_format() const;\n inline wuffs_base__table_u8 plane(uint32_t p);\n inline wuffs_base__color_u32_argb_premul color_u32_at(uint32_t x,\n uint32_t y) const;\n inline wuff" +
- "s_base__status set_color_u32_at(\n uint32_t x,\n uint32_t y,\n wuffs_base__color_u32_argb_premul color);\n#endif // __cplusplus\n\n} wuffs_base__pixel_buffer;\n\nstatic inline wuffs_base__pixel_buffer //\nwuffs_base__null_pixel_buffer() {\n wuffs_base__pixel_buffer ret;\n ret.pixcfg = wuffs_base__null_pixel_config();\n ret.private_impl.planes[0] = wuffs_base__empty_table_u8();\n ret.private_impl.planes[1] = wuffs_base__empty_table_u8();\n ret.private_impl.planes[2] = wuffs_base__empty_table_u8();\n ret.private_impl.planes[3] = wuffs_base__empty_table_u8();\n return ret;\n}\n\nstatic inline wuffs_base__status //\nwuffs_base__pixel_buffer__set_from_slice(wuffs_base__pixel_buffer* pb,\n const wuffs_base__pixel_config* pixcfg,\n wuffs_base__slice_u8 pixbuf_memory) {\n if (!pb) {\n return wuffs_base__make_status(wuffs_base__error__bad_receiver);\n }\n memset(pb, 0, sizeof(*pb));\n if (!pixcfg) {\n return wuffs_base__make_status(" +
- "wuffs_base__error__bad_argument);\n }\n if (wuffs_base__pixel_format__is_planar(&pixcfg->private_impl.pixfmt)) {\n // TODO: support planar pixel formats, concious of pixel subsampling.\n return wuffs_base__make_status(wuffs_base__error__unsupported_option);\n }\n uint32_t bits_per_pixel =\n wuffs_base__pixel_format__bits_per_pixel(&pixcfg->private_impl.pixfmt);\n if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {\n // TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?\n return wuffs_base__make_status(wuffs_base__error__unsupported_option);\n }\n uint64_t bytes_per_pixel = bits_per_pixel / 8;\n\n uint8_t* ptr = pixbuf_memory.ptr;\n uint64_t len = pixbuf_memory.len;\n if (wuffs_base__pixel_format__is_indexed(&pixcfg->private_impl.pixfmt)) {\n // Split a 1024 byte chunk (256 palette entries × 4 bytes per entry) from\n // the start of pixbuf_memory. We split from the start, not the end, so\n // that the both chunks' pointers have the same alignment as the original\n // point" +
- "er, up to an alignment of 1024.\n if (len < 1024) {\n return wuffs_base__make_status(\n wuffs_base__error__bad_argument_length_too_short);\n }\n wuffs_base__table_u8* tab =\n &pb->private_impl\n .planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];\n tab->ptr = ptr;\n tab->width = 1024;\n tab->height = 1;\n tab->stride = 1024;\n ptr += 1024;\n len -= 1024;\n }\n\n uint64_t wh = ((uint64_t)pixcfg->private_impl.width) *\n ((uint64_t)pixcfg->private_impl.height);\n size_t width = (size_t)(pixcfg->private_impl.width);\n if ((wh > (UINT64_MAX / bytes_per_pixel)) ||\n (width > (SIZE_MAX / bytes_per_pixel))) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n wh *= bytes_per_pixel;\n width = ((size_t)(width * bytes_per_pixel));\n if (wh > len) {\n return wuffs_base__make_status(\n wuffs_base__error__bad_argument_length_too_short);\n }\n\n pb->pixcfg = *pixcfg;\n wuffs_base__table_u8* tab = &pb->private_impl.planes[0];\n" +
- " tab->ptr = ptr;\n tab->width = width;\n tab->height = pixcfg->private_impl.height;\n tab->stride = width;\n return wuffs_base__make_status(NULL);\n}\n\nstatic inline wuffs_base__status //\nwuffs_base__pixel_buffer__set_from_table(wuffs_base__pixel_buffer* pb,\n const wuffs_base__pixel_config* pixcfg,\n wuffs_base__table_u8 pixbuf_memory) {\n if (!pb) {\n return wuffs_base__make_status(wuffs_base__error__bad_receiver);\n }\n memset(pb, 0, sizeof(*pb));\n if (!pixcfg ||\n wuffs_base__pixel_format__is_planar(&pixcfg->private_impl.pixfmt)) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n uint32_t bits_per_pixel =\n wuffs_base__pixel_format__bits_per_pixel(&pixcfg->private_impl.pixfmt);\n if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {\n // TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?\n return wuffs_base__make_status(wuffs_base__error__unsupported_option);\n }\n uint64_" +
- "t bytes_per_pixel = bits_per_pixel / 8;\n\n uint64_t width_in_bytes =\n ((uint64_t)pixcfg->private_impl.width) * bytes_per_pixel;\n if ((width_in_bytes > pixbuf_memory.width) ||\n (pixcfg->private_impl.height > pixbuf_memory.height)) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n\n pb->pixcfg = *pixcfg;\n pb->private_impl.planes[0] = pixbuf_memory;\n return wuffs_base__make_status(NULL);\n}\n\n// wuffs_base__pixel_buffer__palette returns the palette color data. If\n// non-empty, it will have length 1024.\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__pixel_buffer__palette(wuffs_base__pixel_buffer* pb) {\n if (pb &&\n wuffs_base__pixel_format__is_indexed(&pb->pixcfg.private_impl.pixfmt)) {\n wuffs_base__table_u8* tab =\n &pb->private_impl\n .planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];\n if ((tab->width == 1024) && (tab->height == 1)) {\n return wuffs_base__make_slice_u8(tab->ptr, 1024);\n }\n }\n return wuffs_base__make_slice_u8(NUL" +
- "L, 0);\n}\n\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__pixel_buffer__palette_or_else(wuffs_base__pixel_buffer* pb,\n wuffs_base__slice_u8 fallback) {\n if (pb &&\n wuffs_base__pixel_format__is_indexed(&pb->pixcfg.private_impl.pixfmt)) {\n wuffs_base__table_u8* tab =\n &pb->private_impl\n .planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];\n if ((tab->width == 1024) && (tab->height == 1)) {\n return wuffs_base__make_slice_u8(tab->ptr, 1024);\n }\n }\n return fallback;\n}\n\nstatic inline wuffs_base__pixel_format //\nwuffs_base__pixel_buffer__pixel_format(const wuffs_base__pixel_buffer* pb) {\n if (pb) {\n return pb->pixcfg.private_impl.pixfmt;\n }\n return wuffs_base__make_pixel_format(WUFFS_BASE__PIXEL_FORMAT__INVALID);\n}\n\nstatic inline wuffs_base__table_u8 //\nwuffs_base__pixel_buffer__plane(wuffs_base__pixel_buffer* pb, uint32_t p) {\n if (pb && (p < WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX)) {\n return pb->private_impl.plane" +
- "s[p];\n }\n\n wuffs_base__table_u8 ret;\n ret.ptr = NULL;\n ret.width = 0;\n ret.height = 0;\n ret.stride = 0;\n return ret;\n}\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__color_u32_argb_premul //\nwuffs_base__pixel_buffer__color_u32_at(const wuffs_base__pixel_buffer* pb,\n uint32_t x,\n uint32_t y);\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__status //\nwuffs_base__pixel_buffer__set_color_u32_at(\n wuffs_base__pixel_buffer* pb,\n uint32_t x,\n uint32_t y,\n wuffs_base__color_u32_argb_premul color);\n\n#ifdef __cplusplus\n\ninline wuffs_base__status //\nwuffs_base__pixel_buffer::set_from_slice(\n const wuffs_base__pixel_config* pixcfg_arg,\n wuffs_base__slice_u8 pixbuf_memory) {\n return wuffs_base__pixel_buffer__set_from_slice(this, pixcfg_arg,\n pixbuf_memory);\n}\n\ninline wuffs_base__status //\nwuffs_base__pixel_buffer::set_from_table(\n const wuffs_base__pixel_config* pixcfg_arg,\n wuffs_b" +
- "ase__table_u8 pixbuf_memory) {\n return wuffs_base__pixel_buffer__set_from_table(this, pixcfg_arg,\n pixbuf_memory);\n}\n\ninline wuffs_base__slice_u8 //\nwuffs_base__pixel_buffer::palette() {\n return wuffs_base__pixel_buffer__palette(this);\n}\n\ninline wuffs_base__slice_u8 //\nwuffs_base__pixel_buffer::palette_or_else(wuffs_base__slice_u8 fallback) {\n return wuffs_base__pixel_buffer__palette_or_else(this, fallback);\n}\n\ninline wuffs_base__pixel_format //\nwuffs_base__pixel_buffer::pixel_format() const {\n return wuffs_base__pixel_buffer__pixel_format(this);\n}\n\ninline wuffs_base__table_u8 //\nwuffs_base__pixel_buffer::plane(uint32_t p) {\n return wuffs_base__pixel_buffer__plane(this, p);\n}\n\ninline wuffs_base__color_u32_argb_premul //\nwuffs_base__pixel_buffer::color_u32_at(uint32_t x, uint32_t y) const {\n return wuffs_base__pixel_buffer__color_u32_at(this, x, y);\n}\n\ninline wuffs_base__status //\nwuffs_base__pixel_buffer::set_color_u32_at(\n uint32_t x,\n uint32" +
- "_t y,\n wuffs_base__color_u32_argb_premul color) {\n return wuffs_base__pixel_buffer__set_color_u32_at(this, x, y, color);\n}\n\n#endif // __cplusplus\n\n" +
+ "s_base__status set_color_u32_at(\n uint32_t x,\n uint32_t y,\n wuffs_base__color_u32_argb_premul color);\n inline wuffs_base__status set_color_u32_fill_rect(\n wuffs_base__rect_ie_u32 rect,\n wuffs_base__color_u32_argb_premul color);\n#endif // __cplusplus\n\n} wuffs_base__pixel_buffer;\n\nstatic inline wuffs_base__pixel_buffer //\nwuffs_base__null_pixel_buffer() {\n wuffs_base__pixel_buffer ret;\n ret.pixcfg = wuffs_base__null_pixel_config();\n ret.private_impl.planes[0] = wuffs_base__empty_table_u8();\n ret.private_impl.planes[1] = wuffs_base__empty_table_u8();\n ret.private_impl.planes[2] = wuffs_base__empty_table_u8();\n ret.private_impl.planes[3] = wuffs_base__empty_table_u8();\n return ret;\n}\n\nstatic inline wuffs_base__status //\nwuffs_base__pixel_buffer__set_from_slice(wuffs_base__pixel_buffer* pb,\n const wuffs_base__pixel_config* pixcfg,\n wuffs_base__slice_u8 pixbuf_memory) {\n if (!pb) {\n return wuffs_b" +
+ "ase__make_status(wuffs_base__error__bad_receiver);\n }\n memset(pb, 0, sizeof(*pb));\n if (!pixcfg) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n if (wuffs_base__pixel_format__is_planar(&pixcfg->private_impl.pixfmt)) {\n // TODO: support planar pixel formats, concious of pixel subsampling.\n return wuffs_base__make_status(wuffs_base__error__unsupported_option);\n }\n uint32_t bits_per_pixel =\n wuffs_base__pixel_format__bits_per_pixel(&pixcfg->private_impl.pixfmt);\n if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {\n // TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?\n return wuffs_base__make_status(wuffs_base__error__unsupported_option);\n }\n uint64_t bytes_per_pixel = bits_per_pixel / 8;\n\n uint8_t* ptr = pixbuf_memory.ptr;\n uint64_t len = pixbuf_memory.len;\n if (wuffs_base__pixel_format__is_indexed(&pixcfg->private_impl.pixfmt)) {\n // Split a 1024 byte chunk (256 palette entries × 4 bytes per entry) from\n // the start of pixbuf_me" +
+ "mory. We split from the start, not the end, so\n // that the both chunks' pointers have the same alignment as the original\n // pointer, up to an alignment of 1024.\n if (len < 1024) {\n return wuffs_base__make_status(\n wuffs_base__error__bad_argument_length_too_short);\n }\n wuffs_base__table_u8* tab =\n &pb->private_impl\n .planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];\n tab->ptr = ptr;\n tab->width = 1024;\n tab->height = 1;\n tab->stride = 1024;\n ptr += 1024;\n len -= 1024;\n }\n\n uint64_t wh = ((uint64_t)pixcfg->private_impl.width) *\n ((uint64_t)pixcfg->private_impl.height);\n size_t width = (size_t)(pixcfg->private_impl.width);\n if ((wh > (UINT64_MAX / bytes_per_pixel)) ||\n (width > (SIZE_MAX / bytes_per_pixel))) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n wh *= bytes_per_pixel;\n width = ((size_t)(width * bytes_per_pixel));\n if (wh > len) {\n return wuffs_base__make_status(\n wu" +
+ "ffs_base__error__bad_argument_length_too_short);\n }\n\n pb->pixcfg = *pixcfg;\n wuffs_base__table_u8* tab = &pb->private_impl.planes[0];\n tab->ptr = ptr;\n tab->width = width;\n tab->height = pixcfg->private_impl.height;\n tab->stride = width;\n return wuffs_base__make_status(NULL);\n}\n\nstatic inline wuffs_base__status //\nwuffs_base__pixel_buffer__set_from_table(wuffs_base__pixel_buffer* pb,\n const wuffs_base__pixel_config* pixcfg,\n wuffs_base__table_u8 pixbuf_memory) {\n if (!pb) {\n return wuffs_base__make_status(wuffs_base__error__bad_receiver);\n }\n memset(pb, 0, sizeof(*pb));\n if (!pixcfg ||\n wuffs_base__pixel_format__is_planar(&pixcfg->private_impl.pixfmt)) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n uint32_t bits_per_pixel =\n wuffs_base__pixel_format__bits_per_pixel(&pixcfg->private_impl.pixfmt);\n if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {\n // TODO: suppor" +
+ "t fraction-of-byte pixels, e.g. 1 bit per pixel?\n return wuffs_base__make_status(wuffs_base__error__unsupported_option);\n }\n uint64_t bytes_per_pixel = bits_per_pixel / 8;\n\n uint64_t width_in_bytes =\n ((uint64_t)pixcfg->private_impl.width) * bytes_per_pixel;\n if ((width_in_bytes > pixbuf_memory.width) ||\n (pixcfg->private_impl.height > pixbuf_memory.height)) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n\n pb->pixcfg = *pixcfg;\n pb->private_impl.planes[0] = pixbuf_memory;\n return wuffs_base__make_status(NULL);\n}\n\n// wuffs_base__pixel_buffer__palette returns the palette color data. If\n// non-empty, it will have length 1024.\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__pixel_buffer__palette(wuffs_base__pixel_buffer* pb) {\n if (pb &&\n wuffs_base__pixel_format__is_indexed(&pb->pixcfg.private_impl.pixfmt)) {\n wuffs_base__table_u8* tab =\n &pb->private_impl\n .planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];\n if ((tab->width =" +
+ "= 1024) && (tab->height == 1)) {\n return wuffs_base__make_slice_u8(tab->ptr, 1024);\n }\n }\n return wuffs_base__make_slice_u8(NULL, 0);\n}\n\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__pixel_buffer__palette_or_else(wuffs_base__pixel_buffer* pb,\n wuffs_base__slice_u8 fallback) {\n if (pb &&\n wuffs_base__pixel_format__is_indexed(&pb->pixcfg.private_impl.pixfmt)) {\n wuffs_base__table_u8* tab =\n &pb->private_impl\n .planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];\n if ((tab->width == 1024) && (tab->height == 1)) {\n return wuffs_base__make_slice_u8(tab->ptr, 1024);\n }\n }\n return fallback;\n}\n\nstatic inline wuffs_base__pixel_format //\nwuffs_base__pixel_buffer__pixel_format(const wuffs_base__pixel_buffer* pb) {\n if (pb) {\n return pb->pixcfg.private_impl.pixfmt;\n }\n return wuffs_base__make_pixel_format(WUFFS_BASE__PIXEL_FORMAT__INVALID);\n}\n\nstatic inline wuffs_base__table_u8 //\nwuffs_base__pixel_buffer__plane(wu" +
+ "ffs_base__pixel_buffer* pb, uint32_t p) {\n if (pb && (p < WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX)) {\n return pb->private_impl.planes[p];\n }\n\n wuffs_base__table_u8 ret;\n ret.ptr = NULL;\n ret.width = 0;\n ret.height = 0;\n ret.stride = 0;\n return ret;\n}\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__color_u32_argb_premul //\nwuffs_base__pixel_buffer__color_u32_at(const wuffs_base__pixel_buffer* pb,\n uint32_t x,\n uint32_t y);\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__status //\nwuffs_base__pixel_buffer__set_color_u32_at(\n wuffs_base__pixel_buffer* pb,\n uint32_t x,\n uint32_t y,\n wuffs_base__color_u32_argb_premul color);\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__status //\nwuffs_base__pixel_buffer__set_color_u32_fill_rect(\n wuffs_base__pixel_buffer* pb,\n wuffs_base__rect_ie_u32 rect,\n wuffs_base__color_u32_argb_premul color);\n\n#ifdef __cplusplus\n\ninline wuffs_base__status //\nwuffs_base__pixel_buffer::set_from_slice(\n con" +
+ "st wuffs_base__pixel_config* pixcfg_arg,\n wuffs_base__slice_u8 pixbuf_memory) {\n return wuffs_base__pixel_buffer__set_from_slice(this, pixcfg_arg,\n pixbuf_memory);\n}\n\ninline wuffs_base__status //\nwuffs_base__pixel_buffer::set_from_table(\n const wuffs_base__pixel_config* pixcfg_arg,\n wuffs_base__table_u8 pixbuf_memory) {\n return wuffs_base__pixel_buffer__set_from_table(this, pixcfg_arg,\n pixbuf_memory);\n}\n\ninline wuffs_base__slice_u8 //\nwuffs_base__pixel_buffer::palette() {\n return wuffs_base__pixel_buffer__palette(this);\n}\n\ninline wuffs_base__slice_u8 //\nwuffs_base__pixel_buffer::palette_or_else(wuffs_base__slice_u8 fallback) {\n return wuffs_base__pixel_buffer__palette_or_else(this, fallback);\n}\n\ninline wuffs_base__pixel_format //\nwuffs_base__pixel_buffer::pixel_format() const {\n return wuffs_base__pixel_buffer__pixel_format(this);\n}\n\ninline wuffs_base__table_u8 //\nwuffs_base__pixel_buffer::pla" +
+ "ne(uint32_t p) {\n return wuffs_base__pixel_buffer__plane(this, p);\n}\n\ninline wuffs_base__color_u32_argb_premul //\nwuffs_base__pixel_buffer::color_u32_at(uint32_t x, uint32_t y) const {\n return wuffs_base__pixel_buffer__color_u32_at(this, x, y);\n}\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__status //\nwuffs_base__pixel_buffer__set_color_u32_fill_rect(\n wuffs_base__pixel_buffer* pb,\n wuffs_base__rect_ie_u32 rect,\n wuffs_base__color_u32_argb_premul color);\n\ninline wuffs_base__status //\nwuffs_base__pixel_buffer::set_color_u32_at(\n uint32_t x,\n uint32_t y,\n wuffs_base__color_u32_argb_premul color) {\n return wuffs_base__pixel_buffer__set_color_u32_at(this, x, y, color);\n}\n\ninline wuffs_base__status //\nwuffs_base__pixel_buffer::set_color_u32_fill_rect(\n wuffs_base__rect_ie_u32 rect,\n wuffs_base__color_u32_argb_premul color) {\n return wuffs_base__pixel_buffer__set_color_u32_fill_rect(this, rect, color);\n}\n\n#endif // __cplusplus\n\n" +
"" +
"// --------\n\ntypedef struct wuffs_base__decode_frame_options__struct {\n // Do not access the private_impl's fields directly. There is no API/ABI\n // compatibility or safety guarantee if you do so.\n struct {\n uint8_t TODO;\n } private_impl;\n\n#ifdef __cplusplus\n#endif // __cplusplus\n\n} wuffs_base__decode_frame_options;\n\n#ifdef __cplusplus\n\n#endif // __cplusplus\n\n" +
"" +
@@ -559,6 +559,10 @@
"alette(pb),\n pb->pixcfg.private_impl.pixfmt, color));\n break;\n\n case WUFFS_BASE__PIXEL_FORMAT__BGR_565:\n wuffs_base__poke_u16le__no_bounds_check(\n row + (2 * ((size_t)x)),\n wuffs_base__color_u32_argb_premul__as__color_u16_rgb_565(color));\n break;\n case WUFFS_BASE__PIXEL_FORMAT__BGR:\n wuffs_base__poke_u24le__no_bounds_check(row + (3 * ((size_t)x)), color);\n break;\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:\n wuffs_base__poke_u32le__no_bounds_check(\n row + (4 * ((size_t)x)),\n wuffs_base__color_u32_argb_premul__as__color_u32_argb_nonpremul(\n color));\n break;\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL_4X16LE:\n wuffs_base__poke_u64le__no_bounds_check(\n row + (8 * ((size_t)x)),\n wuffs_base__color_u32_argb_premul__as__color_u64_argb_nonpremul(\n color));\n break;\n\n case WUFFS_BASE__PIXEL_FORMAT__RGB:\n wuffs_base__poke_u24le__no_bounds_c" +
"heck(\n row + (3 * ((size_t)x)), wuffs_base__swap_u32_argb_abgr(color));\n break;\n case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL:\n wuffs_base__poke_u32le__no_bounds_check(\n row + (4 * ((size_t)x)),\n wuffs_base__color_u32_argb_premul__as__color_u32_argb_nonpremul(\n wuffs_base__swap_u32_argb_abgr(color)));\n break;\n case WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__RGBX:\n wuffs_base__poke_u32le__no_bounds_check(\n row + (4 * ((size_t)x)), wuffs_base__swap_u32_argb_abgr(color));\n break;\n\n default:\n // TODO: support more formats.\n return wuffs_base__make_status(wuffs_base__error__unsupported_option);\n }\n\n return wuffs_base__make_status(NULL);\n}\n\n" +
"" +
+ "// --------\n\nstatic inline void //\nwuffs_base__pixel_buffer__set_color_u32_fill_rect__xxxx(\n wuffs_base__pixel_buffer* pb,\n wuffs_base__rect_ie_u32 rect,\n uint32_t color) {\n size_t stride = pb->private_impl.planes[0].stride;\n uint32_t width = wuffs_base__rect_ie_u32__width(&rect);\n if (((stride & 3) == 0) && ((stride >> 2) == width) &&\n (rect.min_incl_x == 0)) {\n uint8_t* ptr =\n pb->private_impl.planes[0].ptr + (stride * ((size_t)rect.min_incl_y));\n uint32_t height = wuffs_base__rect_ie_u32__height(&rect);\n size_t n;\n for (n = ((size_t)width) * ((size_t)height); n > 0; n--) {\n wuffs_base__poke_u32le__no_bounds_check(ptr, color);\n ptr += 4;\n }\n return;\n }\n\n uint32_t y;\n for (y = rect.min_incl_y; y < rect.max_excl_y; y++) {\n uint8_t* ptr = pb->private_impl.planes[0].ptr + (stride * ((size_t)y)) +\n (4 * ((size_t)rect.min_incl_x));\n uint32_t n;\n for (n = width; n > 0; n--) {\n wuffs_base__poke_u32le__no_bounds_check(ptr, color)" +
+ ";\n ptr += 4;\n }\n }\n}\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__status //\nwuffs_base__pixel_buffer__set_color_u32_fill_rect(\n wuffs_base__pixel_buffer* pb,\n wuffs_base__rect_ie_u32 rect,\n wuffs_base__color_u32_argb_premul color) {\n if (!pb) {\n return wuffs_base__make_status(wuffs_base__error__bad_receiver);\n } else if (wuffs_base__rect_ie_u32__is_empty(&rect)) {\n return wuffs_base__make_status(NULL);\n }\n wuffs_base__rect_ie_u32 bounds =\n wuffs_base__pixel_config__bounds(&pb->pixcfg);\n if (!wuffs_base__rect_ie_u32__contains_rect(&bounds, rect)) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n\n if (wuffs_base__pixel_format__is_planar(&pb->pixcfg.private_impl.pixfmt)) {\n // TODO: support planar formats.\n return wuffs_base__make_status(wuffs_base__error__unsupported_option);\n }\n\n switch (pb->pixcfg.private_impl.pixfmt.repr) {\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:\n wuffs_base__pixel_buffer__set_color_u32_fill_rect__xxxx(\n " +
+ "pb, rect,\n wuffs_base__color_u32_argb_premul__as__color_u32_argb_nonpremul(\n color));\n return wuffs_base__make_status(NULL);\n\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__BGRX:\n wuffs_base__pixel_buffer__set_color_u32_fill_rect__xxxx(pb, rect, color);\n return wuffs_base__make_status(NULL);\n\n // TODO: fast paths for other formats.\n }\n\n uint32_t y;\n for (y = rect.min_incl_y; y < rect.max_excl_y; y++) {\n uint32_t x;\n for (x = rect.min_incl_x; x < rect.max_excl_x; x++) {\n wuffs_base__pixel_buffer__set_color_u32_at(pb, x, y, color);\n }\n }\n return wuffs_base__make_status(NULL);\n}\n\n" +
+ "" +
"// --------\n\nWUFFS_BASE__MAYBE_STATIC uint8_t //\nwuffs_base__pixel_palette__closest_element(\n wuffs_base__slice_u8 palette_slice,\n wuffs_base__pixel_format palette_format,\n wuffs_base__color_u32_argb_premul c) {\n size_t n = palette_slice.len / 4;\n if (n > 256) {\n n = 256;\n }\n size_t best_index = 0;\n uint64_t best_score = 0xFFFFFFFFFFFFFFFF;\n\n // Work in 16-bit color.\n uint32_t ca = 0x101 * (0xFF & (c >> 24));\n uint32_t cr = 0x101 * (0xFF & (c >> 16));\n uint32_t cg = 0x101 * (0xFF & (c >> 8));\n uint32_t cb = 0x101 * (0xFF & (c >> 0));\n\n switch (palette_format.repr) {\n case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY: {\n bool nonpremul = palette_format.repr ==\n WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL;\n\n size_t i;\n for (i = 0; i < n; i++) {\n // Work in 16-bit color.\n uint32_t pb = 0x101 * ((uint32_t)(palette" +
"_slice.ptr[(4 * i) + 0]));\n uint32_t pg = 0x101 * ((uint32_t)(palette_slice.ptr[(4 * i) + 1]));\n uint32_t pr = 0x101 * ((uint32_t)(palette_slice.ptr[(4 * i) + 2]));\n uint32_t pa = 0x101 * ((uint32_t)(palette_slice.ptr[(4 * i) + 3]));\n\n // Convert to premultiplied alpha.\n if (nonpremul && (pa != 0xFFFF)) {\n pb = (pb * pa) / 0xFFFF;\n pg = (pg * pa) / 0xFFFF;\n pr = (pr * pa) / 0xFFFF;\n }\n\n // These deltas are conceptually int32_t (signed) but after squaring,\n // it's equivalent to work in uint32_t (unsigned).\n pb -= cb;\n pg -= cg;\n pr -= cr;\n pa -= ca;\n uint64_t score = ((uint64_t)(pb * pb)) + ((uint64_t)(pg * pg)) +\n ((uint64_t)(pr * pr)) + ((uint64_t)(pa * pa));\n if (best_score > score) {\n best_score = score;\n best_index = i;\n }\n }\n break;\n }\n }\n\n return (uint8_t)best_index;\n}\n\n" +
"" +
@@ -737,31 +741,34 @@
const AuxImageCc = "" +
"// ---------------- Auxiliary - Image\n\n#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__AUX__IMAGE)\n\n#include <utility>\n\nnamespace wuffs_aux {\n\nDecodeImageResult::DecodeImageResult(MemOwner&& pixbuf_mem_owner0,\n wuffs_base__slice_u8 pixbuf_mem_slice0,\n wuffs_base__pixel_buffer pixbuf0,\n std::string&& error_message0)\n : pixbuf_mem_owner(std::move(pixbuf_mem_owner0)),\n pixbuf_mem_slice(pixbuf_mem_slice0),\n pixbuf(pixbuf0),\n error_message(std::move(error_message0)) {}\n\nDecodeImageResult::DecodeImageResult(std::string&& error_message0)\n : pixbuf_mem_owner(nullptr, &free),\n pixbuf_mem_slice(wuffs_base__empty_slice_u8()),\n pixbuf(wuffs_base__null_pixel_buffer()),\n error_message(std::move(error_message0)) {}\n\nDecodeImageCallbacks::AllocResult::AllocResult(MemOwner&& mem_owner0,\n wuffs_base__slice_u8 mem_slice0" +
")\n : mem_owner(std::move(mem_owner0)),\n mem_slice(mem_slice0),\n error_message(\"\") {}\n\nDecodeImageCallbacks::AllocResult::AllocResult(std::string&& error_message0)\n : mem_owner(nullptr, &free),\n mem_slice(wuffs_base__empty_slice_u8()),\n error_message(std::move(error_message0)) {}\n\nwuffs_base__image_decoder::unique_ptr //\nDecodeImageCallbacks::OnImageFormat(uint32_t fourcc,\n wuffs_base__slice_u8 prefix) {\n switch (fourcc) {\n#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__BMP)\n case WUFFS_BASE__FOURCC__BMP:\n return wuffs_bmp__decoder::alloc_as__wuffs_base__image_decoder();\n#endif\n\n#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__GIF)\n case WUFFS_BASE__FOURCC__GIF:\n return wuffs_gif__decoder::alloc_as__wuffs_base__image_decoder();\n#endif\n\n#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__NIE)\n case WUFFS_BASE__FOURCC__NIE:\n return wuffs_nie__decoder::alloc_as__wuffs_ba" +
- "se__image_decoder();\n#endif\n\n#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__PNG)\n case WUFFS_BASE__FOURCC__PNG: {\n auto dec = wuffs_png__decoder::alloc_as__wuffs_base__image_decoder();\n // Favor faster decodes over rejecting invalid checksums.\n dec->set_quirk_enabled(WUFFS_BASE__QUIRK_IGNORE_CHECKSUM, true);\n return dec;\n }\n#endif\n\n#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__WBMP)\n case WUFFS_BASE__FOURCC__WBMP:\n return wuffs_wbmp__decoder::alloc_as__wuffs_base__image_decoder();\n#endif\n }\n\n return wuffs_base__image_decoder::unique_ptr(nullptr, &free);\n}\n\nDecodeImageCallbacks::AllocResult //\nDecodeImageCallbacks::OnImageConfig(\n const wuffs_base__image_config& image_config) {\n uint32_t w = image_config.pixcfg.width();\n uint32_t h = image_config.pixcfg.height();\n if ((w == 0) || (h == 0)) {\n return AllocResult(\"\");\n }\n uint64_t len = image_config.pixcfg.pixbuf_len();\n if ((len == 0) || (SIZE_MAX < len)) {\n return " +
- "AllocResult(DecodeImage_UnsupportedPixelConfiguration);\n }\n void* ptr = calloc((size_t)len, 1);\n if (!ptr) {\n return AllocResult(DecodeImage_OutOfMemory);\n }\n return AllocResult(MemOwner(ptr, &free),\n wuffs_base__make_slice_u8((uint8_t*)ptr, (size_t)len));\n}\n\nDecodeImageCallbacks::AllocResult //\nDecodeImageCallbacks::AllocWorkbuf(wuffs_base__range_ii_u64 len) {\n if (len.max_incl == 0) {\n return DecodeImageCallbacks::AllocResult(\"\");\n } else if (SIZE_MAX < len.max_incl) {\n return DecodeImageCallbacks::AllocResult(DecodeImage_OutOfMemory);\n }\n void* p = calloc((size_t)len.max_incl, 1);\n if (!p) {\n return DecodeImageCallbacks::AllocResult(DecodeImage_OutOfMemory);\n }\n return DecodeImageCallbacks::AllocResult(\n MemOwner(p, &free),\n wuffs_base__make_slice_u8((uint8_t*)p, (size_t)len.max_incl));\n}\n\nvoid //\nDecodeImageCallbacks::Done(\n DecodeImageResult& result,\n sync_io::Input& input,\n IOBuffer& buffer,\n wuffs_base__image_decoder::unique_ptr image_" +
- "decoder) {}\n\nconst char DecodeImage_BufferIsTooShort[] = //\n \"wuffs_aux::DecodeImage: buffer is too short\";\nconst char DecodeImage_MaxInclDimensionExceeded[] = //\n \"wuffs_aux::DecodeImage: max_incl_dimension exceeded\";\nconst char DecodeImage_OutOfMemory[] = //\n \"wuffs_aux::DecodeImage: out of memory\";\nconst char DecodeImage_UnexpectedEndOfFile[] = //\n \"wuffs_aux::DecodeImage: unexpected end of file\";\nconst char DecodeImage_UnsupportedImageFormat[] = //\n \"wuffs_aux::DecodeImage: unsupported image format\";\nconst char DecodeImage_UnsupportedPixelBlend[] = //\n \"wuffs_aux::DecodeImage: unsupported pixel blend\";\nconst char DecodeImage_UnsupportedPixelConfiguration[] = //\n \"wuffs_aux::DecodeImage: unsupported pixel configuration\";\nconst char DecodeImage_UnsupportedPixelFormat[] = //\n \"wuffs_aux::DecodeImage: unsupported pixel format\";\n\n" +
+ "se__image_decoder();\n#endif\n\n#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__PNG)\n case WUFFS_BASE__FOURCC__PNG: {\n auto dec = wuffs_png__decoder::alloc_as__wuffs_base__image_decoder();\n // Favor faster decodes over rejecting invalid checksums.\n dec->set_quirk_enabled(WUFFS_BASE__QUIRK_IGNORE_CHECKSUM, true);\n return dec;\n }\n#endif\n\n#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__WBMP)\n case WUFFS_BASE__FOURCC__WBMP:\n return wuffs_wbmp__decoder::alloc_as__wuffs_base__image_decoder();\n#endif\n }\n\n return wuffs_base__image_decoder::unique_ptr(nullptr, &free);\n}\n\nDecodeImageCallbacks::AllocResult //\nDecodeImageCallbacks::OnImageConfig(\n const wuffs_base__image_config& image_config,\n bool allow_uninitialized_memory) {\n uint32_t w = image_config.pixcfg.width();\n uint32_t h = image_config.pixcfg.height();\n if ((w == 0) || (h == 0)) {\n return AllocResult(\"\");\n }\n uint64_t len = image_config.pixcfg.pixbuf_len();\n if ((len == " +
+ "0) || (SIZE_MAX < len)) {\n return AllocResult(DecodeImage_UnsupportedPixelConfiguration);\n }\n void* ptr =\n allow_uninitialized_memory ? malloc((size_t)len) : calloc((size_t)len, 1);\n return ptr ? AllocResult(\n MemOwner(ptr, &free),\n wuffs_base__make_slice_u8((uint8_t*)ptr, (size_t)len))\n : AllocResult(DecodeImage_OutOfMemory);\n}\n\nDecodeImageCallbacks::AllocResult //\nDecodeImageCallbacks::AllocWorkbuf(wuffs_base__range_ii_u64 len_range,\n bool allow_uninitialized_memory) {\n uint64_t len = len_range.max_incl;\n if (len == 0) {\n return AllocResult(\"\");\n } else if (SIZE_MAX < len) {\n return AllocResult(DecodeImage_OutOfMemory);\n }\n void* ptr =\n allow_uninitialized_memory ? malloc((size_t)len) : calloc((size_t)len, 1);\n return ptr ? AllocResult(\n MemOwner(ptr, &free),\n wuffs_base__make_slice_u8((uint8_t*)ptr, (size_t)len))\n : AllocResult(DecodeImage_OutOfMemor" +
+ "y);\n}\n\nvoid //\nDecodeImageCallbacks::Done(\n DecodeImageResult& result,\n sync_io::Input& input,\n IOBuffer& buffer,\n wuffs_base__image_decoder::unique_ptr image_decoder) {}\n\nconst char DecodeImage_BufferIsTooShort[] = //\n \"wuffs_aux::DecodeImage: buffer is too short\";\nconst char DecodeImage_MaxInclDimensionExceeded[] = //\n \"wuffs_aux::DecodeImage: max_incl_dimension exceeded\";\nconst char DecodeImage_OutOfMemory[] = //\n \"wuffs_aux::DecodeImage: out of memory\";\nconst char DecodeImage_UnexpectedEndOfFile[] = //\n \"wuffs_aux::DecodeImage: unexpected end of file\";\nconst char DecodeImage_UnsupportedImageFormat[] = //\n \"wuffs_aux::DecodeImage: unsupported image format\";\nconst char DecodeImage_UnsupportedPixelBlend[] = //\n \"wuffs_aux::DecodeImage: unsupported pixel blend\";\nconst char DecodeImage_UnsupportedPixelConfiguration[] = //\n \"wuffs_aux::DecodeImage: unsupported pixel configuration\";\nconst char DecodeImage_UnsupportedPixelFormat[] = //\n \"wuffs_aux::DecodeImage: unsuppo" +
+ "rted pixel format\";\n\n" +
"" +
"// --------\n\nnamespace {\n\nstd::string //\nDecodeImageAdvanceIOBuf(sync_io::Input& input,\n wuffs_base__io_buffer& io_buf,\n bool compactable,\n uint64_t min_excl_pos,\n uint64_t pos) {\n if ((pos <= min_excl_pos) || (pos < io_buf.reader_position())) {\n // Redirects must go forward.\n return DecodeImage_UnsupportedImageFormat;\n }\n while (true) {\n uint64_t relative_pos = pos - io_buf.reader_position();\n if (relative_pos <= io_buf.reader_length()) {\n io_buf.meta.ri += (size_t)relative_pos;\n break;\n } else if (io_buf.meta.closed) {\n return DecodeImage_UnexpectedEndOfFile;\n }\n io_buf.meta.ri = io_buf.meta.wi;\n if (compactable) {\n io_buf.compact();\n }\n std::string error_message = input.CopyIn(&io_buf);\n if (!error_message.empty()) {\n return error_message;\n }\n }\n return \"\";\n}\n\nDecodeImageResult //\nDecodeImage0(wuffs_base__image_decoder::unique_ptr& image_decoder,\n " +
- " DecodeImageCallbacks& callbacks,\n sync_io::Input& input,\n wuffs_base__io_buffer& io_buf,\n uint32_t override_pixel_format_repr,\n wuffs_base__pixel_blend pixel_blend,\n uint32_t max_incl_dimension) {\n // Check args.\n switch (override_pixel_format_repr) {\n case 0:\n case WUFFS_BASE__PIXEL_FORMAT__BGR_565:\n case WUFFS_BASE__PIXEL_FORMAT__BGR:\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:\n break;\n default:\n return DecodeImageResult(DecodeImage_UnsupportedPixelFormat);\n }\n switch (pixel_blend) {\n case WUFFS_BASE__PIXEL_BLEND__SRC:\n case WUFFS_BASE__PIXEL_BLEND__SRC_OVER:\n break;\n default:\n return DecodeImageResult(DecodeImage_UnsupportedPixelBlend);\n }\n\n wuffs_base__image_config image_config = wuffs_base__null_image_config();\n uint64_t start_pos = io_buf.reader_position();\n bool redirected = false;\n int32_t fourcc = 0;\nredirect:\n do {\n // Det" +
- "ermine the image format.\n if (!redirected) {\n while (true) {\n fourcc = wuffs_base__magic_number_guess_fourcc(io_buf.reader_slice());\n if (fourcc > 0) {\n break;\n } else if ((fourcc == 0) && (io_buf.reader_length() >= 64)) {\n break;\n } else if (io_buf.meta.closed || (io_buf.writer_length() == 0)) {\n fourcc = 0;\n break;\n }\n std::string error_message = input.CopyIn(&io_buf);\n if (!error_message.empty()) {\n return DecodeImageResult(std::move(error_message));\n }\n }\n } else {\n wuffs_base__io_buffer empty = wuffs_base__empty_io_buffer();\n wuffs_base__more_information minfo = wuffs_base__empty_more_information();\n wuffs_base__status tmm_status =\n image_decoder->tell_me_more(&empty, &minfo, &io_buf);\n if (!tmm_status.is_ok()) {\n return DecodeImageResult(tmm_status.message());\n }\n if (minfo.flavor != WUFFS_BASE__MORE_INFORMATION__FLAVOR__IO_REDIRECT) {\n " +
- " return DecodeImageResult(DecodeImage_UnsupportedImageFormat);\n }\n uint64_t pos = minfo.io_redirect__range().min_incl;\n std::string error_message = DecodeImageAdvanceIOBuf(\n input, io_buf, !input.BringsItsOwnIOBuffer(), start_pos, pos);\n if (!error_message.empty()) {\n return DecodeImageResult(std::move(error_message));\n }\n fourcc = (int32_t)(minfo.io_redirect__fourcc());\n if (fourcc == 0) {\n return DecodeImageResult(DecodeImage_UnsupportedImageFormat);\n }\n image_decoder.reset();\n }\n\n // Make the image decoder.\n image_decoder = callbacks.OnImageFormat(\n (uint32_t)fourcc,\n fourcc ? wuffs_base__empty_slice_u8() : io_buf.reader_slice());\n if (!image_decoder) {\n return DecodeImageResult(DecodeImage_UnsupportedImageFormat);\n }\n\n // Decode the image config.\n while (true) {\n wuffs_base__status id_dic_status =\n image_decoder->decode_image_config(&image_config, &io_buf);\n if (id_dic_status.repr" +
- " == NULL) {\n break;\n } else if (id_dic_status.repr == wuffs_base__note__i_o_redirect) {\n if (redirected) {\n return DecodeImageResult(DecodeImage_UnsupportedImageFormat);\n }\n redirected = true;\n goto redirect;\n } else if (id_dic_status.repr != wuffs_base__suspension__short_read) {\n return DecodeImageResult(id_dic_status.message());\n } else if (io_buf.meta.closed) {\n return DecodeImageResult(DecodeImage_UnexpectedEndOfFile);\n } else {\n std::string error_message = input.CopyIn(&io_buf);\n if (!error_message.empty()) {\n return DecodeImageResult(std::move(error_message));\n }\n }\n }\n } while (false);\n\n // Apply the override pixel format.\n uint32_t w = image_config.pixcfg.width();\n uint32_t h = image_config.pixcfg.height();\n if ((w > max_incl_dimension) || (h > max_incl_dimension)) {\n return DecodeImageResult(DecodeImage_MaxInclDimensionExceeded);\n }\n if (override_pixel_format_repr != 0) {\n " +
- "image_config.pixcfg.set(override_pixel_format_repr,\n WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, w, h);\n }\n\n // Allocate the pixel buffer.\n uint64_t pixbuf_len_min_incl = 0;\n if ((w > 0) && (h > 0)) {\n pixbuf_len_min_incl = image_config.pixcfg.pixbuf_len();\n if (pixbuf_len_min_incl == 0) {\n return DecodeImageResult(DecodeImage_UnsupportedPixelFormat);\n }\n }\n DecodeImageCallbacks::AllocResult oic_result =\n callbacks.OnImageConfig(image_config);\n if (!oic_result.error_message.empty()) {\n return DecodeImageResult(std::move(oic_result.error_message));\n } else if (oic_result.mem_slice.len < pixbuf_len_min_incl) {\n return DecodeImageResult(DecodeImage_BufferIsTooShort);\n }\n wuffs_base__pixel_buffer pixel_buffer;\n wuffs_base__status pb_sfs_status =\n pixel_buffer.set_from_slice(&image_config.pixcfg, oic_result.mem_slice);\n if (!pb_sfs_status.is_ok()) {\n return DecodeImageResult(pb_sfs_status.message());\n }\n\n // Allocate the work buffer.\n wuffs_base__" +
- "range_ii_u64 workbuf_len = image_decoder->workbuf_len();\n DecodeImageCallbacks::AllocResult alloc_workbuf_result =\n callbacks.AllocWorkbuf(workbuf_len);\n if (!alloc_workbuf_result.error_message.empty()) {\n return DecodeImageResult(std::move(alloc_workbuf_result.error_message));\n } else if (alloc_workbuf_result.mem_slice.len < workbuf_len.min_incl) {\n return DecodeImageResult(DecodeImage_BufferIsTooShort);\n }\n\n // Decode the frame config.\n wuffs_base__frame_config frame_config = wuffs_base__null_frame_config();\n while (true) {\n wuffs_base__status id_dfc_status =\n image_decoder->decode_frame_config(&frame_config, &io_buf);\n if (id_dfc_status.repr == NULL) {\n break;\n } else if (id_dfc_status.repr != wuffs_base__suspension__short_read) {\n return DecodeImageResult(id_dfc_status.message());\n } else if (io_buf.meta.closed) {\n return DecodeImageResult(DecodeImage_UnexpectedEndOfFile);\n } else {\n std::string error_message = input.CopyIn(&io_buf);\n if (!e" +
- "rror_message.empty()) {\n return DecodeImageResult(std::move(error_message));\n }\n }\n }\n\n // Decode the frame (the pixels).\n //\n // From here on, always returns the pixel_buffer. If we get this far, we can\n // still display a partial image, even if we encounter an error.\n std::string message(\"\");\n if ((pixel_blend == WUFFS_BASE__PIXEL_BLEND__SRC_OVER) &&\n frame_config.overwrite_instead_of_blend()) {\n pixel_blend = WUFFS_BASE__PIXEL_BLEND__SRC;\n }\n while (true) {\n wuffs_base__status id_df_status =\n image_decoder->decode_frame(&pixel_buffer, &io_buf, pixel_blend,\n alloc_workbuf_result.mem_slice, NULL);\n if (id_df_status.repr == NULL) {\n break;\n } else if (id_df_status.repr != wuffs_base__suspension__short_read) {\n message = id_df_status.message();\n break;\n } else if (io_buf.meta.closed) {\n message = DecodeImage_UnexpectedEndOfFile;\n break;\n } else {\n std::string error_message = input.CopyIn(&io_b" +
- "uf);\n if (!error_message.empty()) {\n message = std::move(error_message);\n break;\n }\n }\n }\n return DecodeImageResult(std::move(oic_result.mem_owner),\n oic_result.mem_slice, pixel_buffer,\n std::move(message));\n}\n\n} // namespace\n\nDecodeImageResult //\nDecodeImage(DecodeImageCallbacks& callbacks,\n sync_io::Input& input,\n uint32_t override_pixel_format_repr,\n wuffs_base__pixel_blend pixel_blend,\n uint32_t max_incl_dimension) {\n wuffs_base__io_buffer* io_buf = input.BringsItsOwnIOBuffer();\n wuffs_base__io_buffer fallback_io_buf = wuffs_base__empty_io_buffer();\n std::unique_ptr<uint8_t[]> fallback_io_array(nullptr);\n if (!io_buf) {\n fallback_io_array = std::unique_ptr<uint8_t[]>(new uint8_t[32768]);\n fallback_io_buf =\n wuffs_base__ptr_u8__writer(fallback_io_array.get(), 32768);\n io_buf = &fallback_io_buf;\n }\n\n wuffs_base__image_decoder::unique_ptr image_decoder(nullptr, " +
- "&free);\n DecodeImageResult result =\n DecodeImage0(image_decoder, callbacks, input, *io_buf,\n override_pixel_format_repr, pixel_blend, max_incl_dimension);\n callbacks.Done(result, input, *io_buf, std::move(image_decoder));\n return result;\n}\n\n} // namespace wuffs_aux\n\n#endif // !defined(WUFFS_CONFIG__MODULES) ||\n // defined(WUFFS_CONFIG__MODULE__AUX__IMAGE)\n" +
+ " DecodeImageCallbacks& callbacks,\n sync_io::Input& input,\n wuffs_base__io_buffer& io_buf,\n uint32_t override_pixel_format_repr,\n wuffs_base__pixel_blend pixel_blend,\n wuffs_base__color_u32_argb_premul background_color,\n uint32_t max_incl_dimension) {\n // Check args.\n switch (override_pixel_format_repr) {\n case 0:\n case WUFFS_BASE__PIXEL_FORMAT__BGR_565:\n case WUFFS_BASE__PIXEL_FORMAT__BGR:\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:\n break;\n default:\n return DecodeImageResult(DecodeImage_UnsupportedPixelFormat);\n }\n switch (pixel_blend) {\n case WUFFS_BASE__PIXEL_BLEND__SRC:\n case WUFFS_BASE__PIXEL_BLEND__SRC_OVER:\n break;\n default:\n return DecodeImageResult(DecodeImage_UnsupportedPixelBlend);\n }\n\n wuffs_base__image_config image_config = wuffs_base__null_image_config();\n uint64_t start_pos = io_buf.reader_position();\n bool redi" +
+ "rected = false;\n int32_t fourcc = 0;\nredirect:\n do {\n // Determine the image format.\n if (!redirected) {\n while (true) {\n fourcc = wuffs_base__magic_number_guess_fourcc(io_buf.reader_slice());\n if (fourcc > 0) {\n break;\n } else if ((fourcc == 0) && (io_buf.reader_length() >= 64)) {\n break;\n } else if (io_buf.meta.closed || (io_buf.writer_length() == 0)) {\n fourcc = 0;\n break;\n }\n std::string error_message = input.CopyIn(&io_buf);\n if (!error_message.empty()) {\n return DecodeImageResult(std::move(error_message));\n }\n }\n } else {\n wuffs_base__io_buffer empty = wuffs_base__empty_io_buffer();\n wuffs_base__more_information minfo = wuffs_base__empty_more_information();\n wuffs_base__status tmm_status =\n image_decoder->tell_me_more(&empty, &minfo, &io_buf);\n if (tmm_status.repr != nullptr) {\n return DecodeImageResult(tmm_status.message());\n }\n if (minf" +
+ "o.flavor != WUFFS_BASE__MORE_INFORMATION__FLAVOR__IO_REDIRECT) {\n return DecodeImageResult(DecodeImage_UnsupportedImageFormat);\n }\n uint64_t pos = minfo.io_redirect__range().min_incl;\n std::string error_message = DecodeImageAdvanceIOBuf(\n input, io_buf, !input.BringsItsOwnIOBuffer(), start_pos, pos);\n if (!error_message.empty()) {\n return DecodeImageResult(std::move(error_message));\n }\n fourcc = (int32_t)(minfo.io_redirect__fourcc());\n if (fourcc == 0) {\n return DecodeImageResult(DecodeImage_UnsupportedImageFormat);\n }\n image_decoder.reset();\n }\n\n // Make the image decoder.\n image_decoder = callbacks.OnImageFormat(\n (uint32_t)fourcc,\n fourcc ? wuffs_base__empty_slice_u8() : io_buf.reader_slice());\n if (!image_decoder) {\n return DecodeImageResult(DecodeImage_UnsupportedImageFormat);\n }\n\n // Decode the image config.\n while (true) {\n wuffs_base__status id_dic_status =\n image_decoder->d" +
+ "ecode_image_config(&image_config, &io_buf);\n if (id_dic_status.repr == nullptr) {\n break;\n } else if (id_dic_status.repr == wuffs_base__note__i_o_redirect) {\n if (redirected) {\n return DecodeImageResult(DecodeImage_UnsupportedImageFormat);\n }\n redirected = true;\n goto redirect;\n } else if (id_dic_status.repr != wuffs_base__suspension__short_read) {\n return DecodeImageResult(id_dic_status.message());\n } else if (io_buf.meta.closed) {\n return DecodeImageResult(DecodeImage_UnexpectedEndOfFile);\n } else {\n std::string error_message = input.CopyIn(&io_buf);\n if (!error_message.empty()) {\n return DecodeImageResult(std::move(error_message));\n }\n }\n }\n } while (false);\n\n // Apply the override pixel format.\n uint32_t w = image_config.pixcfg.width();\n uint32_t h = image_config.pixcfg.height();\n if ((w > max_incl_dimension) || (h > max_incl_dimension)) {\n return DecodeImageResult(DecodeImage_M" +
+ "axInclDimensionExceeded);\n }\n if (override_pixel_format_repr != 0) {\n image_config.pixcfg.set(override_pixel_format_repr,\n WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, w, h);\n }\n\n // Allocate the pixel buffer.\n uint64_t pixbuf_len_min_incl = 0;\n if ((w > 0) && (h > 0)) {\n pixbuf_len_min_incl = image_config.pixcfg.pixbuf_len();\n if (pixbuf_len_min_incl == 0) {\n return DecodeImageResult(DecodeImage_UnsupportedPixelFormat);\n }\n }\n bool valid_background_color =\n wuffs_base__color_u32_argb_premul__is_valid(background_color);\n DecodeImageCallbacks::AllocResult oic_result =\n callbacks.OnImageConfig(image_config, valid_background_color);\n if (!oic_result.error_message.empty()) {\n return DecodeImageResult(std::move(oic_result.error_message));\n } else if (oic_result.mem_slice.len < pixbuf_len_min_incl) {\n return DecodeImageResult(DecodeImage_BufferIsTooShort);\n }\n wuffs_base__pixel_buffer pixel_buffer;\n wuffs_base__status pb_sfs_status =\n pixel_buff" +
+ "er.set_from_slice(&image_config.pixcfg, oic_result.mem_slice);\n if (!pb_sfs_status.is_ok()) {\n return DecodeImageResult(pb_sfs_status.message());\n }\n if (valid_background_color) {\n wuffs_base__status pb_scufr_status = pixel_buffer.set_color_u32_fill_rect(\n pixel_buffer.pixcfg.bounds(), background_color);\n if (pb_scufr_status.repr != nullptr) {\n return DecodeImageResult(pb_scufr_status.message());\n }\n }\n\n // Allocate the work buffer. Wuffs' decoders conventionally assume that this\n // can be uninitialized memory.\n wuffs_base__range_ii_u64 workbuf_len = image_decoder->workbuf_len();\n DecodeImageCallbacks::AllocResult alloc_workbuf_result =\n callbacks.AllocWorkbuf(workbuf_len, true);\n if (!alloc_workbuf_result.error_message.empty()) {\n return DecodeImageResult(std::move(alloc_workbuf_result.error_message));\n } else if (alloc_workbuf_result.mem_slice.len < workbuf_len.min_incl) {\n return DecodeImageResult(DecodeImage_BufferIsTooShort);\n }\n\n // Decode the frame config" +
+ ".\n wuffs_base__frame_config frame_config = wuffs_base__null_frame_config();\n while (true) {\n wuffs_base__status id_dfc_status =\n image_decoder->decode_frame_config(&frame_config, &io_buf);\n if (id_dfc_status.repr == nullptr) {\n break;\n } else if (id_dfc_status.repr != wuffs_base__suspension__short_read) {\n return DecodeImageResult(id_dfc_status.message());\n } else if (io_buf.meta.closed) {\n return DecodeImageResult(DecodeImage_UnexpectedEndOfFile);\n } else {\n std::string error_message = input.CopyIn(&io_buf);\n if (!error_message.empty()) {\n return DecodeImageResult(std::move(error_message));\n }\n }\n }\n\n // Decode the frame (the pixels).\n //\n // From here on, always returns the pixel_buffer. If we get this far, we can\n // still display a partial image, even if we encounter an error.\n std::string message(\"\");\n if ((pixel_blend == WUFFS_BASE__PIXEL_BLEND__SRC_OVER) &&\n frame_config.overwrite_instead_of_blend()) {\n pixel_blend = WUFFS_B" +
+ "ASE__PIXEL_BLEND__SRC;\n }\n while (true) {\n wuffs_base__status id_df_status =\n image_decoder->decode_frame(&pixel_buffer, &io_buf, pixel_blend,\n alloc_workbuf_result.mem_slice, nullptr);\n if (id_df_status.repr == nullptr) {\n break;\n } else if (id_df_status.repr != wuffs_base__suspension__short_read) {\n message = id_df_status.message();\n break;\n } else if (io_buf.meta.closed) {\n message = DecodeImage_UnexpectedEndOfFile;\n break;\n } else {\n std::string error_message = input.CopyIn(&io_buf);\n if (!error_message.empty()) {\n message = std::move(error_message);\n break;\n }\n }\n }\n return DecodeImageResult(std::move(oic_result.mem_owner),\n oic_result.mem_slice, pixel_buffer,\n std::move(message));\n}\n\n} // namespace\n\nDecodeImageResult //\nDecodeImage(DecodeImageCallbacks& callbacks,\n sync_io::Input& input,\n uint32_t override_pixel_" +
+ "format_repr,\n wuffs_base__pixel_blend pixel_blend,\n wuffs_base__color_u32_argb_premul background_color,\n uint32_t max_incl_dimension) {\n wuffs_base__io_buffer* io_buf = input.BringsItsOwnIOBuffer();\n wuffs_base__io_buffer fallback_io_buf = wuffs_base__empty_io_buffer();\n std::unique_ptr<uint8_t[]> fallback_io_array(nullptr);\n if (!io_buf) {\n fallback_io_array = std::unique_ptr<uint8_t[]>(new uint8_t[32768]);\n fallback_io_buf =\n wuffs_base__ptr_u8__writer(fallback_io_array.get(), 32768);\n io_buf = &fallback_io_buf;\n }\n\n wuffs_base__image_decoder::unique_ptr image_decoder(nullptr, &free);\n DecodeImageResult result = DecodeImage0(\n image_decoder, callbacks, input, *io_buf, override_pixel_format_repr,\n pixel_blend, background_color, max_incl_dimension);\n callbacks.Done(result, input, *io_buf, std::move(image_decoder));\n return result;\n}\n\n} // namespace wuffs_aux\n\n#endif // !defined(WUFFS_CONFIG__MODULES) ||\n // defined(WUFFS_CONFIG__MODU" +
+ "LE__AUX__IMAGE)\n" +
""
const AuxImageHh = "" +
"// ---------------- Auxiliary - Image\n\nnamespace wuffs_aux {\n\nstruct DecodeImageResult {\n DecodeImageResult(MemOwner&& pixbuf_mem_owner0,\n wuffs_base__slice_u8 pixbuf_mem_slice0,\n wuffs_base__pixel_buffer pixbuf0,\n std::string&& error_message0);\n DecodeImageResult(std::string&& error_message0);\n\n MemOwner pixbuf_mem_owner;\n wuffs_base__slice_u8 pixbuf_mem_slice;\n wuffs_base__pixel_buffer pixbuf;\n std::string error_message;\n};\n\n// DecodeImageCallbacks are the callbacks given to DecodeImage. They are always\n// called in this order:\n// 1. OnImageFormat\n// 2. OnImageConfig\n// 3. AllocWorkbuf\n// 4. Done\n//\n// It may return early - the third callback might not be invoked if the second\n// one fails (returns a non-empty error message) - but the final callback\n// (Done) is always invoked.\nclass DecodeImageCallbacks {\n public:\n // AllocResult holds a memory allocation (the result of malloc or new, a\n // statically allocated pointer, etc), or an error " +
"message. The memory is\n // de-allocated when mem_owner goes out of scope and is destroyed.\n struct AllocResult {\n AllocResult(MemOwner&& mem_owner0, wuffs_base__slice_u8 mem_slice0);\n AllocResult(std::string&& error_message0);\n\n MemOwner mem_owner;\n wuffs_base__slice_u8 mem_slice;\n std::string error_message;\n };\n\n // OnImageFormat returns the image decoder for the input data's file format.\n // Returning a nullptr means failure (DecodeImage_UnsupportedImageFormat).\n //\n // Common formats will have a FourCC value in the range [1 ..= 0x7FFF_FFFF],\n // such as WUFFS_BASE__FOURCC__JPEG. A zero FourCC value means that the\n // caller is responsible for examining the opening bytes (a prefix) of the\n // input data. OnImageFormat implementations should not modify those bytes.\n //\n // OnImageFormat might be called more than once, since some image file\n // formats can wrap others. For example, a nominal BMP file can actually\n // contain a JPEG or a PNG.\n //\n // The default OnImageFormat acc" +
- "epts the FOURCC codes listed below. For\n // modular builds (i.e. when #define'ing WUFFS_CONFIG__MODULES), acceptance\n // of the ETC file format is optional (for each value of ETC) and depends on\n // the corresponding module to be enabled at compile time (i.e. #define'ing\n // WUFFS_CONFIG__MODULE__ETC).\n // - WUFFS_BASE__FOURCC__BMP\n // - WUFFS_BASE__FOURCC__GIF\n // - WUFFS_BASE__FOURCC__NIE\n // - WUFFS_BASE__FOURCC__PNG\n // - WUFFS_BASE__FOURCC__WBMP\n virtual wuffs_base__image_decoder::unique_ptr //\n OnImageFormat(uint32_t fourcc, wuffs_base__slice_u8 prefix);\n\n // OnImageConfig allocates the pixel buffer.\n //\n // The default OnImageConfig implementation allocates zeroed memory.\n virtual AllocResult //\n OnImageConfig(const wuffs_base__image_config& image_config);\n\n // AllocWorkbuf allocates the work buffer. The allocated buffer's length\n // should be at least len.min_incl, but larger allocations (up to\n // len.max_incl) may have better performance (by using more memory).\n //\n // Th" +
- "e default AllocWorkbuf implementation allocates len.max_incl bytes of\n // zeroed memory.\n virtual AllocResult //\n AllocWorkbuf(wuffs_base__range_ii_u64 len);\n\n // Done is always the last Callback method called by DecodeImage, whether or\n // not parsing the input encountered an error. Even when successful, trailing\n // data may remain in input and buffer.\n //\n // The image_decoder is the one returned by OnImageFormat (if OnImageFormat\n // was successful), or a no-op unique_ptr otherwise. Like any unique_ptr,\n // ownership moves to the Done implementation.\n //\n // Do not keep a reference to buffer or buffer.data.ptr after Done returns,\n // as DecodeImage may then de-allocate the backing array.\n //\n // The default Done implementation is a no-op, other than running the\n // image_decoder unique_ptr destructor.\n virtual void //\n Done(DecodeImageResult& result,\n sync_io::Input& input,\n IOBuffer& buffer,\n wuffs_base__image_decoder::unique_ptr image_decoder);\n};\n\nextern const char" +
- " DecodeImage_BufferIsTooShort[];\nextern const char DecodeImage_MaxInclDimensionExceeded[];\nextern const char DecodeImage_OutOfMemory[];\nextern const char DecodeImage_UnexpectedEndOfFile[];\nextern const char DecodeImage_UnsupportedImageFormat[];\nextern const char DecodeImage_UnsupportedPixelBlend[];\nextern const char DecodeImage_UnsupportedPixelConfiguration[];\nextern const char DecodeImage_UnsupportedPixelFormat[];\n\n// DecodeImage decodes the image data in input. A variety of image file formats\n// can be decoded, depending on what callbacks.OnImageFormat returns.\n//\n// For animated formats, only the first frame is returned, since the API is\n// simpler for synchronous I/O and having DecodeImage only return when\n// completely done, but rendering animation often involves handling other\n// events in between animation frames. To decode multiple frames of animated\n// images, or for asynchronous I/O (e.g. when decoding an image streamed over\n// the network), use Wuffs' lower level C API instead of its higher level,\n" +
- "// simplified C++ API (the wuffs_aux API).\n//\n// The DecodeImageResult's fields depend on whether decoding succeeded:\n// - On total success, the error_message is empty and pixbuf.pixcfg.is_valid()\n// is true.\n// - On partial success (e.g. the input file was truncated but we are still\n// able to decode some of the pixels), error_message is non-empty but\n// pixbuf.pixcfg.is_valid() is still true. It is up to the caller whether to\n// accept or reject partial success.\n// - On failure, the error_message is non_empty and pixbuf.pixcfg.is_valid()\n// is false.\n//\n// The callbacks allocate the pixel buffer memory and work buffer memory. On\n// success, pixel buffer memory ownership is passed to the DecodeImage caller\n// as the returned pixbuf_mem_owner. Regardless of success or failure, the work\n// buffer memory is deleted.\n//\n// If override_pixel_format_repr is zero then the pixel buffer will have the\n// image file's natural pixel format. For example, GIF images' natural pixel\n// format is an indexed" +
- " one.\n//\n// If override_pixel_format_repr is non-zero (and one of the constants listed\n// below) then the image will be decoded to that particular pixel format:\n// - WUFFS_BASE__PIXEL_FORMAT__BGR_565\n// - WUFFS_BASE__PIXEL_FORMAT__BGR\n// - WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL\n// - WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL\n//\n// The pixel_blend (one of the constants listed below) determines how to\n// composite the decoded image over the pixel buffer's original pixels (as\n// returned by callbacks.OnImageConfig):\n// - WUFFS_BASE__PIXEL_BLEND__SRC\n// - WUFFS_BASE__PIXEL_BLEND__SRC_OVER\n//\n// Decoding fails (with DecodeImage_MaxInclDimensionExceeded) if the image's\n// width or height is greater than max_incl_dimension.\nDecodeImageResult //\nDecodeImage(DecodeImageCallbacks& callbacks,\n sync_io::Input& input,\n uint32_t override_pixel_format_repr,\n wuffs_base__pixel_blend pixel_blend = WUFFS_BASE__PIXEL_BLEND__SRC,\n uint32_t max_incl_dimension = 1048575); // 0x000F_" +
- "FFFF\n\n} // namespace wuffs_aux\n" +
+ "epts the FOURCC codes listed below. For\n // modular builds (i.e. when #define'ing WUFFS_CONFIG__MODULES), acceptance\n // of the ETC file format is optional (for each value of ETC) and depends on\n // the corresponding module to be enabled at compile time (i.e. #define'ing\n // WUFFS_CONFIG__MODULE__ETC).\n // - WUFFS_BASE__FOURCC__BMP\n // - WUFFS_BASE__FOURCC__GIF\n // - WUFFS_BASE__FOURCC__NIE\n // - WUFFS_BASE__FOURCC__PNG\n // - WUFFS_BASE__FOURCC__WBMP\n virtual wuffs_base__image_decoder::unique_ptr //\n OnImageFormat(uint32_t fourcc, wuffs_base__slice_u8 prefix);\n\n // OnImageConfig allocates the pixel buffer.\n //\n // allow_uninitialized_memory will be true if a valid background_color was\n // passed to DecodeImage, since the pixel buffer's contents will be\n // overwritten with that color after OnImageConfig returns.\n //\n // The default OnImageConfig implementation allocates either uninitialized or\n // zeroed memory. Zeroed memory typically corresponds to filling with opaque\n // black or " +
+ "transparent black, depending on the pixel format.\n virtual AllocResult //\n OnImageConfig(const wuffs_base__image_config& image_config,\n bool allow_uninitialized_memory);\n\n // AllocWorkbuf allocates the work buffer. The allocated buffer's length\n // should be at least len_range.min_incl, but larger allocations (up to\n // len_range.max_incl) may have better performance (by using more memory).\n //\n // The default AllocWorkbuf implementation allocates len_range.max_incl bytes\n // of either uninitialized or zeroed memory.\n virtual AllocResult //\n AllocWorkbuf(wuffs_base__range_ii_u64 len_range,\n bool allow_uninitialized_memory);\n\n // Done is always the last Callback method called by DecodeImage, whether or\n // not parsing the input encountered an error. Even when successful, trailing\n // data may remain in input and buffer.\n //\n // The image_decoder is the one returned by OnImageFormat (if OnImageFormat\n // was successful), or a no-op unique_ptr otherwise. Like any un" +
+ "ique_ptr,\n // ownership moves to the Done implementation.\n //\n // Do not keep a reference to buffer or buffer.data.ptr after Done returns,\n // as DecodeImage may then de-allocate the backing array.\n //\n // The default Done implementation is a no-op, other than running the\n // image_decoder unique_ptr destructor.\n virtual void //\n Done(DecodeImageResult& result,\n sync_io::Input& input,\n IOBuffer& buffer,\n wuffs_base__image_decoder::unique_ptr image_decoder);\n};\n\nextern const char DecodeImage_BufferIsTooShort[];\nextern const char DecodeImage_MaxInclDimensionExceeded[];\nextern const char DecodeImage_OutOfMemory[];\nextern const char DecodeImage_UnexpectedEndOfFile[];\nextern const char DecodeImage_UnsupportedImageFormat[];\nextern const char DecodeImage_UnsupportedPixelBlend[];\nextern const char DecodeImage_UnsupportedPixelConfiguration[];\nextern const char DecodeImage_UnsupportedPixelFormat[];\n\n// DecodeImage decodes the image data in input. A variety of image file formats\n// can be dec" +
+ "oded, depending on what callbacks.OnImageFormat returns.\n//\n// For animated formats, only the first frame is returned, since the API is\n// simpler for synchronous I/O and having DecodeImage only return when\n// completely done, but rendering animation often involves handling other\n// events in between animation frames. To decode multiple frames of animated\n// images, or for asynchronous I/O (e.g. when decoding an image streamed over\n// the network), use Wuffs' lower level C API instead of its higher level,\n// simplified C++ API (the wuffs_aux API).\n//\n// The DecodeImageResult's fields depend on whether decoding succeeded:\n// - On total success, the error_message is empty and pixbuf.pixcfg.is_valid()\n// is true.\n// - On partial success (e.g. the input file was truncated but we are still\n// able to decode some of the pixels), error_message is non-empty but\n// pixbuf.pixcfg.is_valid() is still true. It is up to the caller whether to\n// accept or reject partial success.\n// - On failure, the error_me" +
+ "ssage is non_empty and pixbuf.pixcfg.is_valid()\n// is false.\n//\n// The callbacks allocate the pixel buffer memory and work buffer memory. On\n// success, pixel buffer memory ownership is passed to the DecodeImage caller\n// as the returned pixbuf_mem_owner. Regardless of success or failure, the work\n// buffer memory is deleted.\n//\n// If override_pixel_format_repr is zero then the pixel buffer will have the\n// image file's natural pixel format. For example, GIF images' natural pixel\n// format is an indexed one.\n//\n// If override_pixel_format_repr is non-zero (and one of the constants listed\n// below) then the image will be decoded to that particular pixel format:\n// - WUFFS_BASE__PIXEL_FORMAT__BGR_565\n// - WUFFS_BASE__PIXEL_FORMAT__BGR\n// - WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL\n// - WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL\n//\n// The pixel_blend (one of the constants listed below) determines how to\n// composite the decoded image over the pixel buffer's original pixels (as\n// returned by callbacks.OnImageCo" +
+ "nfig):\n// - WUFFS_BASE__PIXEL_BLEND__SRC\n// - WUFFS_BASE__PIXEL_BLEND__SRC_OVER\n//\n// The background_color is used to fill the pixel buffer after\n// callbacks.OnImageConfig returns, if it is valid in the\n// wuffs_base__color_u32_argb_premul__is_valid sense. The default value,\n// 0x0000_0001, is not valid since its Blue channel value (0x01) is greater\n// than its Alpha channel value (0x00). A valid background_color will typically\n// be overwritten when pixel_blend is WUFFS_BASE__PIXEL_BLEND__SRC, but might\n// still be visible on partial (not total) success or when pixel_blend is\n// WUFFS_BASE__PIXEL_BLEND__SRC_OVER and the decoded image is not fully opaque.\n//\n// Decoding fails (with DecodeImage_MaxInclDimensionExceeded) if the image's\n// width or height is greater than max_incl_dimension.\nDecodeImageResult //\nDecodeImage(DecodeImageCallbacks& callbacks,\n sync_io::Input& input,\n uint32_t override_pixel_format_repr,\n wuffs_base__pixel_blend pixel_blend = WUFFS_BASE__PIXEL_BLE" +
+ "ND__SRC,\n wuffs_base__color_u32_argb_premul background_color = 1, // Invalid.\n uint32_t max_incl_dimension = 1048575); // 0x000F_FFFF\n\n} // namespace wuffs_aux\n" +
""
const AuxJsonCc = "" +
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 728a550..75aab2e 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -3153,6 +3153,20 @@
// 0xAARRGGBB (Alpha most significant, Blue least), regardless of endianness.
typedef uint32_t wuffs_base__color_u32_argb_premul;
+// wuffs_base__color_u32_argb_premul__is_valid returns whether c's Red, Green
+// and Blue channels are all less than or equal to its Alpha channel. c uses
+// premultiplied alpha, so 50% opaque 100% saturated red is 0x7F7F_0000 and a
+// value like 0x7F80_0000 is invalid.
+static inline bool //
+wuffs_base__color_u32_argb_premul__is_valid(
+ wuffs_base__color_u32_argb_premul c) {
+ uint32_t a = 0xFF & (c >> 24);
+ uint32_t r = 0xFF & (c >> 16);
+ uint32_t g = 0xFF & (c >> 8);
+ uint32_t b = 0xFF & (c >> 0);
+ return (a >= r) && (a >= g) && (a >= b);
+}
+
static inline uint16_t //
wuffs_base__color_u32_argb_premul__as__color_u16_rgb_565(
wuffs_base__color_u32_argb_premul c) {
@@ -4235,6 +4249,9 @@
uint32_t x,
uint32_t y,
wuffs_base__color_u32_argb_premul color);
+ inline wuffs_base__status set_color_u32_fill_rect(
+ wuffs_base__rect_ie_u32 rect,
+ wuffs_base__color_u32_argb_premul color);
#endif // __cplusplus
} wuffs_base__pixel_buffer;
@@ -4415,6 +4432,12 @@
uint32_t y,
wuffs_base__color_u32_argb_premul color);
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
+wuffs_base__pixel_buffer__set_color_u32_fill_rect(
+ wuffs_base__pixel_buffer* pb,
+ wuffs_base__rect_ie_u32 rect,
+ wuffs_base__color_u32_argb_premul color);
+
#ifdef __cplusplus
inline wuffs_base__status //
@@ -4458,6 +4481,12 @@
return wuffs_base__pixel_buffer__color_u32_at(this, x, y);
}
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
+wuffs_base__pixel_buffer__set_color_u32_fill_rect(
+ wuffs_base__pixel_buffer* pb,
+ wuffs_base__rect_ie_u32 rect,
+ wuffs_base__color_u32_argb_premul color);
+
inline wuffs_base__status //
wuffs_base__pixel_buffer::set_color_u32_at(
uint32_t x,
@@ -4466,6 +4495,13 @@
return wuffs_base__pixel_buffer__set_color_u32_at(this, x, y, color);
}
+inline wuffs_base__status //
+wuffs_base__pixel_buffer::set_color_u32_fill_rect(
+ wuffs_base__rect_ie_u32 rect,
+ wuffs_base__color_u32_argb_premul color) {
+ return wuffs_base__pixel_buffer__set_color_u32_fill_rect(this, rect, color);
+}
+
#endif // __cplusplus
// --------
@@ -9482,18 +9518,26 @@
// OnImageConfig allocates the pixel buffer.
//
- // The default OnImageConfig implementation allocates zeroed memory.
+ // allow_uninitialized_memory will be true if a valid background_color was
+ // passed to DecodeImage, since the pixel buffer's contents will be
+ // overwritten with that color after OnImageConfig returns.
+ //
+ // The default OnImageConfig implementation allocates either uninitialized or
+ // zeroed memory. Zeroed memory typically corresponds to filling with opaque
+ // black or transparent black, depending on the pixel format.
virtual AllocResult //
- OnImageConfig(const wuffs_base__image_config& image_config);
+ OnImageConfig(const wuffs_base__image_config& image_config,
+ bool allow_uninitialized_memory);
// AllocWorkbuf allocates the work buffer. The allocated buffer's length
- // should be at least len.min_incl, but larger allocations (up to
- // len.max_incl) may have better performance (by using more memory).
+ // should be at least len_range.min_incl, but larger allocations (up to
+ // len_range.max_incl) may have better performance (by using more memory).
//
- // The default AllocWorkbuf implementation allocates len.max_incl bytes of
- // zeroed memory.
+ // The default AllocWorkbuf implementation allocates len_range.max_incl bytes
+ // of either uninitialized or zeroed memory.
virtual AllocResult //
- AllocWorkbuf(wuffs_base__range_ii_u64 len);
+ AllocWorkbuf(wuffs_base__range_ii_u64 len_range,
+ bool allow_uninitialized_memory);
// Done is always the last Callback method called by DecodeImage, whether or
// not parsing the input encountered an error. Even when successful, trailing
@@ -9567,6 +9611,15 @@
// - WUFFS_BASE__PIXEL_BLEND__SRC
// - WUFFS_BASE__PIXEL_BLEND__SRC_OVER
//
+// The background_color is used to fill the pixel buffer after
+// callbacks.OnImageConfig returns, if it is valid in the
+// wuffs_base__color_u32_argb_premul__is_valid sense. The default value,
+// 0x0000_0001, is not valid since its Blue channel value (0x01) is greater
+// than its Alpha channel value (0x00). A valid background_color will typically
+// be overwritten when pixel_blend is WUFFS_BASE__PIXEL_BLEND__SRC, but might
+// still be visible on partial (not total) success or when pixel_blend is
+// WUFFS_BASE__PIXEL_BLEND__SRC_OVER and the decoded image is not fully opaque.
+//
// Decoding fails (with DecodeImage_MaxInclDimensionExceeded) if the image's
// width or height is greater than max_incl_dimension.
DecodeImageResult //
@@ -9574,6 +9627,7 @@
sync_io::Input& input,
uint32_t override_pixel_format_repr,
wuffs_base__pixel_blend pixel_blend = WUFFS_BASE__PIXEL_BLEND__SRC,
+ wuffs_base__color_u32_argb_premul background_color = 1, // Invalid.
uint32_t max_incl_dimension = 1048575); // 0x000F_FFFF
} // namespace wuffs_aux
@@ -14863,6 +14917,87 @@
// --------
+static inline void //
+wuffs_base__pixel_buffer__set_color_u32_fill_rect__xxxx(
+ wuffs_base__pixel_buffer* pb,
+ wuffs_base__rect_ie_u32 rect,
+ uint32_t color) {
+ size_t stride = pb->private_impl.planes[0].stride;
+ uint32_t width = wuffs_base__rect_ie_u32__width(&rect);
+ if (((stride & 3) == 0) && ((stride >> 2) == width) &&
+ (rect.min_incl_x == 0)) {
+ uint8_t* ptr =
+ pb->private_impl.planes[0].ptr + (stride * ((size_t)rect.min_incl_y));
+ uint32_t height = wuffs_base__rect_ie_u32__height(&rect);
+ size_t n;
+ for (n = ((size_t)width) * ((size_t)height); n > 0; n--) {
+ wuffs_base__poke_u32le__no_bounds_check(ptr, color);
+ ptr += 4;
+ }
+ return;
+ }
+
+ uint32_t y;
+ for (y = rect.min_incl_y; y < rect.max_excl_y; y++) {
+ uint8_t* ptr = pb->private_impl.planes[0].ptr + (stride * ((size_t)y)) +
+ (4 * ((size_t)rect.min_incl_x));
+ uint32_t n;
+ for (n = width; n > 0; n--) {
+ wuffs_base__poke_u32le__no_bounds_check(ptr, color);
+ ptr += 4;
+ }
+ }
+}
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
+wuffs_base__pixel_buffer__set_color_u32_fill_rect(
+ wuffs_base__pixel_buffer* pb,
+ wuffs_base__rect_ie_u32 rect,
+ wuffs_base__color_u32_argb_premul color) {
+ if (!pb) {
+ return wuffs_base__make_status(wuffs_base__error__bad_receiver);
+ } else if (wuffs_base__rect_ie_u32__is_empty(&rect)) {
+ return wuffs_base__make_status(NULL);
+ }
+ wuffs_base__rect_ie_u32 bounds =
+ wuffs_base__pixel_config__bounds(&pb->pixcfg);
+ if (!wuffs_base__rect_ie_u32__contains_rect(&bounds, rect)) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+
+ if (wuffs_base__pixel_format__is_planar(&pb->pixcfg.private_impl.pixfmt)) {
+ // TODO: support planar formats.
+ return wuffs_base__make_status(wuffs_base__error__unsupported_option);
+ }
+
+ switch (pb->pixcfg.private_impl.pixfmt.repr) {
+ case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
+ wuffs_base__pixel_buffer__set_color_u32_fill_rect__xxxx(
+ pb, rect,
+ wuffs_base__color_u32_argb_premul__as__color_u32_argb_nonpremul(
+ color));
+ return wuffs_base__make_status(NULL);
+
+ case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:
+ case WUFFS_BASE__PIXEL_FORMAT__BGRX:
+ wuffs_base__pixel_buffer__set_color_u32_fill_rect__xxxx(pb, rect, color);
+ return wuffs_base__make_status(NULL);
+
+ // TODO: fast paths for other formats.
+ }
+
+ uint32_t y;
+ for (y = rect.min_incl_y; y < rect.max_excl_y; y++) {
+ uint32_t x;
+ for (x = rect.min_incl_x; x < rect.max_excl_x; x++) {
+ wuffs_base__pixel_buffer__set_color_u32_at(pb, x, y, color);
+ }
+ }
+ return wuffs_base__make_status(NULL);
+}
+
+// --------
+
WUFFS_BASE__MAYBE_STATIC uint8_t //
wuffs_base__pixel_palette__closest_element(
wuffs_base__slice_u8 palette_slice,
@@ -36813,7 +36948,8 @@
DecodeImageCallbacks::AllocResult //
DecodeImageCallbacks::OnImageConfig(
- const wuffs_base__image_config& image_config) {
+ const wuffs_base__image_config& image_config,
+ bool allow_uninitialized_memory) {
uint32_t w = image_config.pixcfg.width();
uint32_t h = image_config.pixcfg.height();
if ((w == 0) || (h == 0)) {
@@ -36823,28 +36959,29 @@
if ((len == 0) || (SIZE_MAX < len)) {
return AllocResult(DecodeImage_UnsupportedPixelConfiguration);
}
- void* ptr = calloc((size_t)len, 1);
- if (!ptr) {
- return AllocResult(DecodeImage_OutOfMemory);
- }
- return AllocResult(MemOwner(ptr, &free),
- wuffs_base__make_slice_u8((uint8_t*)ptr, (size_t)len));
+ void* ptr =
+ allow_uninitialized_memory ? malloc((size_t)len) : calloc((size_t)len, 1);
+ return ptr ? AllocResult(
+ MemOwner(ptr, &free),
+ wuffs_base__make_slice_u8((uint8_t*)ptr, (size_t)len))
+ : AllocResult(DecodeImage_OutOfMemory);
}
DecodeImageCallbacks::AllocResult //
-DecodeImageCallbacks::AllocWorkbuf(wuffs_base__range_ii_u64 len) {
- if (len.max_incl == 0) {
- return DecodeImageCallbacks::AllocResult("");
- } else if (SIZE_MAX < len.max_incl) {
- return DecodeImageCallbacks::AllocResult(DecodeImage_OutOfMemory);
+DecodeImageCallbacks::AllocWorkbuf(wuffs_base__range_ii_u64 len_range,
+ bool allow_uninitialized_memory) {
+ uint64_t len = len_range.max_incl;
+ if (len == 0) {
+ return AllocResult("");
+ } else if (SIZE_MAX < len) {
+ return AllocResult(DecodeImage_OutOfMemory);
}
- void* p = calloc((size_t)len.max_incl, 1);
- if (!p) {
- return DecodeImageCallbacks::AllocResult(DecodeImage_OutOfMemory);
- }
- return DecodeImageCallbacks::AllocResult(
- MemOwner(p, &free),
- wuffs_base__make_slice_u8((uint8_t*)p, (size_t)len.max_incl));
+ void* ptr =
+ allow_uninitialized_memory ? malloc((size_t)len) : calloc((size_t)len, 1);
+ return ptr ? AllocResult(
+ MemOwner(ptr, &free),
+ wuffs_base__make_slice_u8((uint8_t*)ptr, (size_t)len))
+ : AllocResult(DecodeImage_OutOfMemory);
}
void //
@@ -36912,6 +37049,7 @@
wuffs_base__io_buffer& io_buf,
uint32_t override_pixel_format_repr,
wuffs_base__pixel_blend pixel_blend,
+ wuffs_base__color_u32_argb_premul background_color,
uint32_t max_incl_dimension) {
// Check args.
switch (override_pixel_format_repr) {
@@ -36960,7 +37098,7 @@
wuffs_base__more_information minfo = wuffs_base__empty_more_information();
wuffs_base__status tmm_status =
image_decoder->tell_me_more(&empty, &minfo, &io_buf);
- if (!tmm_status.is_ok()) {
+ if (tmm_status.repr != nullptr) {
return DecodeImageResult(tmm_status.message());
}
if (minfo.flavor != WUFFS_BASE__MORE_INFORMATION__FLAVOR__IO_REDIRECT) {
@@ -36991,7 +37129,7 @@
while (true) {
wuffs_base__status id_dic_status =
image_decoder->decode_image_config(&image_config, &io_buf);
- if (id_dic_status.repr == NULL) {
+ if (id_dic_status.repr == nullptr) {
break;
} else if (id_dic_status.repr == wuffs_base__note__i_o_redirect) {
if (redirected) {
@@ -37031,8 +37169,10 @@
return DecodeImageResult(DecodeImage_UnsupportedPixelFormat);
}
}
+ bool valid_background_color =
+ wuffs_base__color_u32_argb_premul__is_valid(background_color);
DecodeImageCallbacks::AllocResult oic_result =
- callbacks.OnImageConfig(image_config);
+ callbacks.OnImageConfig(image_config, valid_background_color);
if (!oic_result.error_message.empty()) {
return DecodeImageResult(std::move(oic_result.error_message));
} else if (oic_result.mem_slice.len < pixbuf_len_min_incl) {
@@ -37044,11 +37184,19 @@
if (!pb_sfs_status.is_ok()) {
return DecodeImageResult(pb_sfs_status.message());
}
+ if (valid_background_color) {
+ wuffs_base__status pb_scufr_status = pixel_buffer.set_color_u32_fill_rect(
+ pixel_buffer.pixcfg.bounds(), background_color);
+ if (pb_scufr_status.repr != nullptr) {
+ return DecodeImageResult(pb_scufr_status.message());
+ }
+ }
- // Allocate the work buffer.
+ // Allocate the work buffer. Wuffs' decoders conventionally assume that this
+ // can be uninitialized memory.
wuffs_base__range_ii_u64 workbuf_len = image_decoder->workbuf_len();
DecodeImageCallbacks::AllocResult alloc_workbuf_result =
- callbacks.AllocWorkbuf(workbuf_len);
+ callbacks.AllocWorkbuf(workbuf_len, true);
if (!alloc_workbuf_result.error_message.empty()) {
return DecodeImageResult(std::move(alloc_workbuf_result.error_message));
} else if (alloc_workbuf_result.mem_slice.len < workbuf_len.min_incl) {
@@ -37060,7 +37208,7 @@
while (true) {
wuffs_base__status id_dfc_status =
image_decoder->decode_frame_config(&frame_config, &io_buf);
- if (id_dfc_status.repr == NULL) {
+ if (id_dfc_status.repr == nullptr) {
break;
} else if (id_dfc_status.repr != wuffs_base__suspension__short_read) {
return DecodeImageResult(id_dfc_status.message());
@@ -37086,8 +37234,8 @@
while (true) {
wuffs_base__status id_df_status =
image_decoder->decode_frame(&pixel_buffer, &io_buf, pixel_blend,
- alloc_workbuf_result.mem_slice, NULL);
- if (id_df_status.repr == NULL) {
+ alloc_workbuf_result.mem_slice, nullptr);
+ if (id_df_status.repr == nullptr) {
break;
} else if (id_df_status.repr != wuffs_base__suspension__short_read) {
message = id_df_status.message();
@@ -37115,6 +37263,7 @@
sync_io::Input& input,
uint32_t override_pixel_format_repr,
wuffs_base__pixel_blend pixel_blend,
+ wuffs_base__color_u32_argb_premul background_color,
uint32_t max_incl_dimension) {
wuffs_base__io_buffer* io_buf = input.BringsItsOwnIOBuffer();
wuffs_base__io_buffer fallback_io_buf = wuffs_base__empty_io_buffer();
@@ -37127,9 +37276,9 @@
}
wuffs_base__image_decoder::unique_ptr image_decoder(nullptr, &free);
- DecodeImageResult result =
- DecodeImage0(image_decoder, callbacks, input, *io_buf,
- override_pixel_format_repr, pixel_blend, max_incl_dimension);
+ DecodeImageResult result = DecodeImage0(
+ image_decoder, callbacks, input, *io_buf, override_pixel_format_repr,
+ pixel_blend, background_color, max_incl_dimension);
callbacks.Done(result, input, *io_buf, std::move(image_decoder));
return result;
}