diff options
Diffstat (limited to 'image/png/filter.ha')
-rw-r--r-- | image/png/filter.ha | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/image/png/filter.ha b/image/png/filter.ha new file mode 100644 index 0000000..5ae54e9 --- /dev/null +++ b/image/png/filter.ha @@ -0,0 +1,75 @@ +use bytes; +use io; +use memio; + +// Filter modes supported by PNG files. +export type filter = enum u8 { + NONE = 0, + SUB = 1, + UP = 2, + AVERAGE = 3, + PAETH = 4, +}; + +fn applyfilter(dec: *decoder) void = { + const mode = dec.filter as filter; + const bpp = dec.bpp; + switch (mode) { + case filter::NONE => + yield; // no-op + case filter::SUB => + for (let i = bpp; i < len(dec.cr); i += 1) { + dec.cr[i] += dec.cr[i - bpp]; + }; + case filter::UP => + for (let i = 0z; i < len(dec.cr); i += 1) { + dec.cr[i] += dec.pr[i]; + }; + case filter::AVERAGE => + for (let i = 0z; i < bpp; i += 1) { + dec.cr[i] += dec.pr[i] / 2; + }; + for (let i = bpp; i < len(dec.cr); i += 1) { + dec.cr[i] += ((dec.cr[i - bpp]: int + dec.pr[i]: int) / 2): u8; + }; + case filter::PAETH => + applypaeth(dec); + }; + dec.filter = void; + dec.pr[..] = dec.cr[..]; +}; + +@test fn filter_none() void = { + const src = memio::fixed(no_filtering); + const image = load(&src)!; + defer image_finish(&image); + assert(bytes::equal(image.pixels, no_filtering_data)); +}; + +@test fn filter_sub() void = { + const src = memio::fixed(filter_sub_png); + const image = load(&src)!; + defer image_finish(&image); + assert(bytes::equal(image.pixels, filter_sub_data)); +}; + +@test fn filter_up() void = { + const src = memio::fixed(filter_up_png); + const image = load(&src)!; + defer image_finish(&image); + assert(bytes::equal(image.pixels, filter_up_data)); +}; + +@test fn filter_average() void = { + const src = memio::fixed(filter_avg_png); + const image = load(&src)!; + defer image_finish(&image); + assert(bytes::equal(image.pixels, filter_avg_data)); +}; + +@test fn filter_peath() void = { + const src = memio::fixed(filter_peath_png); + const image = load(&src)!; + defer image_finish(&image); + assert(bytes::equal(image.pixels, filter_peath_data)); +}; |