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)); };