Skip to content

Commit

Permalink
std/netpbm: decode 16 bits per channel inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
nigeltao committed Sep 20, 2024
1 parent b369d23 commit dbbb853
Show file tree
Hide file tree
Showing 2 changed files with 194 additions and 8 deletions.
115 changes: 110 additions & 5 deletions release/c/wuffs-unsupported-snapshot.c
Original file line number Diff line number Diff line change
Expand Up @@ -11946,6 +11946,10 @@ struct wuffs_netpbm__decoder__struct {
uint32_t p_do_decode_frame;
} private_impl;

struct {
uint8_t f_buffer[8];
} private_data;

#ifdef __cplusplus
#if defined(WUFFS_BASE__HAVE_UNIQUE_PTR)
using unique_ptr = std::unique_ptr<wuffs_netpbm__decoder, wuffs_unique_ptr_deleter>;
Expand Down Expand Up @@ -61921,7 +61925,14 @@ wuffs_netpbm__decoder__do_decode_frame(

WUFFS_BASE__GENERATED_C_CODE
static wuffs_base__status
wuffs_netpbm__decoder__swizzle(
wuffs_netpbm__decoder__swizzle_easy(
wuffs_netpbm__decoder* self,
wuffs_base__pixel_buffer* a_dst,
wuffs_base__io_buffer* a_src);

WUFFS_BASE__GENERATED_C_CODE
static wuffs_base__status
wuffs_netpbm__decoder__swizzle_hard(
wuffs_netpbm__decoder* self,
wuffs_base__pixel_buffer* a_dst,
wuffs_base__io_buffer* a_src);
Expand Down Expand Up @@ -62396,7 +62407,14 @@ wuffs_netpbm__decoder__do_decode_image_config(
}
self->private_impl.f_max_value = v_n;
}
if (self->private_impl.f_max_value != 255u) {
if (self->private_impl.f_max_value == 255u) {
} else if (self->private_impl.f_max_value == 65535u) {
if (self->private_impl.f_pixfmt == 536870920u) {
self->private_impl.f_pixfmt = 537919499u;
} else if (self->private_impl.f_pixfmt == 2684356744u) {
self->private_impl.f_pixfmt = 2164308923u;
}
} else {
status = wuffs_base__make_status(wuffs_netpbm__error__unsupported_netpbm_file);
goto exit;
}
Expand Down Expand Up @@ -62691,6 +62709,8 @@ wuffs_netpbm__decoder__do_decode_frame(
}
self->private_impl.f_dst_x = 0u;
self->private_impl.f_dst_y = 0u;
self->private_data.f_buffer[6u] = 255u;
self->private_data.f_buffer[7u] = 255u;
v_status = wuffs_base__pixel_swizzler__prepare(&self->private_impl.f_swizzler,
wuffs_base__pixel_buffer__pixel_format(a_dst),
wuffs_base__pixel_buffer__palette(a_dst),
Expand All @@ -62708,7 +62728,11 @@ wuffs_netpbm__decoder__do_decode_frame(
goto ok;
}
while (true) {
v_status = wuffs_netpbm__decoder__swizzle(self, a_dst, a_src);
if (self->private_impl.f_pixfmt != 2164308923u) {
v_status = wuffs_netpbm__decoder__swizzle_easy(self, a_dst, a_src);
} else {
v_status = wuffs_netpbm__decoder__swizzle_hard(self, a_dst, a_src);
}
if (wuffs_base__status__is_ok(&v_status)) {
break;
} else if (v_status.repr != wuffs_netpbm__note__internal_note_short_read) {
Expand Down Expand Up @@ -62740,11 +62764,11 @@ wuffs_netpbm__decoder__do_decode_frame(
return status;
}

// -------- func netpbm.decoder.swizzle
// -------- func netpbm.decoder.swizzle_easy

WUFFS_BASE__GENERATED_C_CODE
static wuffs_base__status
wuffs_netpbm__decoder__swizzle(
wuffs_netpbm__decoder__swizzle_easy(
wuffs_netpbm__decoder* self,
wuffs_base__pixel_buffer* a_dst,
wuffs_base__io_buffer* a_src) {
Expand Down Expand Up @@ -62798,6 +62822,8 @@ wuffs_netpbm__decoder__swizzle(
v_src_bytes_per_pixel = 1u;
if (self->private_impl.f_pixfmt == 2684356744u) {
v_src_bytes_per_pixel = 3u;
} else if (self->private_impl.f_pixfmt == 537919499u) {
v_src_bytes_per_pixel = 2u;
}
v_n = (((uint64_t)(io2_a_src - iop_a_src)) / ((uint64_t)(v_src_bytes_per_pixel)));
v_n = wuffs_base__u64__min(v_n, ((uint64_t)(((uint32_t)(self->private_impl.f_width - self->private_impl.f_dst_x)))));
Expand Down Expand Up @@ -62841,6 +62867,85 @@ wuffs_netpbm__decoder__swizzle(
return status;
}

// -------- func netpbm.decoder.swizzle_hard

WUFFS_BASE__GENERATED_C_CODE
static wuffs_base__status
wuffs_netpbm__decoder__swizzle_hard(
wuffs_netpbm__decoder* self,
wuffs_base__pixel_buffer* a_dst,
wuffs_base__io_buffer* a_src) {
wuffs_base__status status = wuffs_base__make_status(NULL);

wuffs_base__pixel_format v_dst_pixfmt = {0};
uint32_t v_dst_bits_per_pixel = 0;
uint64_t v_dst_bytes_per_pixel = 0;
wuffs_base__table_u8 v_tab = {0};
wuffs_base__slice_u8 v_dst = {0};
uint64_t v_i = 0;

const uint8_t* iop_a_src = NULL;
const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
const uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
const uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
if (a_src && a_src->data.ptr) {
io0_a_src = a_src->data.ptr;
io1_a_src = io0_a_src + a_src->meta.ri;
iop_a_src = io1_a_src;
io2_a_src = io0_a_src + a_src->meta.wi;
}

v_dst_pixfmt = wuffs_base__pixel_buffer__pixel_format(a_dst);
v_dst_bits_per_pixel = wuffs_base__pixel_format__bits_per_pixel(&v_dst_pixfmt);
if ((v_dst_bits_per_pixel & 7u) != 0u) {
status = wuffs_base__make_status(wuffs_base__error__unsupported_option);
goto exit;
}
v_dst_bytes_per_pixel = ((uint64_t)((v_dst_bits_per_pixel / 8u)));
v_tab = wuffs_base__pixel_buffer__plane(a_dst, 0u);
while (self->private_impl.f_dst_y < self->private_impl.f_height) {
v_dst = wuffs_private_impl__table_u8__row_u32(v_tab, self->private_impl.f_dst_y);
v_i = (((uint64_t)(self->private_impl.f_dst_x)) * v_dst_bytes_per_pixel);
if (v_i <= ((uint64_t)(v_dst.len))) {
v_dst = wuffs_base__slice_u8__subslice_i(v_dst, v_i);
}
while (true) {
if (self->private_impl.f_dst_x >= self->private_impl.f_width) {
self->private_impl.f_dst_x = 0u;
self->private_impl.f_dst_y += 1u;
break;
}
if (((uint64_t)(io2_a_src - iop_a_src)) < 6u) {
status = wuffs_base__make_status(wuffs_netpbm__note__internal_note_short_read);
goto ok;
}
self->private_data.f_buffer[5u] = iop_a_src[0u];
self->private_data.f_buffer[4u] = iop_a_src[1u];
self->private_data.f_buffer[3u] = iop_a_src[2u];
self->private_data.f_buffer[2u] = iop_a_src[3u];
self->private_data.f_buffer[1u] = iop_a_src[4u];
self->private_data.f_buffer[0u] = iop_a_src[5u];
iop_a_src += 6u;
wuffs_base__pixel_swizzler__swizzle_interleaved_from_slice(&self->private_impl.f_swizzler, v_dst, wuffs_base__pixel_buffer__palette(a_dst), wuffs_base__make_slice_u8(self->private_data.f_buffer, 8));
if (v_dst_bytes_per_pixel <= ((uint64_t)(v_dst.len))) {
v_dst = wuffs_base__slice_u8__subslice_i(v_dst, v_dst_bytes_per_pixel);
}
self->private_impl.f_dst_x += 1u;
}
}
status = wuffs_base__make_status(NULL);
goto ok;

ok:
goto exit;
exit:
if (a_src && a_src->data.ptr) {
a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}

return status;
}

// -------- func netpbm.decoder.frame_dirty_rect

WUFFS_BASE__GENERATED_C_CODE
Expand Down
87 changes: 84 additions & 3 deletions std/netpbm/decode_netpbm.wuffs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ pub struct decoder? implements base.image_decoder(

swizzler : base.pixel_swizzler,
util : base.utility,
) + (
buffer : array[8] base.u8,
)

pub func decoder.get_quirk(key: base.u32) base.u64 {
Expand Down Expand Up @@ -191,7 +193,15 @@ pri func decoder.do_decode_image_config?(dst: nptr base.image_config, src: base.
this.max_value = n
}

if this.max_value <> 255 {
if this.max_value == 255 {
// No-op.
} else if this.max_value == 65535 {
if this.pixfmt == base.PIXEL_FORMAT__Y {
this.pixfmt = base.PIXEL_FORMAT__Y_16BE
} else if this.pixfmt == base.PIXEL_FORMAT__RGB {
this.pixfmt = base.PIXEL_FORMAT__BGRA_NONPREMUL_4X16LE
}
} else {
return "#unsupported Netpbm file"
}

Expand Down Expand Up @@ -281,6 +291,8 @@ pri func decoder.do_decode_frame?(dst: ptr base.pixel_buffer, src: base.io_reade

this.dst_x = 0
this.dst_y = 0
this.buffer[6] = 0xFF
this.buffer[7] = 0xFF

status = this.swizzler.prepare!(
dst_pixfmt: args.dst.pixel_format(),
Expand All @@ -293,7 +305,11 @@ pri func decoder.do_decode_frame?(dst: ptr base.pixel_buffer, src: base.io_reade
}

while true {
status = this.swizzle!(dst: args.dst, src: args.src)
if this.pixfmt <> base.PIXEL_FORMAT__BGRA_NONPREMUL_4X16LE {
status = this.swizzle_easy!(dst: args.dst, src: args.src)
} else {
status = this.swizzle_hard!(dst: args.dst, src: args.src)
}
if status.is_ok() {
break
} else if status <> "@internal note: short read" {
Expand All @@ -305,7 +321,7 @@ pri func decoder.do_decode_frame?(dst: ptr base.pixel_buffer, src: base.io_reade
this.call_sequence = 0x60
}

pri func decoder.swizzle!(dst: ptr base.pixel_buffer, src: base.io_reader) base.status {
pri func decoder.swizzle_easy!(dst: ptr base.pixel_buffer, src: base.io_reader) base.status {
var dst_pixfmt : base.pixel_format
var dst_bits_per_pixel : base.u32[..= 256]
var dst_bytes_per_pixel : base.u32[..= 32]
Expand Down Expand Up @@ -348,6 +364,9 @@ pri func decoder.swizzle!(dst: ptr base.pixel_buffer, src: base.io_reader) base.
if this.pixfmt == base.PIXEL_FORMAT__RGB {
src_bytes_per_pixel = 3
assert src_bytes_per_pixel > 0
} else if this.pixfmt == base.PIXEL_FORMAT__Y_16BE {
src_bytes_per_pixel = 2
assert src_bytes_per_pixel > 0
}
n = args.src.length() / (src_bytes_per_pixel as base.u64)
n = n.min(no_more_than: (this.width ~mod- this.dst_x) as base.u64)
Expand Down Expand Up @@ -383,6 +402,68 @@ pri func decoder.swizzle!(dst: ptr base.pixel_buffer, src: base.io_reader) base.
return ok
}

pri func decoder.swizzle_hard!(dst: ptr base.pixel_buffer, src: base.io_reader) base.status {
var dst_pixfmt : base.pixel_format
var dst_bits_per_pixel : base.u32[..= 256]
var dst_bytes_per_pixel : base.u64[..= 32]
var tab : table base.u8
var dst : slice base.u8
var i : base.u64

// TODO: the dst_pixfmt variable shouldn't be necessary. We should be able
// to chain the two calls: "args.dst.pixel_format().bits_per_pixel()".
dst_pixfmt = args.dst.pixel_format()
dst_bits_per_pixel = dst_pixfmt.bits_per_pixel()
if (dst_bits_per_pixel & 7) <> 0 {
return base."#unsupported option"
}
dst_bytes_per_pixel = (dst_bits_per_pixel / 8) as base.u64
tab = args.dst.plane(p: 0)

while this.dst_y < this.height {
assert this.dst_y < 0xFF_FFFF via "a < b: a < c; c <= b"(c: this.height)
dst = tab.row_u32(y: this.dst_y)

i = (this.dst_x as base.u64) * dst_bytes_per_pixel
if i <= dst.length() {
dst = dst[i ..]
}

while true,
pre this.dst_y < 0xFF_FFFF,
{
if this.dst_x >= this.width {
this.dst_x = 0
this.dst_y += 1
break
}
assert this.dst_x < 0xFF_FFFF via "a < b: a < c; c <= b"(c: this.width)

if args.src.length() < 6 {
return "@internal note: short read"
}
// Convert RGB_3X16BE to BGR_3X16LE.
this.buffer[5] = args.src.peek_u8_at(offset: 0)
this.buffer[4] = args.src.peek_u8_at(offset: 1)
this.buffer[3] = args.src.peek_u8_at(offset: 2)
this.buffer[2] = args.src.peek_u8_at(offset: 3)
this.buffer[1] = args.src.peek_u8_at(offset: 4)
this.buffer[0] = args.src.peek_u8_at(offset: 5)
args.src.skip_u32_fast!(actual: 6, worst_case: 6)

this.swizzler.swizzle_interleaved_from_slice!(
dst: dst, dst_palette: args.dst.palette(), src: this.buffer[.. 8])

if dst_bytes_per_pixel <= dst.length() {
dst = dst[dst_bytes_per_pixel ..]
}

this.dst_x += 1
}
}
return ok
}

pub func decoder.frame_dirty_rect() base.rect_ie_u32 {
return this.util.make_rect_ie_u32(
min_incl_x: 0,
Expand Down

0 comments on commit dbbb853

Please sign in to comment.