use crate::consts::{ALIGNED_BLOCK_INDEX_DC_INDEX, RASTER_TO_ALIGNED, ZIGZAG_TO_ALIGNED};
use super::{block_context::BlockContext, jpeg_header::JPegHeader};
pub struct BlockBasedImage {
block_width: i32,
original_height: i32,
dpos_offset: i32,
image: Vec<ExpandedBlockData>,
}
static EMPTY: ExpandedBlockData = ExpandedBlockData { raw_data: [0; 64] };
impl BlockBasedImage {
pub fn new(
jpeg_header: &JPegHeader,
component: usize,
luma_y_start: i32,
luma_y_end: i32,
) -> Self {
let block_width = jpeg_header.cmp_info[component].bch;
let original_height = jpeg_header.cmp_info[component].bcv;
let max_size = block_width * original_height;
return BlockBasedImage {
block_width: block_width,
original_height: original_height,
image: Vec::with_capacity(
(max_size * (luma_y_end - luma_y_start) / jpeg_header.cmp_info[0].bcv) as usize,
),
dpos_offset: max_size * luma_y_start / jpeg_header.cmp_info[0].bcv,
};
}
pub fn merge(images: &mut Vec<Vec<BlockBasedImage>>, index: usize) -> Self {
let total_size = images.iter().map(|x| x[index].image.len()).sum();
let mut contents = Vec::with_capacity(total_size);
let mut block_width = None;
let mut original_height = None;
for v in images {
assert!(
v[index].dpos_offset == contents.len() as i32,
"previous content should match new content"
);
if let Some(w) = block_width {
assert_eq!(w, v[index].block_width, "all block_width must match")
} else {
block_width = Some(v[index].block_width);
}
if let Some(w) = original_height {
assert_eq!(
w, v[index].original_height,
"all original_height must match"
)
} else {
original_height = Some(v[index].original_height);
}
contents.append(&mut v[index].image);
}
return BlockBasedImage {
block_width: block_width.unwrap(),
original_height: original_height.unwrap(),
image: contents,
dpos_offset: 0,
};
}
#[allow(dead_code)]
pub fn dump(&self) {
println!(
"size = {0}, capacity = {1}, dpos_offset = {2}",
self.image.len(),
self.image.capacity(),
self.dpos_offset
);
}
pub fn off_y(&self, y: i32) -> BlockContext {
return BlockContext::new(
self.block_width * y,
if y != 0 {
self.block_width * (y - 1)
} else {
-1
},
if (y & 1) != 0 { self.block_width } else { 0 },
if (y & 1) != 0 { 0 } else { self.block_width },
self,
);
}
pub fn get_block_width(&self) -> i32 {
self.block_width
}
pub fn get_original_height(&self) -> i32 {
self.original_height
}
fn fill_up_to_dpos(&mut self, dpos: i32) {
if self.image.len() == 0 {
assert!(self.dpos_offset == dpos);
}
assert!(dpos >= self.dpos_offset);
while self.image.len() <= (dpos - self.dpos_offset) as usize {
if self.image.len() >= self.image.capacity() {
panic!("out of memory");
}
self.image.push(ExpandedBlockData { raw_data: [0; 64] });
}
}
pub fn set_block_data(&mut self, dpos: i32, block_data: &[i16; 64]) {
self.fill_up_to_dpos(dpos);
self.image[(dpos - self.dpos_offset) as usize] = ExpandedBlockData {
raw_data: *block_data,
};
}
pub fn get_block(&self, dpos: i32) -> &ExpandedBlockData {
if (dpos - self.dpos_offset) as usize >= self.image.len() {
return &EMPTY;
} else {
return &self.image[(dpos - self.dpos_offset) as usize];
}
}
pub fn get_block_mut(&mut self, dpos: i32) -> &mut ExpandedBlockData {
self.fill_up_to_dpos(dpos);
return &mut self.image[(dpos - self.dpos_offset) as usize];
}
}
pub struct ExpandedBlockData {
raw_data: [i16; 64],
}
impl ExpandedBlockData {
pub fn get_dc(&self) -> i16 {
return self.raw_data[ALIGNED_BLOCK_INDEX_DC_INDEX];
}
pub fn set_dc(&mut self, value: i16) {
self.raw_data[ALIGNED_BLOCK_INDEX_DC_INDEX] = value
}
pub fn set_coefficient_zigzag_block(block_data: &mut [i16; 64], index: u8, value: i16) {
block_data[usize::from(crate::consts::ZIGZAG_TO_ALIGNED[usize::from(index)])] = value;
}
#[allow(dead_code)]
pub fn get_hash(&self) -> i32 {
let mut sum = 0;
for i in 0..64 {
sum += self.raw_data[i] as i32
}
return sum;
}
pub fn get_count_of_non_zeros_7x7(&self) -> u8 {
let mut num_non_zeros7x7: u8 = 0;
for index in 0..49 {
if self.raw_data[index] != 0 {
num_non_zeros7x7 += 1;
}
}
return num_non_zeros7x7;
}
pub fn get_coefficient(&self, index: usize) -> i16 {
return self.raw_data[index];
}
pub fn set_coefficient(&mut self, index: usize, v: i16) {
self.raw_data[index] = v;
}
pub fn set_coefficient_zigzag(&mut self, index: usize, v: i16) {
self.raw_data[usize::from(ZIGZAG_TO_ALIGNED[index])] = v;
}
pub fn get_coefficient_raster(&self, index: usize) -> i16 {
return self.raw_data[usize::from(RASTER_TO_ALIGNED[index])];
}
pub fn get_coefficient_zigzag(&self, index: usize) -> i16 {
return self.raw_data[usize::from(ZIGZAG_TO_ALIGNED[index])];
}
}