summaryrefslogtreecommitdiff
path: root/image/png/filter.ha
diff options
context:
space:
mode:
Diffstat (limited to 'image/png/filter.ha')
-rw-r--r--image/png/filter.ha75
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));
+};