use crate::{
chunk::{ColorType, ImageData, ImageEnd, ImageHeader},
consts,
encode::{filter, Error as EncoderError, Result},
encoder::Enc,
Rgba,
};
#[derive(Debug)]
pub(crate) struct StepEnc {
pub(crate) encoder: Enc,
#[allow(dead_code)]
coldepth: Option<(ColorType, u32)>,
#[allow(dead_code)]
header: Option<ImageHeader>,
}
impl StepEnc {
pub(crate) fn new(encoder: Enc) -> Self {
Self {
encoder,
coldepth: None,
header: None,
}
}
pub(crate) fn encode(
&mut self,
pixels: &[u8],
width: u32,
height: u32,
palette: &[Rgba],
) -> Result<()> {
let image_header = ImageHeader {
width,
height,
color_type: ColorType::Palette,
bit_depth: 8,
interlace: false,
};
encode(&mut self.encoder, pixels, &image_header, palette)
}
}
pub(super) fn encode(
enc: &mut Enc,
image: &[u8],
header: &ImageHeader,
palette: &[Rgba],
) -> Result<()> {
enc.raw(&consts::PNG_SIGNATURE);
if header.color_type == ColorType::Palette
&& (palette.is_empty() || palette.len() > 256)
{
eprintln!("{}", palette.len());
return Err(EncoderError::BadPalette);
}
let data = pre_process_scanlines(image, header);
header.write(enc);
if header.color_type == ColorType::Palette {
enc.prepare(palette.len() * 3, consts::PALETTE);
for p in palette.iter() {
enc.u8(p.r);
enc.u8(p.g);
enc.u8(p.b);
}
enc.write_crc();
}
if header.color_type == ColorType::Palette {
enc.prepare(palette.len(), consts::TRANSPARENCY);
for alpha in palette.iter() {
enc.u8(alpha.a);
}
enc.write_crc();
}
ImageData::with_data(data).write(enc)?;
ImageEnd.write(enc);
Ok(())
}
fn pre_process_scanlines(inp: &[u8], header: &ImageHeader) -> Vec<u8> {
let width = header.width;
let height = header.height;
let bit_depth = header.bit_depth;
let color_type = header.color_type;
let h = height as usize;
let w = width as usize;
let bpp = color_type.bpp(bit_depth);
let bpp = bpp as usize;
let outsize = h + (h * ((w * bpp + 7) / 8));
let mut out = vec![0u8; outsize];
filter::filter(&mut out, inp, w, h, header);
out
}