use std::io::Cursor;
use std::sync::Arc;
use crate::bitstream::BitStream;
use crate::components::{ComponentID, SubSampRatios};
use crate::decoder::MAX_COMPONENTS;
use crate::errors::DecodeErrors;
use crate::errors::DecodeErrors::Format;
use crate::headers::{parse_huffman, parse_sos};
use crate::marker::Marker;
use crate::misc::read_byte;
use crate::worker::post_process;
use crate::{ColorSpace, Decoder};
impl Decoder
{
#[rustfmt::skip]
pub(crate) fn decode_mcu_ycbcr_progressive(
&mut self, reader: &mut Cursor<Vec<u8>>,
) -> Result<Vec<u8>, DecodeErrors>
{
self.check_component_dimensions()?;
let mcu_height;
let mut block = [vec![], vec![], vec![]];
let mut mcu_width;
let mut seen_scans = 1;
if self.interleaved
{
mcu_width = self.mcu_x;
mcu_height = self.mcu_y;
} else {
mcu_width = (self.info.width as usize + 7) / 8;
mcu_height = (self.info.height as usize + 7) / 8;
}
mcu_width *= 64;
for i in 0..self.input_colorspace.num_components()
{
let comp = &self.components[i];
let len = mcu_width * comp.vertical_sample * comp.horizontal_sample * mcu_height;
block[i] = vec![0; len];
}
let mut stream = BitStream::new_progressive(self.succ_high, self.succ_low,
self.spec_start, self.spec_end);
self.parse_entropy_coded_data(reader, &mut stream, &mut block)?;
let mut marker = stream.marker.take().ok_or(DecodeErrors::FormatStatic("Marker missing where expected"))?;
'eoi: while marker != Marker::EOI
{
match marker
{
Marker::DHT => {
parse_huffman(self, reader)?;
}
Marker::SOS =>
{
parse_sos(reader, self)?;
stream.update_progressive_params(self.succ_high, self.succ_low,
self.spec_start, self.spec_end);
self.parse_entropy_coded_data(reader, &mut stream, &mut block)?;
marker = get_marker(reader, &mut stream).ok_or(DecodeErrors::FormatStatic("Marker missing where expected"))?;
seen_scans+=1;
if seen_scans > self.options.get_max_scans(){
return Err(DecodeErrors::Format(format!("Too many scans, exceeded limit of {}", self.options.get_max_scans())))
}
stream.reset();
continue 'eoi;
}
_ =>
{
break 'eoi;
}
}
marker = get_marker(reader, &mut stream).ok_or(DecodeErrors::FormatStatic("Marker missing where expected"))?;
}
self.finish_progressive_decoding(&block, mcu_width)
}
#[rustfmt::skip]
fn finish_progressive_decoding(&mut self, block: &[Vec<i16>; 3], mcu_width: usize) -> Result<Vec<u8>, DecodeErrors> {
self.set_upsampling()?;
let mut mcu_width = mcu_width;
let mut bias = 1;
if self.sub_sample_ratio == SubSampRatios::H
{
mcu_width *= 2;
}
if self.sub_sample_ratio == SubSampRatios::HV {
bias = 2;
}
if self.input_colorspace == ColorSpace::GRAYSCALE && self.interleaved {
if self.options.get_strict_mode(){
return Err(DecodeErrors::FormatStatic("[strict-mode]: Grayscale image with down-sampled component."))
}
warn!("Grayscale image with down-sampled component, resetting component details");
self.h_max = 1;
self.v_max = 1;
self.sub_sample_ratio = SubSampRatios::None;
self.components[0].vertical_sample = 1;
self.components[0].width_stride = mcu_width * 8;
self.components[0].horizontal_sample = mcu_width;
bias = 1;
}
let y = &block[0];
let cb = &block[1];
let cr = &block[2];
let extra_space = usize::from(self.interleaved) * 128 * usize::from(self.height()) * self.options.get_out_colorspace().num_components();
let capacity = usize::from(self.info.width + 8) * usize::from(self.info.height + 8);
let mut out_vector = vec![0_u8; capacity * self.options.get_out_colorspace().num_components() + extra_space];
let h_max = self.h_max;
let v_max = self.v_max;
let components = Arc::new(self.components.clone());
let input = self.input_colorspace;
let output = self.options.get_out_colorspace();
let idct_func = self.idct_func;
let color_convert_16 = self.color_convert_16;
let width = usize::from(self.width());
let chunks_size = width * self.options.get_out_colorspace().num_components() * 8 * h_max * v_max;
let out_chunks = out_vector.chunks_exact_mut(chunks_size);
let y_chunk_size =
mcu_width * self.components[0].vertical_sample * self.components[0].horizontal_sample * bias;
let y_chunk = y.chunks_exact(y_chunk_size);
let mut pool = scoped_threadpool::Pool::new(self.options.get_threads());
if self.input_colorspace.num_components() == 3 {
let cb_chunk_size =
mcu_width * self.components[1].vertical_sample * self.components[1].horizontal_sample * bias;
let cb_chunk = cb.chunks_exact(cb_chunk_size);
let cr_chunk = cr.chunks_exact(cb_chunk_size);
pool.scoped(|scope| {
for (((y, cb), cr), out) in y_chunk
.zip(cb_chunk)
.zip(cr_chunk)
.zip(out_chunks)
{
let component = components.clone();
scope.execute(move || {
post_process(&[y, cb, cr], &component, idct_func, color_convert_16,
input, output, out, width,
);
});
}
});
} else {
pool.scoped(|scope| {
for (y, out) in y_chunk.zip(out_chunks)
{
let component = components.clone();
scope.execute(move || {
post_process(&[y, &[], &[]], &component, idct_func, color_convert_16,
input, output, out, width,
);
});
}
});
}
debug!("Finished decoding image");
out_vector.truncate(
usize::from(self.width())
* usize::from(self.height())
* self.options.get_out_colorspace().num_components(),
);
return Ok(out_vector);
}
#[rustfmt::skip]
#[allow(clippy::too_many_lines)]
fn parse_entropy_coded_data(
&mut self, reader: &mut Cursor<Vec<u8>>, stream: &mut BitStream, buffer: &mut [Vec<i16>; 3],
) -> Result<bool, DecodeErrors>
{
self.check_component_dimensions()?;
stream.reset();
self.components.iter_mut().for_each(|x| x.dc_pred = 0);
if usize::from(self.num_scans) > self.input_colorspace.num_components() {
return Err(Format(format!("Number of scans {} cannot be greater than number of components, {}", self.num_scans, self.input_colorspace.num_components())));
}
if self.num_scans == 1
{
if self.spec_end != 0 && self.spec_start == 0
{
return Err(DecodeErrors::HuffmanDecode(
"Can't merge DC and AC corrupt jpeg".to_string(),
));
}
let k = self.z_order[0];
if k >= self.components.len() {
return Err(DecodeErrors::Format(format!("Cannot find component {}, corrupt image", k)));
}
let (mcu_width, mcu_height);
if self.components[k].component_id == ComponentID::Y || !self.interleaved
{
mcu_width = ((self.info.width + 7) / 8) as usize;
mcu_height = ((self.info.height + 7) / 8) as usize;
} else {
mcu_width = self.mcu_x;
mcu_height = self.mcu_y;
}
let mut i = 0;
let mut j = 0;
while i < mcu_height
{
while j < mcu_width
{
let start = 64 * (j + i * (self.components[k].width_stride / 8));
if i >= mcu_height {
break;
}
let data: &mut [i16; 64] = buffer.get_mut(k)
.unwrap().get_mut(start..start + 64)
.unwrap().try_into().unwrap();
if self.spec_start == 0
{
let pos = self.components[k].dc_huff_table & (MAX_COMPONENTS - 1);
let dc_table = self.dc_huffman_tables.get(pos)
.ok_or_else(|| DecodeErrors::Format(format!("No huffman table for component:{}", pos)))?
.as_ref()
.ok_or_else(|| DecodeErrors::Format(format!("Huffman table at index {} not initialized", pos)))?;
let dc_pred = &mut self.components[k].dc_pred;
if self.succ_high == 0
{
stream.decode_prog_dc_first(reader, dc_table, &mut data[0], dc_pred)?;
} else {
stream.decode_prog_dc_refine(reader, &mut data[0])?;
}
} else {
let pos = self.components[k].ac_huff_table;
let ac_table = self.ac_huffman_tables.get(pos)
.ok_or_else(|| DecodeErrors::Format(format!("No huffman table for component:{}", pos)))?
.as_ref()
.ok_or_else(|| DecodeErrors::Format(format!("Huffman table at index {} not initialized", pos)))?;
if self.succ_high == 0
{
if stream.eob_run > 0
{
i += (j + stream.eob_run as usize - 1) / mcu_width;
j = (j + stream.eob_run as usize - 1) % mcu_width;
stream.eob_run = 0;
} else {
stream.decode_mcu_ac_first(reader, ac_table, data)?;
}
} else {
stream.decode_mcu_ac_refine(reader, ac_table, data)?;
}
}
j += 1;
self.todo -= 1;
if self.todo == 0
{
self.handle_rst(stream)?;
}
}
j = 0;
i += 1;
}
} else {
if self.spec_end != 0
{
return Err(DecodeErrors::HuffmanDecode(
"Can't merge dc and AC corrupt jpeg".to_string(),
));
}
for i in 0..self.mcu_y
{
for j in 0..self.mcu_x
{
for k in 0..self.num_scans
{
let n = self.z_order[k as usize];
if n >= self.components.len() {
return Err(DecodeErrors::Format(format!("Cannot find component {}, corrupt image", n)));
}
let component = &mut self.components[n];
let huff_table = self.dc_huffman_tables.get(component.dc_huff_table)
.ok_or_else(|| DecodeErrors::Format(format!("No huffman table for component:{}", component.dc_huff_table)))?
.as_ref()
.ok_or_else(|| DecodeErrors::Format(format!("Huffman table at index {} not initialized", component.dc_huff_table)))?;
for v_samp in 0..component.vertical_sample
{
for h_samp in 0..component.horizontal_sample
{
let x2 = j * component.horizontal_sample + h_samp;
let y2 = i * component.vertical_sample + v_samp;
let position = 64 * (x2 + y2 * component.width_stride / 8);
let data = &mut buffer[n as usize][position];
if self.succ_high == 0
{
stream.decode_prog_dc_first(reader, huff_table, data, &mut component.dc_pred)?;
} else {
stream.decode_prog_dc_refine(reader, data)?;
}
}
}
self.todo = self.todo.wrapping_sub(1);
if self.todo == 0 {
self.handle_rst(stream)?;
}
}
}
}
}
return Ok(true);
}
}
fn get_marker(reader: &mut Cursor<Vec<u8>>, stream: &mut BitStream) -> Option<Marker>
{
if let Some(marker) = stream.marker
{
stream.marker = None;
return Some(marker);
}
let len = u64::try_from(reader.get_ref().len()).unwrap();
loop
{
let marker = read_byte(reader).ok()?;
if marker == 255
{
let mut r = read_byte(reader).ok()?;
while r == 0xFF
{
r = read_byte(reader).ok()?;
}
if r != 0
{
return Marker::from_u8(r)
.ok_or_else(|| DecodeErrors::Format(format!("Unknown marker 0xFF{:X}", r)))
.ok();
}
if reader.position() >= len
{
return None;
}
}
}
}