use crate::{
Result,
block::{DisposalMethod, GraphicControl},
decode, encode,
};
use pix::{Palette, Raster, gray::Gray8, rgb::SRgba8};
use std::io::{Read, Write};
pub(crate) enum StepRaster {
TrueColor(Raster<SRgba8>),
Indexed(Raster<Gray8>, Palette),
}
#[derive(Clone)]
pub struct Step {
pub(crate) raster: StepRaster,
pub(crate) graphic_control_ext: Option<GraphicControl>,
}
pub struct Decoder<R: Read> {
reader: R,
max_image_sz: Option<usize>,
}
impl Clone for StepRaster {
fn clone(&self) -> Self {
match self {
StepRaster::TrueColor(r) => {
StepRaster::TrueColor(Raster::with_raster(r))
}
StepRaster::Indexed(r, p) => {
StepRaster::Indexed(Raster::with_raster(r), p.clone())
}
}
}
}
impl Step {
pub fn with_true_color(raster: Raster<SRgba8>) -> Self {
let raster = StepRaster::TrueColor(raster);
Step {
raster,
graphic_control_ext: None,
}
}
pub fn with_indexed(raster: Raster<Gray8>, palette: Palette) -> Self {
let raster = StepRaster::Indexed(raster, palette);
Step {
raster,
graphic_control_ext: None,
}
}
pub fn with_disposal_method(mut self, method: DisposalMethod) -> Self {
let mut control = self.graphic_control_ext.unwrap_or_default();
control.set_disposal_method(method);
if control != GraphicControl::default() {
self.graphic_control_ext = Some(control);
} else {
self.graphic_control_ext = None;
}
self
}
pub fn with_transparent_color(mut self, clr: Option<u8>) -> Self {
let mut control = self.graphic_control_ext.unwrap_or_default();
control.set_transparent_color(clr);
if control != GraphicControl::default() {
self.graphic_control_ext = Some(control);
} else {
self.graphic_control_ext = None;
}
self
}
pub fn transparent_color(&self) -> Option<u8> {
self.graphic_control_ext.and_then(|c| c.transparent_color())
}
pub fn with_delay_time_cs(mut self, delay: Option<u16>) -> Self {
let mut control = self.graphic_control_ext.unwrap_or_default();
control.set_delay_time_cs(delay.unwrap_or_default());
if control != GraphicControl::default() {
self.graphic_control_ext = Some(control);
} else {
self.graphic_control_ext = None;
}
self
}
pub fn raster(&self) -> &Raster<SRgba8> {
match &self.raster {
StepRaster::TrueColor(r) => r,
StepRaster::Indexed(_, _) => todo!("convert to true color"),
}
}
pub fn delay_time_cs(&self) -> Option<u16> {
self.graphic_control_ext.map(|c| c.delay_time_cs())
}
}
impl<R: Read> Decoder<R> {
pub fn new(reader: R) -> Self {
Decoder {
reader,
max_image_sz: Some(1 << 25),
}
}
pub fn max_image_sz(mut self, max_image_sz: Option<usize>) -> Self {
self.max_image_sz = max_image_sz;
self
}
pub fn into_blocks(self) -> decode::Blocks<R> {
decode::Blocks::new(self.reader, self.max_image_sz)
}
pub fn into_frames(self) -> decode::Frames<R> {
decode::Frames::new(self.into_blocks())
}
pub fn into_steps(self) -> decode::Steps<R> {
decode::Steps::new_once(self.into_frames())
}
}
impl<R: Read> IntoIterator for Decoder<R> {
type Item = Result<Step>;
type IntoIter = decode::Steps<R>;
fn into_iter(self) -> Self::IntoIter {
decode::Steps::new_looping(self.into_frames())
}
}
pub struct Encoder<W: Write> {
writer: W,
}
impl<W: Write> Encoder<W> {
pub fn new(writer: W) -> Self {
Encoder { writer }
}
pub fn into_block_enc(self) -> encode::BlockEnc<W> {
encode::BlockEnc::new(self.writer)
}
pub fn into_frame_enc(self) -> encode::FrameEnc<W> {
encode::FrameEnc::new(self.into_block_enc())
}
pub fn into_step_enc(self) -> encode::StepEnc<W> {
encode::StepEnc::new(self.into_frame_enc())
}
}