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.
571 lines
21 KiB
Rust
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(())
|
|
}
|
|
}
|