Files
DarkRoom/third_party/rawler-0.7.2/src/decompressors/crx/idwt.rs
T
dtourolle 77a1925bac Vendor rawler 0.7.2 unmodified
The crate as crates.io publishes it, minus .cargo-ok, its Cargo.lock and
data/testdata (13 MB of sample files only its own tests read). Not yet
routed through [patch.crates-io]; the next commit is the patch.
2026-09-27 17:33:19 -04:00

571 lines
21 KiB
Rust

// SPDX-License-Identifier: LGPL-2.1
// Copyright 2021 Daniel Vogelbacher <daniel@chaospixel.com>
// Original Crx decoder crx.cpp was written by Alexey Danilchenko for libraw.
// Rewritten in Rust by Daniel Vogelbacher, based on logic found in
// crx.cpp and documentation done by Laurent Clévy (https://github.com/lclevy/canon_cr3).
use super::{
BandParam, CodecParams, Result,
mdat::{Plane, Tile},
};
/// This structure holds the inverse transformation state
/// Each level has it's own state, so for 3 levels of DWT
/// 3 instances are required.
#[derive(Debug, Clone)]
pub(crate) struct WaveletTransform {
/// Contains the decoded data from LL band
/// or from a previous level decode.
band0_buf: Vec<i32>,
/// Contains the decoded data for HL band of current level
band1_buf: Vec<i32>,
/// Contains the decoded data for LH band of current level
band2_buf: Vec<i32>,
/// Contains the decoded data for HH band of current level
band3_buf: Vec<i32>,
/// 8 temporary buffers for inverse transformation (5/3?)
band0_pos: usize,
band1_pos: usize,
band2_pos: usize,
band3_pos: usize,
line_buf: [Vec<i32>; 8],
/// Current line position
cur_line: usize,
/// TODO ???
cur_h: usize,
/// TODO ???
flt_tap_h: usize,
/// Height of the final image for the current level
height: usize,
/// Width of the final image for the current level
width: usize,
}
impl WaveletTransform {
pub(crate) fn new(height: usize, width: usize) -> Self {
// Line buffers for inverse transformation
let line_buf = [
vec![0; width],
vec![0; width],
vec![0; width],
vec![0; width],
vec![0; width],
vec![0; width],
vec![0; width],
vec![0; width],
];
Self {
// We use empty vectors, they will be replaced
// with the result of a line decode.
band0_buf: Vec::new(),
band1_buf: Vec::new(),
band2_buf: Vec::new(),
band3_buf: Vec::new(),
band0_pos: 0,
band1_pos: 0,
band2_pos: 0,
band3_pos: 0,
line_buf,
cur_line: 0,
cur_h: 0,
flt_tap_h: 0,
height,
width,
}
}
pub(super) fn getline(&mut self) -> &Vec<i32> {
let result = &self.line_buf[(self.flt_tap_h as i32 - self.cur_h as i32 + 5) as usize % 5 + 3];
debug_assert!(self.cur_h > 0);
self.cur_h -= 1;
result
}
pub(super) fn band0(&mut self, offset: usize) -> i32 {
self.band0_buf[self.band0_pos + offset]
}
pub(super) fn band1(&mut self, offset: usize) -> i32 {
self.band1_buf[self.band1_pos + offset]
}
pub(super) fn band2(&mut self, offset: usize) -> i32 {
self.band2_buf[self.band2_pos + offset]
}
pub(super) fn band3(&mut self, offset: usize) -> i32 {
self.band3_buf[self.band3_pos + offset]
}
pub(super) fn advance_bufs(&mut self, count: usize) {
self.band0_pos += count;
self.band1_pos += count;
self.band2_pos += count;
self.band3_pos += count;
}
pub(super) fn reset_bufs(&mut self) {
self.band0_pos = 0;
self.band1_pos = 0;
self.band2_pos = 0;
self.band3_pos = 0;
}
}
impl CodecParams {
pub(super) fn idwt_53_filter_decode(
&self,
tile: &Tile,
plane: &Plane,
params: &mut Vec<BandParam>,
iwt_transforms: &mut Vec<WaveletTransform>,
level: usize,
) -> Result<()> {
if iwt_transforms[level].cur_h > 0 {
return Ok(());
}
let cur_band = 3 * level;
let q_step_level = tile.q_step.as_ref().map(|f| &f[level]);
if iwt_transforms[level].height - 3 <= iwt_transforms[level].cur_line && !tile.tiles_bottom {
if iwt_transforms[level].height & 1 == 1 {
if level > 0 {
self.idwt_53_filter_decode(tile, plane, params, iwt_transforms, level - 1)?;
} else {
let sband = &plane.subbands[cur_band];
iwt_transforms[level].band0_buf = self.decode_line_with_iquantization(sband, &mut params[cur_band], q_step_level)?;
}
let sband = &plane.subbands[cur_band + 1];
iwt_transforms[level].band1_buf = self.decode_line_with_iquantization(sband, &mut params[cur_band + 1], q_step_level)?;
}
} else {
if level > 0 {
self.idwt_53_filter_decode(tile, plane, params, iwt_transforms, level - 1)?;
} else {
// LL band
let sband = &plane.subbands[cur_band];
iwt_transforms[level].band0_buf = self.decode_line_with_iquantization(sband, &mut params[cur_band], q_step_level)?;
}
// HL, LH and HH band
iwt_transforms[level].band1_buf = self.decode_line_with_iquantization(&plane.subbands[cur_band + 1], &mut params[cur_band + 1], q_step_level)?;
iwt_transforms[level].band2_buf = self.decode_line_with_iquantization(&plane.subbands[cur_band + 2], &mut params[cur_band + 2], q_step_level)?;
iwt_transforms[level].band3_buf = self.decode_line_with_iquantization(&plane.subbands[cur_band + 3], &mut params[cur_band + 3], q_step_level)?;
}
Ok(())
}
pub(super) fn idwt_53_horizontal(&self, tile: &Tile, la: usize, lb: usize, wvlt: &mut WaveletTransform) {
//let mut b0pos = 0;
//let mut b1pos = 0;
//let mut b2pos = 0;
//let mut b3pos = 0;
let mut lapos = 0;
let mut lbpos = 0;
wvlt.reset_bufs();
if wvlt.width <= 1 {
wvlt.line_buf[la][0] = wvlt.band0(0);
wvlt.line_buf[lb][0] = wvlt.band2(0);
} else {
if tile.tiles_left {
// Untested
wvlt.line_buf[la][0] = wvlt.band0(0) - ((wvlt.band1(0) + wvlt.band1(1) + 2) >> 2);
wvlt.line_buf[lb][0] = wvlt.band2(0) - ((wvlt.band3(0) + wvlt.band3(1) + 2) >> 2);
wvlt.band1_pos += 1;
wvlt.band3_pos += 1;
} else {
wvlt.line_buf[la][0] = wvlt.band0(0) - ((wvlt.band1(0) + 1) >> 1);
wvlt.line_buf[lb][0] = wvlt.band2(0) - ((wvlt.band3(0) + 1) >> 1);
}
wvlt.band0_pos += 1;
wvlt.band2_pos += 1;
//println!("config: tile: {}, {}, band1 width: {}", tile.id, wvlt.width - 3, wvlt.band1_buf.len());
for _i in (0..(wvlt.width - 3)).step_by(2) {
//println!("val: {}, band1_pos: {}, band1_size: {}", _i, wvlt.band1_pos, wvlt.band1_buf.len());
let delta = wvlt.band0(0) - ((wvlt.band1(0) + wvlt.band1(1) + 2) >> 2);
wvlt.line_buf[la][lapos + 1] = wvlt.band1(0) + ((delta + wvlt.line_buf[la][lapos]) >> 1);
wvlt.line_buf[la][lapos + 2] = delta;
let delta = wvlt.band2(0) - ((wvlt.band3(0) + wvlt.band3(1) + 2) >> 2);
wvlt.line_buf[lb][lbpos + 1] = wvlt.band3(0) + ((delta + wvlt.line_buf[lb][lbpos]) >> 1);
wvlt.line_buf[lb][lbpos + 2] = delta;
wvlt.advance_bufs(1);
lapos += 2;
lbpos += 2;
}
if tile.tiles_right {
// Untested
let delta_a = wvlt.band0(0) - ((wvlt.band1(0) + wvlt.band1(1) + 2) >> 2);
wvlt.line_buf[la][lapos + 1] = wvlt.band1(0) + ((delta_a + wvlt.line_buf[la][lapos + 0]) >> 1);
let delta_b = wvlt.band2(0) - ((wvlt.band3(0) + wvlt.band3(1) + 2) >> 2);
wvlt.line_buf[lb][lbpos + 1] = wvlt.band3(0) + ((delta_b + wvlt.line_buf[lb][lbpos + 0]) >> 1);
if wvlt.width & 1 == 1 {
wvlt.line_buf[la][lapos + 2] = delta_a;
wvlt.line_buf[lb][lbpos + 2] = delta_b;
}
} else if wvlt.width & 1 == 1 {
wvlt.line_buf[la][lapos + 1] = wvlt.band1(0) + ((wvlt.line_buf[la][lapos] + wvlt.band0(0) - ((wvlt.band1(0) + 1) >> 1)) >> 1);
wvlt.line_buf[la][lapos + 2] = wvlt.band0(0) - ((wvlt.band1(0) + 1) >> 1);
wvlt.line_buf[lb][lbpos + 1] = wvlt.band3(0) + ((wvlt.line_buf[lb][lbpos] + wvlt.band2(0) - ((wvlt.band3(0) + 1) >> 1)) >> 1);
wvlt.line_buf[lb][lbpos + 2] = wvlt.band2(0) - ((wvlt.band3(0) + 1) >> 1);
} else {
wvlt.line_buf[la][lapos + 1] = wvlt.line_buf[la][lapos + 0] + wvlt.band1(0);
wvlt.line_buf[lb][lbpos + 1] = wvlt.line_buf[lb][lbpos + 0] + wvlt.band3(0);
}
}
}
pub(super) fn idwt_53_filter_init(
&self,
tile: &Tile,
plane: &Plane,
params: &mut Vec<BandParam>,
iwt_transforms: &mut Vec<WaveletTransform>,
level: usize,
) -> Result<()> {
assert!(level > 0);
if level == 0 {
// This code is not called from pathes where level is 0. But we keep this check.
return Ok(());
}
let mut cur_band = 0;
for cur_level in 0..level {
let q_step_level = tile.q_step.as_ref().map(|f| &f[cur_level]);
if cur_level > 0 {
iwt_transforms[cur_level].band0_buf = iwt_transforms[cur_level - 1].getline().clone();
} else {
iwt_transforms[cur_level].band0_buf = self.decode_line_with_iquantization(&plane.subbands[cur_band], &mut params[cur_band], q_step_level)?;
}
let wvlt = &mut iwt_transforms[cur_level];
let h0 = wvlt.flt_tap_h + 3;
if wvlt.height > 1 {
wvlt.band1_buf = self.decode_line_with_iquantization(&plane.subbands[cur_band + 1], &mut params[cur_band + 1], q_step_level)?;
wvlt.band2_buf = self.decode_line_with_iquantization(&plane.subbands[cur_band + 2], &mut params[cur_band + 2], q_step_level)?;
wvlt.band3_buf = self.decode_line_with_iquantization(&plane.subbands[cur_band + 3], &mut params[cur_band + 3], q_step_level)?;
let l0 = 0;
let l1 = 1;
let l2 = 2;
let mut l2_pos = 0;
if tile.tiles_top {
self.idwt_53_horizontal(tile, l0, 1, wvlt);
wvlt.band3_buf = self.decode_line_with_iquantization(&plane.subbands[cur_band + 3], &mut params[cur_band + 3], q_step_level)?;
wvlt.band2_buf = self.decode_line_with_iquantization(&plane.subbands[cur_band + 2], &mut params[cur_band + 2], q_step_level)?;
// process L band
if wvlt.width <= 1 {
wvlt.line_buf[l2][0] = wvlt.band2(0);
} else {
if tile.tiles_left {
wvlt.line_buf[l2][0] = wvlt.band2(0) - ((wvlt.band3(0) + wvlt.band3(1) + 2) >> 2);
wvlt.band3_pos += 1;
} else {
wvlt.line_buf[l2][0] = wvlt.band2(0) - ((wvlt.band3(0) + 1) >> 1);
}
wvlt.band2_pos += 1;
for _i in (0..wvlt.width - 3).step_by(2) {
let delta = wvlt.band2(0) - ((wvlt.band3(0) + wvlt.band3(1) + 2) >> 2);
wvlt.line_buf[l2][1] = wvlt.band3(0) + ((wvlt.line_buf[l2][l2_pos] + delta) >> 1);
wvlt.line_buf[l2][2] = delta;
wvlt.band2_pos += 1;
wvlt.band3_pos += 1;
l2_pos += 2;
}
if tile.tiles_right {
let delta = wvlt.band2(0) - ((wvlt.band3(0) + wvlt.band3(1) + 2) >> 2);
wvlt.line_buf[l2][l2_pos + 1] = wvlt.band3(0) + ((wvlt.line_buf[l2][l2_pos + 0] + delta) >> 1);
if wvlt.width & 1 == 1 {
wvlt.line_buf[l2][l2_pos + 1] = delta;
}
} else if wvlt.width & 1 == 1 {
let delta = wvlt.band2(0) - ((wvlt.band3(0) + 1) >> 1);
wvlt.line_buf[l2][l2_pos + 1] = wvlt.band3(0) + ((wvlt.line_buf[l2][l2_pos + 0] + delta) >> 1);
wvlt.line_buf[l2][l2_pos + 2] = delta;
} else {
wvlt.line_buf[l2][l2_pos + 1] = wvlt.band3(0) + wvlt.line_buf[l2][l2_pos + 0];
}
}
// process H band
for i in 0..wvlt.width {
wvlt.line_buf[h0][i] = wvlt.line_buf[l0][i] - ((wvlt.line_buf[l1][i] + wvlt.line_buf[l2][i] + 2) >> 2);
}
} else {
self.idwt_53_horizontal(tile, l0, 2, wvlt);
for i in 0..wvlt.width {
wvlt.line_buf[h0][i] = wvlt.line_buf[l0][i] - ((wvlt.line_buf[l2][i] + 1) >> 1);
}
self.idwt_53_filter_decode(tile, plane, params, iwt_transforms, cur_level)?;
self.idwt_53_filter_transform(tile, plane, params, iwt_transforms, cur_level)?;
}
} else {
// This is unused in real world
wvlt.band1_buf = self.decode_line_with_iquantization(&plane.subbands[cur_band + 1], &mut params[cur_band + 1], q_step_level)?;
let mut h0_pos = 0;
// process H band
if wvlt.width <= 1 {
wvlt.line_buf[h0][0] = wvlt.band0(0);
} else {
if tile.tiles_left {
wvlt.line_buf[h0][h0_pos] = wvlt.band0(0) - ((wvlt.band1(0) + wvlt.band1(1) + 2) >> 2);
wvlt.band1_pos += 1;
} else {
wvlt.line_buf[h0][h0_pos] = wvlt.band0(0) - ((wvlt.band1(0) + 1) >> 1);
}
wvlt.band0_pos += 1;
for _i in (0..(wvlt.width - 3)).step_by(2) {
let delta = wvlt.band0(0) - ((wvlt.band1(0) + wvlt.band1(1) + 2) >> 2);
wvlt.line_buf[h0][h0_pos + 1] = wvlt.band1(0) + ((wvlt.line_buf[h0][h0_pos + 0] + delta) >> 1);
wvlt.line_buf[h0][h0_pos + 2] = delta;
wvlt.band0_pos += 1;
wvlt.band1_pos += 1;
h0_pos += 2;
}
if tile.tiles_right {
// untested
let delta = wvlt.band0(0) - ((wvlt.band1(0) + wvlt.band1(1) + 2) >> 2);
wvlt.line_buf[h0][h0_pos + 1] = wvlt.band1(0) + ((wvlt.line_buf[h0][h0_pos + 0] + delta) >> 1);
wvlt.line_buf[h0][h0_pos + 2] = delta;
} else if wvlt.width & 1 == 1 {
let delta = wvlt.band0(0) - ((wvlt.band1(0) + 1) >> 1);
wvlt.line_buf[h0][h0_pos + 1] = wvlt.band1(0) + ((wvlt.line_buf[h0][h0_pos + 0] + delta) >> 1);
wvlt.line_buf[h0][h0_pos + 2] = delta;
} else {
wvlt.line_buf[h0][h0_pos + 1] = wvlt.band1(0) + wvlt.line_buf[h0][h0_pos + 0];
}
}
wvlt.cur_line += 1;
wvlt.cur_h += 1;
wvlt.flt_tap_h = (wvlt.flt_tap_h + 1) % 5;
}
cur_band += 3;
}
Ok(())
}
pub(super) fn idwt_53_filter_transform(
&self,
tile: &Tile,
plane: &Plane,
params: &mut Vec<BandParam>,
iwt_transforms: &mut Vec<WaveletTransform>,
level: usize,
) -> Result<()> {
if iwt_transforms[level].cur_h > 0 {
return Ok(());
}
if iwt_transforms[level].cur_line >= iwt_transforms[level].height - 3 {
if !tile.tiles_bottom {
if iwt_transforms[level].height & 1 == 1 {
if level > 0 {
if iwt_transforms[level - 1].cur_h == 0 {
self.idwt_53_filter_transform(tile, plane, params, iwt_transforms, level - 1)?;
}
iwt_transforms[level].band0_buf = iwt_transforms[level - 1].getline().clone();
}
let wvlt = &mut iwt_transforms[level];
wvlt.reset_bufs();
let h0 = wvlt.flt_tap_h + 3;
let h1 = (wvlt.flt_tap_h + 1) % 5 + 3;
let h2 = (wvlt.flt_tap_h + 2) % 5 + 3;
let l0 = 0;
let l1 = 1;
let mut l0_pos = 0;
//let mut l1_pos = 0;
// process L bands
if wvlt.width <= 1 {
wvlt.line_buf[l0][0] = wvlt.band0(0);
} else {
if tile.tiles_left {
// untested
wvlt.line_buf[l0][l0_pos] = wvlt.band0(0) - ((wvlt.band1(0) + wvlt.band1(1) + 2) >> 2);
wvlt.band1_pos += 1;
} else {
wvlt.line_buf[l0][l0_pos] = wvlt.band0(0) - ((wvlt.band1(0) + 1) >> 1);
}
wvlt.band0_pos += 1;
for _i in (0..(wvlt.width - 3)).step_by(2) {
let delta = wvlt.band0(0) - ((wvlt.band1(0) + wvlt.band1(1) + 2) >> 2);
wvlt.line_buf[l0][l0_pos + 1] = wvlt.band1(0) + ((wvlt.line_buf[l0][l0_pos + 0] + delta) >> 1);
wvlt.line_buf[l0][l0_pos + 2] = delta;
wvlt.band0_pos += 1;
wvlt.band1_pos += 1;
l0_pos += 2;
}
if tile.tiles_right {
// untested
let delta = wvlt.band0(0) - ((wvlt.band1(0) + wvlt.band1(1) + 2) >> 2);
wvlt.line_buf[l0][l0_pos + 1] = wvlt.band1(0) + ((wvlt.line_buf[l0][l0_pos + 0] + delta) >> 1);
if wvlt.width & 1 == 1 {
wvlt.line_buf[l0][l0_pos + 2] = delta;
}
} else if wvlt.width & 1 == 1 {
let delta = wvlt.band0(0) - ((wvlt.band1(0) + 1) >> 1);
wvlt.line_buf[l0][l0_pos + 1] = wvlt.band1(0) + ((wvlt.line_buf[l0][l0_pos + 0] + delta) >> 1);
wvlt.line_buf[l0][l0_pos + 2] = delta;
} else {
wvlt.line_buf[l0][l0_pos + 1] = wvlt.band1(0) + wvlt.line_buf[l0][l0_pos + 0];
}
}
// process H bands
//wvlt.reset_bufs();
wvlt.line_buf.swap(1, 2);
for i in 0..wvlt.width {
let delta = wvlt.line_buf[l0][i] - ((wvlt.line_buf[l1][i] + 1) >> 1);
wvlt.line_buf[h1][i] = wvlt.line_buf[l1][i] + ((delta + wvlt.line_buf[h0][i]) >> 1);
wvlt.line_buf[h2][i] = delta;
}
wvlt.cur_h += 3;
wvlt.cur_line += 3;
wvlt.flt_tap_h = (wvlt.flt_tap_h + 3) % 5;
} else {
let wvlt = &mut iwt_transforms[level];
let l2 = 2;
let h0 = wvlt.flt_tap_h + 3;
let h1 = (wvlt.flt_tap_h + 1) % 5 + 3;
for i in 0..wvlt.width {
wvlt.line_buf[h1][i] = wvlt.line_buf[h0][i] + wvlt.line_buf[l2][i];
}
// The original libraw CRX decoder copies the pointer from line_buf[2] to [1].
// But it doesn't makes sense, so we swap the buffers as we do on other locations.
wvlt.line_buf.swap(1, 2);
//wvlt.line_buf[1] = wvlt.line_buf[2].clone();
wvlt.cur_h += 2;
wvlt.cur_line += 2;
wvlt.flt_tap_h = (wvlt.flt_tap_h + 2) % 5;
}
} // end if !tile.tiles_bottom
} else {
if level > 0 {
if iwt_transforms[level - 1].cur_h == 0 {
self.idwt_53_filter_transform(tile, plane, params, iwt_transforms, level - 1)?;
}
iwt_transforms[level].band0_buf = iwt_transforms[level - 1].getline().clone();
}
let wvlt = &mut iwt_transforms[level];
wvlt.reset_bufs();
let l0 = 0;
let l1 = 1;
//let l2 = 2;
let mut l0_pos = 0;
let mut l1_pos = 0;
//let mut l2_pos = 0;
let h0 = wvlt.flt_tap_h + 3;
let h1 = (wvlt.flt_tap_h + 1) % 5 + 3;
let h2 = (wvlt.flt_tap_h + 2) % 5 + 3;
// process L bands
if wvlt.width <= 1 {
wvlt.line_buf[l0][0] = wvlt.band0(0);
wvlt.line_buf[l1][0] = wvlt.band2(0);
} else {
// untested
if tile.tiles_left {
wvlt.line_buf[l0][0] = wvlt.band0(0) - ((wvlt.band1(0) + wvlt.band1(1) + 2) >> 2);
wvlt.line_buf[l1][0] = wvlt.band2(0) - ((wvlt.band3(0) + wvlt.band3(1) + 2) >> 2);
wvlt.band1_pos += 1;
wvlt.band3_pos += 1;
} else {
wvlt.line_buf[l0][0] = wvlt.band0(0) - ((wvlt.band1(0) + 1) >> 1);
wvlt.line_buf[l1][0] = wvlt.band2(0) - ((wvlt.band3(0) + 1) >> 1);
}
wvlt.band0_pos += 1;
wvlt.band2_pos += 1;
for _i in (0..(wvlt.width - 3)).step_by(2) {
let delta = wvlt.band0(0) - ((wvlt.band1(0) + wvlt.band1(1) + 2) >> 2);
wvlt.line_buf[l0][l0_pos + 1] = wvlt.band1(0) + ((delta + wvlt.line_buf[l0][l0_pos + 0]) >> 1);
wvlt.line_buf[l0][l0_pos + 2] = delta;
let delta = wvlt.band2(0) - ((wvlt.band3(0) + wvlt.band3(1) + 2) >> 2);
wvlt.line_buf[l1][l1_pos + 1] = wvlt.band3(0) + ((delta + wvlt.line_buf[l1][l1_pos + 0]) >> 1);
wvlt.line_buf[l1][l1_pos + 2] = delta;
wvlt.advance_bufs(1);
l0_pos += 2;
l1_pos += 2;
}
if tile.tiles_right {
// untested
let delta_a = wvlt.band0(0) - ((wvlt.band1(0) + wvlt.band1(1) + 2) >> 2);
wvlt.line_buf[l0][l0_pos + 1] = wvlt.band1(0) + ((delta_a + wvlt.line_buf[l0][l0_pos + 0]) >> 1);
let delta_b = wvlt.band2(0) - ((wvlt.band3(0) + wvlt.band3(1) + 2) >> 2);
wvlt.line_buf[l1][l1_pos + 1] = wvlt.band3(0) + ((delta_b + wvlt.line_buf[l1][l1_pos + 0]) >> 1);
if wvlt.width & 1 == 1 {
wvlt.line_buf[l0][l0_pos + 2] = delta_a;
wvlt.line_buf[l1][l1_pos + 2] = delta_b;
}
} else if wvlt.width & 1 == 1 {
let delta = wvlt.band0(0) - ((wvlt.band1(0) + 1) >> 1);
wvlt.line_buf[l0][l0_pos + 1] = wvlt.band1(0) + ((delta + wvlt.line_buf[l0][l0_pos + 0]) >> 1);
wvlt.line_buf[l0][l0_pos + 2] = delta;
let delta = wvlt.band2(0) - ((wvlt.band3(0) + 1) >> 1);
wvlt.line_buf[l1][l1_pos + 1] = wvlt.band3(0) + ((delta + wvlt.line_buf[l1][l1_pos + 0]) >> 1);
wvlt.line_buf[l1][l1_pos + 2] = delta;
} else {
wvlt.line_buf[l0][l0_pos + 1] = wvlt.line_buf[l0][l0_pos] + wvlt.band1(0);
wvlt.line_buf[l1][l1_pos + 1] = wvlt.line_buf[l1][l1_pos] + wvlt.band3(0);
}
}
// process H bands
let wvlt = &mut iwt_transforms[level];
wvlt.line_buf.swap(1, 2);
let l0 = 0;
let l1 = 1;
let l2 = 2;
for i in 0..wvlt.width {
let delta = wvlt.line_buf[l0][i] - ((wvlt.line_buf[l2][i] + wvlt.line_buf[l1][i] + 2) >> 2);
wvlt.line_buf[h1][i] = wvlt.line_buf[l1][i] + ((delta + wvlt.line_buf[h0][i]) >> 1);
wvlt.line_buf[h2][i] = delta;
}
if iwt_transforms[level].cur_line >= iwt_transforms[level].height - 3 && iwt_transforms[level].height & 1 == 1 {
iwt_transforms[level].cur_h += 3;
iwt_transforms[level].cur_line += 3;
iwt_transforms[level].flt_tap_h = (iwt_transforms[level].flt_tap_h + 3) % 5;
} else {
iwt_transforms[level].cur_h += 2;
iwt_transforms[level].cur_line += 2;
iwt_transforms[level].flt_tap_h = (iwt_transforms[level].flt_tap_h + 2) % 5;
}
}
Ok(())
}
}