The streaming contract of image decoders: step through input chunks, get whole rows into bounded output slices, with bounded memory.
moon add gaato/codec_image///|
/// Hands each row of the image in `chunks` to `row`, with its pass and its
/// row in the pass.
fn[D : @codec_image.Decode] each_row(
decoder : D,
chunks : Array[Bytes],
row : (Int32, Int32, BytesView) -> Unit,
) -> Unit raise {
let mut out = FixedArray::make(0, b'\x00')
for i, chunk in chunks {
let mut input = chunk[:]
for ;; {
if out.length() < decoder.room_needed() {
out = FixedArray::make(decoder.room_needed() * 16, b'\x00')
}
let status = decoder.step(
input,
out.mut_view(),
end=i == chunks.length() - 1,
)
input = input[decoder.last_consumed():]
match status {
Rows => {
let bytes = Bytes::from_array(out[:decoder.last_produced()])
for r in 0..<decoder.rows_count() {
let at = r * decoder.row_bytes()
row(
decoder.pass(),
decoder.rows_first() + r,
bytes[at:at + decoder.row_bytes()],
)
}
}
Done => return
NeedMoreInput => break
_ => ()
}
}
}
}
///|
test "the loop takes any image decoder, a trait object too" {
let drive : (
&@codec_image.Decode,
Array[Bytes],
(Int32, Int32, BytesView) -> Unit,
) -> Unit raise = each_row
ignore(drive)
}pub(open) trait Decode {
fn step(Self, BytesView, MutArrayView[Byte], end~ : Bool) -> Status raise CodecError
fn last_consumed(Self) -> Int
fn last_produced(Self) -> Int
fn reset(Self) -> Unit
fn memory_usage(Self) -> Int
fn room_needed(Self) -> Int
fn width(Self) -> Int
fn height(Self) -> Int
fn frame_x(Self) -> Int
fn frame_y(Self) -> Int
fn frame_width(Self) -> Int
fn frame_height(Self) -> Int
fn pass(Self) -> Int
fn pass_x(Self) -> Int
fn pass_y(Self) -> Int
fn pass_dx(Self) -> Int
fn pass_dy(Self) -> Int
fn rows_first(Self) -> Int
fn rows_count(Self) -> Int
fn row_bytes(Self) -> Int
}Install
Download zipThe streaming contract of image decoders: step through input chunks, get whole rows into bounded output slices, with bounded memory.