diff options
Diffstat (limited to 'image/png/idat.ha')
-rw-r--r-- | image/png/idat.ha | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/image/png/idat.ha b/image/png/idat.ha new file mode 100644 index 0000000..dd2e749 --- /dev/null +++ b/image/png/idat.ha @@ -0,0 +1,82 @@ +use bufio; +use bytes; +use io; +use memio; + +export type idat_reader = struct { + vtable: io::stream, + src: *reader, +}; + +// Returns a new IDAT reader, which reads consecutive IDAT chunks from a +// [[reader]] and outputs their raw (compressed) contents as a continuous data +// stream. Instead of reading from this directly, users are advised to construct +// a [[decoder]] with [[newdecoder]], and use that to read the uncompressed +// pixel data. +// +// This stream does not need to be closed. +export fn new_idat_reader(src: *reader) idat_reader = { + assert(chunk_type(src) == IDAT, + "Attempted to create IDAT reader for non-IDAT chunk"); + return idat_reader { + vtable = &idat_reader_vtable, + src = src, + }; +}; + +const idat_reader_vtable: io::vtable = io::vtable { + reader = &idat_read, + ... +}; + +fn idat_read( + st: *io::stream, + buf: []u8, +) (size | io::EOF | io::error) = { + let st = st: *idat_reader; + + assert(st.vtable == &idat_reader_vtable); + + for (true) match (io::read(st.src, buf)?) { + case io::EOF => + match (nextchunk(st.src)) { + case let err: (invalid | unsupported) => + return wraperror(err); + case let err: io::error => + return err; + case io::EOF => + return io::EOF; + case let ctype: u32 => + if (ctype != IDAT) { + return io::EOF; + }; + }; + case let z: size => + return z; + }; +}; + +@test fn idat_reader() void = { + const src = memio::fixed(no_filtering); + const read = newreader(&src) as reader; + assert(nextchunk(&read) as u32 == IHDR); + const ihdr = ihdr_read(&read)!; + + let pixbuf: []u8 = alloc([0...], decoder_bufsiz(&ihdr)); + defer free(pixbuf); + + for (true) { + const ctype = nextchunk(&read) as u32; + if (ctype == IDAT) { + break; + }; + io::copy(io::empty, &read)!; + }; + + let idat = new_idat_reader(&read); + let dec = newdecoder(&idat, &ihdr, pixbuf)!; + defer io::close(&dec)!; + const pixels = io::drain(&dec)!; + defer free(pixels); + assert(bytes::equal(pixels, no_filtering_data)); +}; |