pixconv: allow swizzling to Y (gray) more often Binary size, before: 124816 gen/lib/c/clang-dynamic/wuffs-base-pixconv.lo 124816 gen/lib/c/clang-static/wuffs-base-pixconv.o 196736 gen/lib/c/gcc-dynamic/wuffs-base-pixconv.lo 196672 gen/lib/c/gcc-static/wuffs-base-pixconv.o After: 142032 gen/lib/c/clang-dynamic/wuffs-base-pixconv.lo 142032 gen/lib/c/clang-static/wuffs-base-pixconv.o 242712 gen/lib/c/gcc-dynamic/wuffs-base-pixconv.lo 242584 gen/lib/c/gcc-static/wuffs-base-pixconv.o
diff --git a/example/stb-imagedumper/stb-imagedumper.c b/example/stb-imagedumper/stb-imagedumper.c index a5bfdfb..87a29d0 100644 --- a/example/stb-imagedumper/stb-imagedumper.c +++ b/example/stb-imagedumper/stb-imagedumper.c
@@ -45,6 +45,8 @@ Define the USE_ONLY_JPEG macro to limit the variety of image file formats that Wuffs decodes to just JPEG, for smaller binaries and faster compiles. +Pass the -ascii-art flag to print ASCII art instead of ANSI color codes. + To run: $CC stb-imagedumper.c && ./a.out *.{jpeg,png}; rm -f a.out @@ -52,6 +54,7 @@ for a C compiler $CC, such as clang or gcc. */ +#include <stdbool.h> #include <stdio.h> #if defined(USE_THE_REAL_STBI) @@ -381,6 +384,7 @@ int remaining_argc; char** remaining_argv; + bool ascii_art; bool demo; } g_flags = {0}; @@ -412,6 +416,10 @@ } } + if (!strcmp(arg, "a") || !strcmp(arg, "ascii-art")) { + g_flags.ascii_art = true; + continue; + } if (!strcmp(arg, "demo")) { g_flags.demo = true; continue; @@ -440,7 +448,7 @@ int w = 0; int h = 0; int channels_in_file = 0; - int bytes_per_pixel = STBI_rgb; + int bytes_per_pixel = g_flags.ascii_art ? STBI_grey : STBI_rgb; unsigned char* pixels = NULL; if (src_len > 0) { @@ -465,10 +473,14 @@ for (int y = 0; y < h; y++) { char* dst = buffer; for (int x = 0; x < w; x++) { - // "\xE2\x96\x88" is U+2588 FULL BLOCK. Before that is a true color - // terminal escape code. - dst += sprintf(dst, "\x1B[38;2;%d;%d;%dm\xE2\x96\x88", // - (uint8_t)src[0], (uint8_t)src[1], (uint8_t)src[2]); + if (g_flags.ascii_art) { + *dst++ = "-:=+IOX@"[(src[0] & 0xFF) >> 5]; + } else { + // "\xE2\x96\x88" is U+2588 FULL BLOCK. Before that is a true color + // terminal escape code. + dst += sprintf(dst, "\x1B[38;2;%d;%d;%dm\xE2\x96\x88", // + (uint8_t)src[0], (uint8_t)src[1], (uint8_t)src[2]); + } src += bytes_per_pixel; } *dst++ = '\n';
diff --git a/internal/cgen/auxiliary/image.cc b/internal/cgen/auxiliary/image.cc index cf41a81..e9f59d2 100644 --- a/internal/cgen/auxiliary/image.cc +++ b/internal/cgen/auxiliary/image.cc
@@ -475,6 +475,7 @@ wuffs_base__pixel_format pixel_format = callbacks.SelectPixfmt(image_config); if (pixel_format.repr != image_config.pixcfg.pixel_format().repr) { switch (pixel_format.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: case WUFFS_BASE__PIXEL_FORMAT__BGR_565: case WUFFS_BASE__PIXEL_FORMAT__BGR: case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
diff --git a/internal/cgen/auxiliary/image.hh b/internal/cgen/auxiliary/image.hh index 14b006d..c2e3251 100644 --- a/internal/cgen/auxiliary/image.hh +++ b/internal/cgen/auxiliary/image.hh
@@ -123,6 +123,7 @@ // SelectPixfmt returns the destination pixel format for AllocPixbuf. It // should return wuffs_base__make_pixel_format(etc) called with one of: + // - WUFFS_BASE__PIXEL_FORMAT__Y // - WUFFS_BASE__PIXEL_FORMAT__BGR_565 // - WUFFS_BASE__PIXEL_FORMAT__BGR // - WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL
diff --git a/internal/cgen/base/image-public.h b/internal/cgen/base/image-public.h index cf546d7..e6b49a7 100644 --- a/internal/cgen/base/image-public.h +++ b/internal/cgen/base/image-public.h
@@ -199,6 +199,46 @@ return (a16 << 48) | (r16 << 32) | (g16 << 16) | (b16 << 0); } +static inline uint8_t // +wuffs_base__color_u64_argb_premul__as__color_u8_gray(uint64_t argb_premul) { + uint32_t r16 = ((uint32_t)(0xFFFF & (argb_premul >> 32))); + uint32_t g16 = ((uint32_t)(0xFFFF & (argb_premul >> 16))); + uint32_t b16 = ((uint32_t)(0xFFFF & (argb_premul >> 0))); + + // These coefficients (the fractions 0.299, 0.587 and 0.114) are the same + // as those given by the JFIF specification. + // + // Note that 19595 + 38470 + 7471 equals 65536, also known as (1 << 16). We + // shift by 24, not just by 16, because the return value is 8-bit color, not + // 16-bit color. + uint32_t weighted_average = + (19595 * r16) + (38470 * g16) + (7471 * b16) + 32768; + return (uint8_t)(weighted_average >> 24); +} + +static inline uint8_t // +wuffs_base__color_u64_argb_nonpremul__as__color_u8_gray( + uint64_t argb_nonpremul) { + uint32_t a16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 48))); + + uint32_t r16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 32))); + r16 = (r16 * a16) / 0xFFFF; + uint32_t g16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 16))); + g16 = (g16 * a16) / 0xFFFF; + uint32_t b16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 0))); + b16 = (b16 * a16) / 0xFFFF; + + // These coefficients (the fractions 0.299, 0.587 and 0.114) are the same + // as those given by the JFIF specification. + // + // Note that 19595 + 38470 + 7471 equals 65536, also known as (1 << 16). We + // shift by 24, not just by 16, because the return value is 8-bit color, not + // 16-bit color. + uint32_t weighted_average = + (19595 * r16) + (38470 * g16) + (7471 * b16) + 32768; + return (uint8_t)(weighted_average >> 24); +} + static inline uint64_t // wuffs_base__color_u32__as__color_u64(uint32_t c) { uint64_t a16 = 0x101 * (0xFF & (c >> 24));
diff --git a/internal/cgen/base/pixconv-submodule-regular.c b/internal/cgen/base/pixconv-submodule-regular.c index 7855acc..0ac5d17 100644 --- a/internal/cgen/base/pixconv-submodule-regular.c +++ b/internal/cgen/base/pixconv-submodule-regular.c
@@ -142,9 +142,8 @@ wuffs_base__peek_u32le__no_bounds_check(row + (4 * ((size_t)x))); case WUFFS_BASE__PIXEL_FORMAT__RGB: - return wuffs_private_impl__swap_u32_argb_abgr( - 0xFF000000 | - wuffs_base__peek_u24le__no_bounds_check(row + (3 * ((size_t)x)))); + return 0xFF000000 | + wuffs_base__peek_u24be__no_bounds_check(row + (3 * ((size_t)x))); case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL: return wuffs_private_impl__swap_u32_argb_abgr( wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul( @@ -860,6 +859,34 @@ // -------- static uint64_t // +wuffs_private_impl__swizzle_squash_align4_y_8888(uint8_t* dst_ptr, + size_t dst_len, + const uint8_t* src_ptr, + size_t src_len, + bool nonpremul) { + size_t len = (dst_len < src_len ? dst_len : src_len) / 4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + + size_t n = len; + while (n--) { + uint32_t argb = wuffs_base__peek_u32le__no_bounds_check(s); + if (nonpremul) { + argb = + wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul(argb); + } + uint32_t s0 = wuffs_base__color_u32_argb_premul__as__color_u8_gray(argb); + wuffs_base__poke_u32le__no_bounds_check( + d, (argb & 0xFF000000) | (s0 * 0x010101)); + s += 4; + d += 4; + } + return len; +} + +// -------- + +static uint64_t // wuffs_private_impl__swizzle_swap_rgb_bgr(uint8_t* dst_ptr, size_t dst_len, uint8_t* dst_palette_ptr, @@ -4685,6 +4712,62 @@ // -------- static uint64_t // +wuffs_private_impl__swizzle_y__bgr(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len3 = src_len / 3; + size_t len = (dst_len < src_len3) ? dst_len : src_len3; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = + 0xFF000000 | wuffs_base__peek_u24le__no_bounds_check(s + (0 * 3)); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0); + + s += 1 * 3; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__bgr_565(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len2 = src_len / 2; + size_t len = (dst_len < src_len2) ? dst_len : src_len2; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = wuffs_base__color_u16_rgb_565__as__color_u32_argb_premul( + wuffs_base__peek_u16le__no_bounds_check(s + (0 * 2))); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0); + + s += 1 * 2; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // wuffs_private_impl__swizzle_y__bgra_nonpremul__src(uint8_t* dst_ptr, size_t dst_len, uint8_t* dst_palette_ptr, @@ -4697,6 +4780,8 @@ const uint8_t* s = src_ptr; size_t n = len; + // TODO: unroll. + while (n >= 1) { uint32_t s0 = wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul( @@ -4725,6 +4810,8 @@ const uint8_t* s = src_ptr; size_t n = len; + // TODO: unroll. + while (n >= 1) { uint32_t d0 = 0xFF000000 | (0x00010101 * ((uint32_t)(d[0]))); uint32_t s0 = wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4)); @@ -4740,6 +4827,154 @@ } static uint64_t // +wuffs_private_impl__swizzle_y__bgra_nonpremul_4x16le__src( + uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len8 = src_len / 8; + size_t len = (dst_len < src_len8) ? dst_len : src_len8; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + d[0] = wuffs_base__color_u64_argb_nonpremul__as__color_u8_gray( + wuffs_base__peek_u64le__no_bounds_check(s + (0 * 8))); + + s += 1 * 8; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__bgra_nonpremul_4x16le__src_over( + uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len8 = src_len / 8; + size_t len = (dst_len < src_len8) ? dst_len : src_len8; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + // Extract 16-bit color components. + uint32_t dr = 0x101 * ((uint32_t)d[0]); + uint32_t dg = 0x101 * ((uint32_t)d[0]); + uint32_t db = 0x101 * ((uint32_t)d[0]); + uint32_t sa = ((uint32_t)wuffs_base__peek_u16le__no_bounds_check(s + 6)); + uint32_t sr = ((uint32_t)wuffs_base__peek_u16le__no_bounds_check(s + 4)); + uint32_t sg = ((uint32_t)wuffs_base__peek_u16le__no_bounds_check(s + 2)); + uint32_t sb = ((uint32_t)wuffs_base__peek_u16le__no_bounds_check(s + 0)); + + // Calculate the inverse of the src-alpha: how much of the dst to keep. + uint32_t ia = 0xFFFF - sa; + + // Composite src (nonpremul) over dst (premul). + dr = ((sr * sa) + (dr * ia)) / 0xFFFF; + dg = ((sg * sa) + (dg * ia)) / 0xFFFF; + db = ((sb * sa) + (db * ia)) / 0xFFFF; + + // Convert to 16-bit color to 8-bit gray. + uint32_t weighted_average = + (19595 * dr) + (38470 * dg) + (7471 * db) + 32768; + d[0] = (uint8_t)(weighted_average >> 24); + + s += 1 * 8; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__bgra_premul__src(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len4 = src_len / 4; + size_t len = (dst_len < src_len4) ? dst_len : src_len4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4)); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0); + + s += 1 * 4; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__bgra_premul__src_over(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len4 = src_len / 4; + size_t len = (dst_len < src_len4) ? dst_len : src_len4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + // Extract 16-bit color components. + uint32_t dr = 0x101 * ((uint32_t)d[0]); + uint32_t dg = 0x101 * ((uint32_t)d[0]); + uint32_t db = 0x101 * ((uint32_t)d[0]); + uint32_t sa = 0x101 * ((uint32_t)s[3]); + uint32_t sr = 0x101 * ((uint32_t)s[2]); + uint32_t sg = 0x101 * ((uint32_t)s[1]); + uint32_t sb = 0x101 * ((uint32_t)s[0]); + + // Calculate the inverse of the src-alpha: how much of the dst to keep. + uint32_t ia = 0xFFFF - sa; + + // Composite src (premul) over dst (premul). + dr = sr + ((dr * ia) / 0xFFFF); + dg = sg + ((dg * ia) / 0xFFFF); + db = sb + ((db * ia) / 0xFFFF); + + // Convert to 16-bit color to 8-bit gray. + uint32_t weighted_average = + (19595 * dr) + (38470 * dg) + (7471 * db) + 32768; + d[0] = (uint8_t)(weighted_average >> 24); + + s += 1 * 4; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // wuffs_private_impl__swizzle_y__bgrx(uint8_t* dst_ptr, size_t dst_len, uint8_t* dst_palette_ptr, @@ -4752,6 +4987,8 @@ const uint8_t* s = src_ptr; size_t n = len; + // TODO: unroll. + while (n >= 1) { uint32_t s0 = 0xFF000000 | wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4)); @@ -4766,6 +5003,152 @@ } static uint64_t // +wuffs_private_impl__swizzle_y__rgb(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len3 = src_len / 3; + size_t len = (dst_len < src_len3) ? dst_len : src_len3; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = + 0xFF000000 | wuffs_base__peek_u24be__no_bounds_check(s + (0 * 3)); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0); + + s += 1 * 3; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__rgba_nonpremul__src(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len4 = src_len / 4; + size_t len = (dst_len < src_len4) ? dst_len : src_len4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = wuffs_private_impl__swap_u32_argb_abgr( + wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul( + wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4)))); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0); + + s += 1 * 4; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__rgba_nonpremul__src_over( + uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len4 = src_len / 4; + size_t len = (dst_len < src_len4) ? dst_len : src_len4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t d0 = 0xFF000000 | (0x00010101 * ((uint32_t)(d[0]))); + uint32_t s0 = wuffs_private_impl__swap_u32_argb_abgr( + wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4))); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray( + wuffs_private_impl__composite_premul_nonpremul_u32_axxx(d0, s0)); + + s += 1 * 4; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__rgba_premul__src(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len4 = src_len / 4; + size_t len = (dst_len < src_len4) ? dst_len : src_len4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = wuffs_private_impl__swap_u32_argb_abgr( + wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4))); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0); + + s += 1 * 4; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__rgba_premul__src_over(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len4 = src_len / 4; + size_t len = (dst_len < src_len4) ? dst_len : src_len4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t d0 = 0xFF000000 | (0x00010101 * ((uint32_t)(d[0]))); + uint32_t s0 = wuffs_private_impl__swap_u32_argb_abgr( + wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4))); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray( + wuffs_private_impl__composite_premul_premul_u32_axxx(d0, s0)); + + s += 1 * 4; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // wuffs_private_impl__swizzle_y__y_16be(uint8_t* dst_ptr, size_t dst_len, uint8_t* dst_palette_ptr, @@ -4778,6 +5161,8 @@ const uint8_t* s = src_ptr; size_t n = len; + // TODO: unroll. + while (n >= 1) { d[0] = s[0]; @@ -4790,6 +5175,162 @@ } static uint64_t // +wuffs_private_impl__swizzle_y__ya_nonpremul__src(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len2 = src_len / 2; + size_t len = (dst_len < src_len2) ? dst_len : src_len2; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = ((uint32_t)(s[1]) << 24) | ((uint32_t)(s[0]) * 0x010101); + d[0] = (uint8_t) + wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul(s0); + + s += 1 * 2; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__ya_nonpremul__src_over(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len2 = src_len / 2; + size_t len = (dst_len < src_len2) ? dst_len : src_len2; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t d0 = 0xFF000000 | ((uint32_t)(d[0]) * 0x010101); + uint32_t s0 = ((uint32_t)(s[1]) << 24) | ((uint32_t)(s[0]) * 0x010101); + d[0] = (uint8_t)wuffs_private_impl__composite_premul_nonpremul_u32_axxx(d0, + s0); + + s += 1 * 2; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__index__src(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + if (dst_palette_len != + WUFFS_BASE__PIXEL_FORMAT__INDEXED__PALETTE_BYTE_LENGTH) { + return 0; + } + size_t len = (dst_len < src_len) ? dst_len : src_len; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + d[0] = dst_palette_ptr[(size_t)s[0] * 4]; + + s += 1 * 1; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__index_bgra_nonpremul__src_over( + uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + if (dst_palette_len != + WUFFS_BASE__PIXEL_FORMAT__INDEXED__PALETTE_BYTE_LENGTH) { + return 0; + } + size_t len = (dst_len < src_len) ? dst_len : src_len; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t d0 = 0xFF000000 | (0x00010101 * ((uint32_t)(d[0]))); + uint32_t s0 = wuffs_base__peek_u32le__no_bounds_check(dst_palette_ptr + + ((size_t)s[0] * 4)); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray( + wuffs_private_impl__composite_premul_nonpremul_u32_axxx(d0, s0)); + + s += 1 * 1; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__index_binary_alpha__src_over( + uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + if (dst_palette_len != + WUFFS_BASE__PIXEL_FORMAT__INDEXED__PALETTE_BYTE_LENGTH) { + return 0; + } + size_t len = (dst_len < src_len) ? dst_len : src_len; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = wuffs_base__peek_u32le__no_bounds_check(dst_palette_ptr + + ((size_t)s[0] * 4)); + if (s0) { + d[0] = (uint8_t)s0; + } + + s += 1 * 1; + d += 1 * 1; + n -= 1; + } + + return len; +} + +// -------- + +static uint64_t // wuffs_private_impl__swizzle_y_16le__y_16be(uint8_t* dst_ptr, size_t dst_len, uint8_t* dst_palette_ptr, @@ -4977,6 +5518,15 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__ya_nonpremul__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__ya_nonpremul__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__YA_NONPREMUL: switch (blend) { case WUFFS_BASE__PIXEL_BLEND__SRC: @@ -5046,6 +5596,26 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + if (wuffs_private_impl__swizzle_squash_align4_y_8888( + dst_palette.ptr, dst_palette.len, src_palette.ptr, + src_palette.len, true) != + (WUFFS_BASE__PIXEL_FORMAT__INDEXED__PALETTE_BYTE_LENGTH / 4)) { + return NULL; + } + return wuffs_private_impl__swizzle_y__index__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + if (wuffs_private_impl__slice_u8__copy_from_slice(dst_palette, + src_palette) != + WUFFS_BASE__PIXEL_FORMAT__INDEXED__PALETTE_BYTE_LENGTH) { + return NULL; + } + return wuffs_private_impl__swizzle_y__index_bgra_nonpremul__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL: if (wuffs_private_impl__slice_u8__copy_from_slice(dst_palette, src_palette) != @@ -5218,6 +5788,21 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + if (wuffs_private_impl__swizzle_squash_align4_y_8888( + dst_palette.ptr, dst_palette.len, src_palette.ptr, + src_palette.len, false) != + (WUFFS_BASE__PIXEL_FORMAT__INDEXED__PALETTE_BYTE_LENGTH / 4)) { + return NULL; + } + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__index__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__index_binary_alpha__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL: case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL: case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY: @@ -5335,6 +5920,9 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + return wuffs_private_impl__swizzle_y__bgr_565; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: return wuffs_private_impl__swizzle_copy_2_2; @@ -5371,6 +5959,9 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + return wuffs_private_impl__swizzle_y__bgr; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: return wuffs_private_impl__swizzle_bgr_565__bgr; @@ -5524,6 +6115,15 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__bgra_nonpremul_4x16le__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__bgra_nonpremul_4x16le__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: switch (blend) { case WUFFS_BASE__PIXEL_BLEND__SRC: @@ -5617,6 +6217,15 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__bgra_premul__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__bgra_premul__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: switch (blend) { case WUFFS_BASE__PIXEL_BLEND__SRC: @@ -5705,6 +6314,15 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__bgra_premul__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__bgra_premul__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: switch (blend) { case WUFFS_BASE__PIXEL_BLEND__SRC: @@ -5839,6 +6457,9 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + return wuffs_private_impl__swizzle_y__rgb; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: return wuffs_private_impl__swizzle_bgr_565__rgb; @@ -5884,6 +6505,15 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__rgba_nonpremul__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__rgba_nonpremul__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: switch (blend) { case WUFFS_BASE__PIXEL_BLEND__SRC: @@ -5982,6 +6612,15 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__rgba_premul__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__rgba_premul__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: switch (blend) { case WUFFS_BASE__PIXEL_BLEND__SRC: @@ -6083,6 +6722,10 @@ #if defined(WUFFS_CONFIG__DST_PIXEL_FORMAT__ENABLE_ALLOWLIST) switch (dst_pixfmt.repr) { +#if defined(WUFFS_CONFIG__DST_PIXEL_FORMAT__ALLOW_Y) + case WUFFS_BASE__PIXEL_FORMAT__Y: + break; +#endif #if defined(WUFFS_CONFIG__DST_PIXEL_FORMAT__ALLOW_BGR_565) case WUFFS_BASE__PIXEL_FORMAT__BGR_565: break;
diff --git a/internal/cgen/base/pixconv-submodule-ycck.c b/internal/cgen/base/pixconv-submodule-ycck.c index 01d7b01..f757cc1 100644 --- a/internal/cgen/base/pixconv-submodule-ycck.c +++ b/internal/cgen/base/pixconv-submodule-ycck.c
@@ -1364,6 +1364,10 @@ #if defined(WUFFS_CONFIG__DST_PIXEL_FORMAT__ENABLE_ALLOWLIST) switch (dst->pixcfg.private_impl.pixfmt.repr) { +#if defined(WUFFS_CONFIG__DST_PIXEL_FORMAT__ALLOW_Y) + case WUFFS_BASE__PIXEL_FORMAT__Y: + break; +#endif #if defined(WUFFS_CONFIG__DST_PIXEL_FORMAT__ALLOW_BGR_565) case WUFFS_BASE__PIXEL_FORMAT__BGR_565: break;
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c index 5e59c99..d9cbee2 100644 --- a/release/c/wuffs-unsupported-snapshot.c +++ b/release/c/wuffs-unsupported-snapshot.c
@@ -4238,6 +4238,46 @@ return (a16 << 48) | (r16 << 32) | (g16 << 16) | (b16 << 0); } +static inline uint8_t // +wuffs_base__color_u64_argb_premul__as__color_u8_gray(uint64_t argb_premul) { + uint32_t r16 = ((uint32_t)(0xFFFF & (argb_premul >> 32))); + uint32_t g16 = ((uint32_t)(0xFFFF & (argb_premul >> 16))); + uint32_t b16 = ((uint32_t)(0xFFFF & (argb_premul >> 0))); + + // These coefficients (the fractions 0.299, 0.587 and 0.114) are the same + // as those given by the JFIF specification. + // + // Note that 19595 + 38470 + 7471 equals 65536, also known as (1 << 16). We + // shift by 24, not just by 16, because the return value is 8-bit color, not + // 16-bit color. + uint32_t weighted_average = + (19595 * r16) + (38470 * g16) + (7471 * b16) + 32768; + return (uint8_t)(weighted_average >> 24); +} + +static inline uint8_t // +wuffs_base__color_u64_argb_nonpremul__as__color_u8_gray( + uint64_t argb_nonpremul) { + uint32_t a16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 48))); + + uint32_t r16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 32))); + r16 = (r16 * a16) / 0xFFFF; + uint32_t g16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 16))); + g16 = (g16 * a16) / 0xFFFF; + uint32_t b16 = ((uint32_t)(0xFFFF & (argb_nonpremul >> 0))); + b16 = (b16 * a16) / 0xFFFF; + + // These coefficients (the fractions 0.299, 0.587 and 0.114) are the same + // as those given by the JFIF specification. + // + // Note that 19595 + 38470 + 7471 equals 65536, also known as (1 << 16). We + // shift by 24, not just by 16, because the return value is 8-bit color, not + // 16-bit color. + uint32_t weighted_average = + (19595 * r16) + (38470 * g16) + (7471 * b16) + 32768; + return (uint8_t)(weighted_average >> 24); +} + static inline uint64_t // wuffs_base__color_u32__as__color_u64(uint32_t c) { uint64_t a16 = 0x101 * (0xFF & (c >> 24)); @@ -16561,6 +16601,7 @@ // SelectPixfmt returns the destination pixel format for AllocPixbuf. It // should return wuffs_base__make_pixel_format(etc) called with one of: + // - WUFFS_BASE__PIXEL_FORMAT__Y // - WUFFS_BASE__PIXEL_FORMAT__BGR_565 // - WUFFS_BASE__PIXEL_FORMAT__BGR // - WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL @@ -23190,9 +23231,8 @@ wuffs_base__peek_u32le__no_bounds_check(row + (4 * ((size_t)x))); case WUFFS_BASE__PIXEL_FORMAT__RGB: - return wuffs_private_impl__swap_u32_argb_abgr( - 0xFF000000 | - wuffs_base__peek_u24le__no_bounds_check(row + (3 * ((size_t)x)))); + return 0xFF000000 | + wuffs_base__peek_u24be__no_bounds_check(row + (3 * ((size_t)x))); case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL: return wuffs_private_impl__swap_u32_argb_abgr( wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul( @@ -23908,6 +23948,34 @@ // -------- static uint64_t // +wuffs_private_impl__swizzle_squash_align4_y_8888(uint8_t* dst_ptr, + size_t dst_len, + const uint8_t* src_ptr, + size_t src_len, + bool nonpremul) { + size_t len = (dst_len < src_len ? dst_len : src_len) / 4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + + size_t n = len; + while (n--) { + uint32_t argb = wuffs_base__peek_u32le__no_bounds_check(s); + if (nonpremul) { + argb = + wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul(argb); + } + uint32_t s0 = wuffs_base__color_u32_argb_premul__as__color_u8_gray(argb); + wuffs_base__poke_u32le__no_bounds_check( + d, (argb & 0xFF000000) | (s0 * 0x010101)); + s += 4; + d += 4; + } + return len; +} + +// -------- + +static uint64_t // wuffs_private_impl__swizzle_swap_rgb_bgr(uint8_t* dst_ptr, size_t dst_len, uint8_t* dst_palette_ptr, @@ -27733,6 +27801,62 @@ // -------- static uint64_t // +wuffs_private_impl__swizzle_y__bgr(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len3 = src_len / 3; + size_t len = (dst_len < src_len3) ? dst_len : src_len3; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = + 0xFF000000 | wuffs_base__peek_u24le__no_bounds_check(s + (0 * 3)); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0); + + s += 1 * 3; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__bgr_565(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len2 = src_len / 2; + size_t len = (dst_len < src_len2) ? dst_len : src_len2; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = wuffs_base__color_u16_rgb_565__as__color_u32_argb_premul( + wuffs_base__peek_u16le__no_bounds_check(s + (0 * 2))); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0); + + s += 1 * 2; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // wuffs_private_impl__swizzle_y__bgra_nonpremul__src(uint8_t* dst_ptr, size_t dst_len, uint8_t* dst_palette_ptr, @@ -27745,6 +27869,8 @@ const uint8_t* s = src_ptr; size_t n = len; + // TODO: unroll. + while (n >= 1) { uint32_t s0 = wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul( @@ -27773,6 +27899,8 @@ const uint8_t* s = src_ptr; size_t n = len; + // TODO: unroll. + while (n >= 1) { uint32_t d0 = 0xFF000000 | (0x00010101 * ((uint32_t)(d[0]))); uint32_t s0 = wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4)); @@ -27788,6 +27916,154 @@ } static uint64_t // +wuffs_private_impl__swizzle_y__bgra_nonpremul_4x16le__src( + uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len8 = src_len / 8; + size_t len = (dst_len < src_len8) ? dst_len : src_len8; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + d[0] = wuffs_base__color_u64_argb_nonpremul__as__color_u8_gray( + wuffs_base__peek_u64le__no_bounds_check(s + (0 * 8))); + + s += 1 * 8; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__bgra_nonpremul_4x16le__src_over( + uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len8 = src_len / 8; + size_t len = (dst_len < src_len8) ? dst_len : src_len8; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + // Extract 16-bit color components. + uint32_t dr = 0x101 * ((uint32_t)d[0]); + uint32_t dg = 0x101 * ((uint32_t)d[0]); + uint32_t db = 0x101 * ((uint32_t)d[0]); + uint32_t sa = ((uint32_t)wuffs_base__peek_u16le__no_bounds_check(s + 6)); + uint32_t sr = ((uint32_t)wuffs_base__peek_u16le__no_bounds_check(s + 4)); + uint32_t sg = ((uint32_t)wuffs_base__peek_u16le__no_bounds_check(s + 2)); + uint32_t sb = ((uint32_t)wuffs_base__peek_u16le__no_bounds_check(s + 0)); + + // Calculate the inverse of the src-alpha: how much of the dst to keep. + uint32_t ia = 0xFFFF - sa; + + // Composite src (nonpremul) over dst (premul). + dr = ((sr * sa) + (dr * ia)) / 0xFFFF; + dg = ((sg * sa) + (dg * ia)) / 0xFFFF; + db = ((sb * sa) + (db * ia)) / 0xFFFF; + + // Convert to 16-bit color to 8-bit gray. + uint32_t weighted_average = + (19595 * dr) + (38470 * dg) + (7471 * db) + 32768; + d[0] = (uint8_t)(weighted_average >> 24); + + s += 1 * 8; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__bgra_premul__src(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len4 = src_len / 4; + size_t len = (dst_len < src_len4) ? dst_len : src_len4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4)); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0); + + s += 1 * 4; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__bgra_premul__src_over(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len4 = src_len / 4; + size_t len = (dst_len < src_len4) ? dst_len : src_len4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + // Extract 16-bit color components. + uint32_t dr = 0x101 * ((uint32_t)d[0]); + uint32_t dg = 0x101 * ((uint32_t)d[0]); + uint32_t db = 0x101 * ((uint32_t)d[0]); + uint32_t sa = 0x101 * ((uint32_t)s[3]); + uint32_t sr = 0x101 * ((uint32_t)s[2]); + uint32_t sg = 0x101 * ((uint32_t)s[1]); + uint32_t sb = 0x101 * ((uint32_t)s[0]); + + // Calculate the inverse of the src-alpha: how much of the dst to keep. + uint32_t ia = 0xFFFF - sa; + + // Composite src (premul) over dst (premul). + dr = sr + ((dr * ia) / 0xFFFF); + dg = sg + ((dg * ia) / 0xFFFF); + db = sb + ((db * ia) / 0xFFFF); + + // Convert to 16-bit color to 8-bit gray. + uint32_t weighted_average = + (19595 * dr) + (38470 * dg) + (7471 * db) + 32768; + d[0] = (uint8_t)(weighted_average >> 24); + + s += 1 * 4; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // wuffs_private_impl__swizzle_y__bgrx(uint8_t* dst_ptr, size_t dst_len, uint8_t* dst_palette_ptr, @@ -27800,6 +28076,8 @@ const uint8_t* s = src_ptr; size_t n = len; + // TODO: unroll. + while (n >= 1) { uint32_t s0 = 0xFF000000 | wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4)); @@ -27814,6 +28092,152 @@ } static uint64_t // +wuffs_private_impl__swizzle_y__rgb(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len3 = src_len / 3; + size_t len = (dst_len < src_len3) ? dst_len : src_len3; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = + 0xFF000000 | wuffs_base__peek_u24be__no_bounds_check(s + (0 * 3)); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0); + + s += 1 * 3; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__rgba_nonpremul__src(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len4 = src_len / 4; + size_t len = (dst_len < src_len4) ? dst_len : src_len4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = wuffs_private_impl__swap_u32_argb_abgr( + wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul( + wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4)))); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0); + + s += 1 * 4; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__rgba_nonpremul__src_over( + uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len4 = src_len / 4; + size_t len = (dst_len < src_len4) ? dst_len : src_len4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t d0 = 0xFF000000 | (0x00010101 * ((uint32_t)(d[0]))); + uint32_t s0 = wuffs_private_impl__swap_u32_argb_abgr( + wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4))); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray( + wuffs_private_impl__composite_premul_nonpremul_u32_axxx(d0, s0)); + + s += 1 * 4; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__rgba_premul__src(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len4 = src_len / 4; + size_t len = (dst_len < src_len4) ? dst_len : src_len4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = wuffs_private_impl__swap_u32_argb_abgr( + wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4))); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0); + + s += 1 * 4; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__rgba_premul__src_over(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len4 = src_len / 4; + size_t len = (dst_len < src_len4) ? dst_len : src_len4; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t d0 = 0xFF000000 | (0x00010101 * ((uint32_t)(d[0]))); + uint32_t s0 = wuffs_private_impl__swap_u32_argb_abgr( + wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4))); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray( + wuffs_private_impl__composite_premul_premul_u32_axxx(d0, s0)); + + s += 1 * 4; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // wuffs_private_impl__swizzle_y__y_16be(uint8_t* dst_ptr, size_t dst_len, uint8_t* dst_palette_ptr, @@ -27826,6 +28250,8 @@ const uint8_t* s = src_ptr; size_t n = len; + // TODO: unroll. + while (n >= 1) { d[0] = s[0]; @@ -27838,6 +28264,162 @@ } static uint64_t // +wuffs_private_impl__swizzle_y__ya_nonpremul__src(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len2 = src_len / 2; + size_t len = (dst_len < src_len2) ? dst_len : src_len2; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = ((uint32_t)(s[1]) << 24) | ((uint32_t)(s[0]) * 0x010101); + d[0] = (uint8_t) + wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul(s0); + + s += 1 * 2; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__ya_nonpremul__src_over(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + size_t src_len2 = src_len / 2; + size_t len = (dst_len < src_len2) ? dst_len : src_len2; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t d0 = 0xFF000000 | ((uint32_t)(d[0]) * 0x010101); + uint32_t s0 = ((uint32_t)(s[1]) << 24) | ((uint32_t)(s[0]) * 0x010101); + d[0] = (uint8_t)wuffs_private_impl__composite_premul_nonpremul_u32_axxx(d0, + s0); + + s += 1 * 2; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__index__src(uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + if (dst_palette_len != + WUFFS_BASE__PIXEL_FORMAT__INDEXED__PALETTE_BYTE_LENGTH) { + return 0; + } + size_t len = (dst_len < src_len) ? dst_len : src_len; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + d[0] = dst_palette_ptr[(size_t)s[0] * 4]; + + s += 1 * 1; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__index_bgra_nonpremul__src_over( + uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + if (dst_palette_len != + WUFFS_BASE__PIXEL_FORMAT__INDEXED__PALETTE_BYTE_LENGTH) { + return 0; + } + size_t len = (dst_len < src_len) ? dst_len : src_len; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t d0 = 0xFF000000 | (0x00010101 * ((uint32_t)(d[0]))); + uint32_t s0 = wuffs_base__peek_u32le__no_bounds_check(dst_palette_ptr + + ((size_t)s[0] * 4)); + d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray( + wuffs_private_impl__composite_premul_nonpremul_u32_axxx(d0, s0)); + + s += 1 * 1; + d += 1 * 1; + n -= 1; + } + + return len; +} + +static uint64_t // +wuffs_private_impl__swizzle_y__index_binary_alpha__src_over( + uint8_t* dst_ptr, + size_t dst_len, + uint8_t* dst_palette_ptr, + size_t dst_palette_len, + const uint8_t* src_ptr, + size_t src_len) { + if (dst_palette_len != + WUFFS_BASE__PIXEL_FORMAT__INDEXED__PALETTE_BYTE_LENGTH) { + return 0; + } + size_t len = (dst_len < src_len) ? dst_len : src_len; + uint8_t* d = dst_ptr; + const uint8_t* s = src_ptr; + size_t n = len; + + // TODO: unroll. + + while (n >= 1) { + uint32_t s0 = wuffs_base__peek_u32le__no_bounds_check(dst_palette_ptr + + ((size_t)s[0] * 4)); + if (s0) { + d[0] = (uint8_t)s0; + } + + s += 1 * 1; + d += 1 * 1; + n -= 1; + } + + return len; +} + +// -------- + +static uint64_t // wuffs_private_impl__swizzle_y_16le__y_16be(uint8_t* dst_ptr, size_t dst_len, uint8_t* dst_palette_ptr, @@ -28025,6 +28607,15 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__ya_nonpremul__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__ya_nonpremul__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__YA_NONPREMUL: switch (blend) { case WUFFS_BASE__PIXEL_BLEND__SRC: @@ -28094,6 +28685,26 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + if (wuffs_private_impl__swizzle_squash_align4_y_8888( + dst_palette.ptr, dst_palette.len, src_palette.ptr, + src_palette.len, true) != + (WUFFS_BASE__PIXEL_FORMAT__INDEXED__PALETTE_BYTE_LENGTH / 4)) { + return NULL; + } + return wuffs_private_impl__swizzle_y__index__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + if (wuffs_private_impl__slice_u8__copy_from_slice(dst_palette, + src_palette) != + WUFFS_BASE__PIXEL_FORMAT__INDEXED__PALETTE_BYTE_LENGTH) { + return NULL; + } + return wuffs_private_impl__swizzle_y__index_bgra_nonpremul__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL: if (wuffs_private_impl__slice_u8__copy_from_slice(dst_palette, src_palette) != @@ -28266,6 +28877,21 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + if (wuffs_private_impl__swizzle_squash_align4_y_8888( + dst_palette.ptr, dst_palette.len, src_palette.ptr, + src_palette.len, false) != + (WUFFS_BASE__PIXEL_FORMAT__INDEXED__PALETTE_BYTE_LENGTH / 4)) { + return NULL; + } + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__index__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__index_binary_alpha__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL: case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL: case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY: @@ -28383,6 +29009,9 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + return wuffs_private_impl__swizzle_y__bgr_565; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: return wuffs_private_impl__swizzle_copy_2_2; @@ -28419,6 +29048,9 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + return wuffs_private_impl__swizzle_y__bgr; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: return wuffs_private_impl__swizzle_bgr_565__bgr; @@ -28572,6 +29204,15 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__bgra_nonpremul_4x16le__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__bgra_nonpremul_4x16le__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: switch (blend) { case WUFFS_BASE__PIXEL_BLEND__SRC: @@ -28665,6 +29306,15 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__bgra_premul__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__bgra_premul__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: switch (blend) { case WUFFS_BASE__PIXEL_BLEND__SRC: @@ -28753,6 +29403,15 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__bgra_premul__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__bgra_premul__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: switch (blend) { case WUFFS_BASE__PIXEL_BLEND__SRC: @@ -28887,6 +29546,9 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + return wuffs_private_impl__swizzle_y__rgb; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: return wuffs_private_impl__swizzle_bgr_565__rgb; @@ -28932,6 +29594,15 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__rgba_nonpremul__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__rgba_nonpremul__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: switch (blend) { case WUFFS_BASE__PIXEL_BLEND__SRC: @@ -29030,6 +29701,15 @@ wuffs_base__slice_u8 src_palette, wuffs_base__pixel_blend blend) { switch (dst_pixfmt.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: + switch (blend) { + case WUFFS_BASE__PIXEL_BLEND__SRC: + return wuffs_private_impl__swizzle_y__rgba_premul__src; + case WUFFS_BASE__PIXEL_BLEND__SRC_OVER: + return wuffs_private_impl__swizzle_y__rgba_premul__src_over; + } + return NULL; + case WUFFS_BASE__PIXEL_FORMAT__BGR_565: switch (blend) { case WUFFS_BASE__PIXEL_BLEND__SRC: @@ -29131,6 +29811,10 @@ #if defined(WUFFS_CONFIG__DST_PIXEL_FORMAT__ENABLE_ALLOWLIST) switch (dst_pixfmt.repr) { +#if defined(WUFFS_CONFIG__DST_PIXEL_FORMAT__ALLOW_Y) + case WUFFS_BASE__PIXEL_FORMAT__Y: + break; +#endif #if defined(WUFFS_CONFIG__DST_PIXEL_FORMAT__ALLOW_BGR_565) case WUFFS_BASE__PIXEL_FORMAT__BGR_565: break; @@ -30716,6 +31400,10 @@ #if defined(WUFFS_CONFIG__DST_PIXEL_FORMAT__ENABLE_ALLOWLIST) switch (dst->pixcfg.private_impl.pixfmt.repr) { +#if defined(WUFFS_CONFIG__DST_PIXEL_FORMAT__ALLOW_Y) + case WUFFS_BASE__PIXEL_FORMAT__Y: + break; +#endif #if defined(WUFFS_CONFIG__DST_PIXEL_FORMAT__ALLOW_BGR_565) case WUFFS_BASE__PIXEL_FORMAT__BGR_565: break; @@ -84678,6 +85366,7 @@ wuffs_base__pixel_format pixel_format = callbacks.SelectPixfmt(image_config); if (pixel_format.repr != image_config.pixcfg.pixel_format().repr) { switch (pixel_format.repr) { + case WUFFS_BASE__PIXEL_FORMAT__Y: case WUFFS_BASE__PIXEL_FORMAT__BGR_565: case WUFFS_BASE__PIXEL_FORMAT__BGR: case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
diff --git a/test/c/std/wbmp.c b/test/c/std/wbmp.c index 1aa176b..2a96541 100644 --- a/test/c/std/wbmp.c +++ b/test/c/std/wbmp.c
@@ -378,10 +378,10 @@ // When updating this list, also consider updating the pixel formats that // fuzz/c/std/pixel_swizzler_fuzzer.c exercises and those that // wuffs_aux::DecodeImageCallbacks::SelectPixfmt accepts. - // - // SelectPixfmt excludes WUFFS_BASE__PIXEL_FORMAT__Y, even though we test - // it here, since it doesn't support every source pixel format in the - // srcs array. See "dst WUFFS_BASE__PIXEL_FORMAT__Y allow-list" below. + { + .color = 0xFF999999, + .pixfmt_repr = WUFFS_BASE__PIXEL_FORMAT__Y, + }, { .color = 0xFF000010, .pixfmt_repr = WUFFS_BASE__PIXEL_FORMAT__BGR_565, @@ -414,10 +414,6 @@ .color = 0x33002233, .pixfmt_repr = WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL, }, - { - .color = 0xFF999999, - .pixfmt_repr = WUFFS_BASE__PIXEL_FORMAT__Y, - }, }; const wuffs_base__pixel_blend blends[] = { @@ -455,19 +451,6 @@ } for (size_t d = 0; d < WUFFS_TESTLIB_ARRAY_SIZE(dsts); d++) { - // See "dst WUFFS_BASE__PIXEL_FORMAT__Y allow-list" above. - if (dsts[d].pixfmt_repr == WUFFS_BASE__PIXEL_FORMAT__Y) { - switch (srcs[s].pixfmt_repr) { - case WUFFS_BASE__PIXEL_FORMAT__Y: - case WUFFS_BASE__PIXEL_FORMAT__Y_16BE: - case WUFFS_BASE__PIXEL_FORMAT__BGRX: - case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL: - break; - default: - continue; - } - } - // Allocate the dst_pixbuf. wuffs_base__pixel_config dst_pixcfg = ((wuffs_base__pixel_config){}); wuffs_base__pixel_config__set(&dst_pixcfg, dsts[d].pixfmt_repr,