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