blob: 01103483d0450669382fbf447ca7104a855297a8 [file] [log] [blame]
// 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
}