| // Copyright 2020 The Wuffs Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| pri func decoder.filter_and_swizzle!(dst: ptr base.pixel_buffer, workbuf: slice base.u8) base.status, |
| choosy, |
| { |
| var dst_pixfmt : base.pixel_format |
| var dst_bits_per_pixel : base.u32[..= 256] |
| var dst_bytes_per_pixel : base.u64[..= 32] |
| var dst_bytes_per_row : base.u64 |
| var dst_palette : slice base.u8 |
| var tab : table base.u8 |
| |
| var y : base.u32 |
| var dst : slice base.u8 |
| var filter : base.u8 |
| var curr_row : slice base.u8 |
| var prev_row : slice base.u8 |
| |
| // TODO: the dst_pixfmt variable shouldn't be necessary. We should be able |
| // to chain the two calls: "args.dst.pixel_format().bits_per_pixel()". |
| dst_pixfmt = args.dst.pixel_format() |
| dst_bits_per_pixel = dst_pixfmt.bits_per_pixel() |
| if (dst_bits_per_pixel & 7) <> 0 { |
| return base."#unsupported option" |
| } |
| dst_bytes_per_pixel = (dst_bits_per_pixel / 8) as base.u64 |
| dst_bytes_per_row = (this.width as base.u64) * dst_bytes_per_pixel |
| dst_palette = args.dst.palette_or_else(fallback: this.dst_palette[..]) |
| tab = args.dst.plane(p: 0) |
| |
| while y < this.height { |
| assert y < 0x00FF_FFFF via "a < b: a < c; c <= b"(c: this.height) |
| dst = tab.row(y: y) |
| if dst_bytes_per_row < dst.length() { |
| dst = dst[.. dst_bytes_per_row] |
| } |
| |
| if 1 > args.workbuf.length() { |
| return "#internal error: inconsistent workbuf length" |
| } |
| filter = args.workbuf[0] |
| args.workbuf = args.workbuf[1 ..] |
| if this.pass_bytes_per_row > args.workbuf.length() { |
| return "#internal error: inconsistent workbuf length" |
| } |
| curr_row = args.workbuf[.. this.pass_bytes_per_row] |
| args.workbuf = args.workbuf[this.pass_bytes_per_row ..] |
| |
| if filter == 0 { |
| // No-op. |
| } else if filter == 1 { |
| this.filter_1!(curr: curr_row) |
| } else if filter == 2 { |
| this.filter_2!(curr: curr_row, prev: prev_row) |
| } else if filter == 3 { |
| this.filter_3!(curr: curr_row, prev: prev_row) |
| } else if filter == 4 { |
| this.filter_4!(curr: curr_row, prev: prev_row) |
| } else { |
| return "#bad filter" |
| } |
| |
| this.swizzler.swizzle_interleaved_from_slice!( |
| dst: dst, |
| dst_palette: dst_palette, |
| src: curr_row) |
| |
| prev_row = curr_row |
| y += 1 |
| } endwhile |
| |
| return ok |
| } |