use zune_core::bit_depth::{BitDepth, BitType};
use zune_core::bytestream::ZReaderTrait;
use zune_core::colorspace::{ColorSpace, ALL_COLORSPACES};
use zune_core::log::{trace, warn};
use zune_core::options::EncoderOptions;
use crate::codecs::ImageFormat;
use crate::core_filters::colorspace::ColorspaceConv;
use crate::core_filters::depth::Depth;
use crate::errors::{ImageErrors, ImageOperationsErrors};
use crate::image::Image;
use crate::metadata::AlphaState::NonPreMultiplied;
use crate::metadata::{AlphaState, ImageMetadata};
use crate::pipelines::EncodeResult;
pub trait DecoderTrait<T: ZReaderTrait> {
fn decode(&mut self) -> Result<Image, crate::errors::ImageErrors>;
fn dimensions(&self) -> Option<(usize, usize)>;
fn out_colorspace(&self) -> ColorSpace;
fn name(&self) -> &'static str;
fn is_experimental(&self) -> bool {
false
}
fn read_headers(&mut self) -> Result<Option<ImageMetadata>, crate::errors::ImageErrors> {
Ok(None)
}
}
pub trait OperationsTrait {
fn name(&self) -> &'static str;
fn execute_impl(&self, image: &mut Image) -> Result<(), ImageErrors>;
fn supported_colorspaces(&self) -> &'static [ColorSpace] {
&ALL_COLORSPACES
}
fn supported_types(&self) -> &'static [BitType];
fn execute(&self, image: &mut Image) -> Result<(), ImageErrors> {
let colorspace = image.colorspace();
let supported = self
.supported_colorspaces()
.iter()
.any(|x| *x == colorspace);
if !supported {
return Err(ImageErrors::UnsupportedColorspace(
colorspace,
self.name(),
self.supported_colorspaces()
));
}
let bit_type = image.metadata.get_depth().bit_type();
let supported = self.supported_types().iter().any(|x| *x == bit_type);
if !supported {
return Err(ImageErrors::OperationsError(
ImageOperationsErrors::UnsupportedType(self.name(), bit_type)
));
}
confirm_invariants(image)?;
self.execute_impl(image)
.map_err(<ImageErrors as Into<ImageErrors>>::into)?;
confirm_invariants(image)?;
Ok(())
}
fn alpha_state(&self) -> AlphaState {
AlphaState::PreMultiplied
}
fn clone_and_execute(&self, image: &Image) -> Result<Image, ImageErrors> {
let mut c_img = image.clone();
self.execute(&mut c_img)?;
Ok(c_img)
}
}
fn confirm_invariants(image: &Image) -> Result<(), ImageErrors> {
for frame in image.frames_ref() {
if frame.channels.len() != image.colorspace().num_components() {
{
return Err(ImageErrors::GenericString(format!(
"Components mismatch, expected {} channels since image format is {:?}, but found {}",
image.colorspace().num_components(),
image.colorspace(),
frame.channels.len()
)));
}
}
}
let (width, height) = image.dimensions();
let expected_length = image.depth().size_of() * width * height;
for channel in image.channels_ref(true) {
if channel.len() != expected_length {
return Err(ImageErrors::DimensionsMisMatch(
expected_length,
channel.len()
));
}
}
Ok(())
}
pub trait EncoderTrait {
fn name(&self) -> &'static str;
fn encode_inner(&mut self, image: &Image) -> Result<Vec<u8>, ImageErrors>;
fn supported_colorspaces(&self) -> &'static [ColorSpace];
fn encode(&mut self, image: &Image) -> Result<Vec<u8>, ImageErrors> {
confirm_invariants(image)?;
let colorspace = image.colorspace();
let supported_colorspaces = self.supported_colorspaces();
let depth = image.depth();
if image.is_animated() && !self.supports_animated_images() {
warn!("The current image is animated but the encoder ({:?}) doesn't support animated images, this will only encode the first frame",self.name());
}
if !supported_colorspaces.contains(&colorspace)
|| !self.supported_bit_depth().contains(&depth)
|| image.metadata.alpha != NonPreMultiplied
{
let mut image_clone = image.clone();
if !supported_colorspaces.contains(&colorspace) {
let default_colorspace = self.default_colorspace(colorspace);
let image_format = self.format();
trace!("Image is in {colorspace:?} colorspace,converting it to {default_colorspace:?} which is the default configured colorspace of {image_format:?}");
let converter = ColorspaceConv::new(default_colorspace);
converter.execute(&mut image_clone)?
}
let image_depth = image.depth();
if !self.supported_bit_depth().contains(&depth) {
trace!(
"Image depth is in {:?}, but {} encoder supports {:?}",
image.depth(),
self.name(),
self.supported_bit_depth()
);
trace!(
"Converting image to a depth of {:?}",
self.default_depth(image_depth)
);
let depth = Depth::new(self.default_depth(image_depth));
depth.execute(&mut image_clone)?;
}
confirm_invariants(&image_clone)?;
self.encode_inner(&image_clone)
} else {
self.encode_inner(image)
}
}
fn format(&self) -> ImageFormat;
fn encode_to_result(&mut self, image: &Image) -> Result<EncodeResult, ImageErrors> {
let data = self.encode(image)?;
Ok(EncodeResult {
data,
format: self.format()
})
}
fn supported_bit_depth(&self) -> &'static [BitDepth];
fn default_depth(&self, depth: BitDepth) -> BitDepth;
fn default_colorspace(&self, _: ColorSpace) -> ColorSpace {
ColorSpace::RGB
}
fn set_options(&mut self, _: EncoderOptions) {}
fn supports_animated_images(&self) -> bool {
false
}
}
pub trait ZuneInts<T> {
fn depth() -> BitDepth;
fn max_value() -> T;
}
impl ZuneInts<u8> for u8 {
#[inline(always)]
fn depth() -> BitDepth {
BitDepth::Eight
}
#[inline(always)]
fn max_value() -> u8 {
255
}
}
impl ZuneInts<u16> for u16 {
#[inline(always)]
fn depth() -> BitDepth {
BitDepth::Sixteen
}
#[inline(always)]
fn max_value() -> u16 {
u16::MAX
}
}
impl ZuneInts<f32> for f32 {
#[inline(always)]
fn depth() -> BitDepth {
BitDepth::Float32
}
#[inline(always)]
fn max_value() -> f32 {
1.0
}
}
pub trait DecodeInto {
fn decode_into(&mut self, buffer: &mut [u8]) -> Result<(), ImageErrors>;
fn output_buffer_size(&mut self) -> Result<usize, ImageErrors>;
}
pub trait IntoImage {
fn into_image(self) -> Result<Image, ImageErrors>;
}
impl IntoImage for Image {
fn into_image(self) -> Result<Image, ImageErrors> {
Ok(self)
}
}