extern crate alloc;
use alloc::borrow::Cow;
use super::byte_encoders::{BytesEncoder, Pixel, RgbEncoder, YCbCrPlanarEncoder};
use super::encoder_config::EncoderConfig;
use super::encoder_types::PixelLayout;
use super::exif::Exif;
use super::extras::EncoderSegments;
use crate::error::Result;
use crate::types::Limits;
use enough::Stop;
pub struct EncodeRequest<'a> {
config: &'a EncoderConfig,
icc_profile: Option<Cow<'a, [u8]>>,
exif: Option<Exif>,
xmp: Option<Cow<'a, [u8]>>,
segments: Option<EncoderSegments>,
stop: Option<&'a dyn Stop>,
limits: Option<Limits>,
}
impl<'a> EncodeRequest<'a> {
pub(crate) fn new(config: &'a EncoderConfig) -> Self {
Self {
config,
icc_profile: None,
exif: None,
xmp: None,
segments: None,
stop: None,
limits: None,
}
}
#[must_use]
pub fn icc_profile(mut self, data: &'a [u8]) -> Self {
self.icc_profile = Some(Cow::Borrowed(data));
self
}
#[must_use]
pub fn icc_profile_owned(mut self, data: alloc::vec::Vec<u8>) -> Self {
self.icc_profile = Some(Cow::Owned(data));
self
}
#[must_use]
pub fn exif(mut self, exif: impl Into<Exif>) -> Self {
self.exif = Some(exif.into());
self
}
#[must_use]
pub fn xmp(mut self, data: &'a [u8]) -> Self {
self.xmp = Some(Cow::Borrowed(data));
self
}
#[must_use]
pub fn xmp_owned(mut self, data: alloc::vec::Vec<u8>) -> Self {
self.xmp = Some(Cow::Owned(data));
self
}
#[must_use]
pub fn segments(mut self, segments: EncoderSegments) -> Self {
self.segments = Some(segments);
self
}
#[must_use]
pub fn stop(mut self, stop: &'a dyn Stop) -> Self {
self.stop = Some(stop);
self
}
#[must_use]
pub fn limits(mut self, limits: Limits) -> Self {
self.limits = Some(limits);
self
}
pub fn encode_from_bytes(
self,
width: u32,
height: u32,
layout: PixelLayout,
) -> Result<BytesEncoder> {
let (config, icc, exif, xmp, _segments) = self.extract_metadata();
BytesEncoder::new(config, width, height, layout, icc, exif, xmp)
}
pub fn encode_from_rgb<P: Pixel>(self, width: u32, height: u32) -> Result<RgbEncoder<P>> {
let (config, icc, exif, xmp, _segments) = self.extract_metadata();
RgbEncoder::new(config, width, height, icc, exif, xmp)
}
pub fn encode_from_ycbcr_planar(self, width: u32, height: u32) -> Result<YCbCrPlanarEncoder> {
let (config, icc, exif, xmp, _segments) = self.extract_metadata();
YCbCrPlanarEncoder::new(config, width, height, icc, exif, xmp)
}
pub fn encode<P: Pixel>(
self,
pixels: &[P],
width: u32,
height: u32,
) -> Result<alloc::vec::Vec<u8>> {
let stop = self.stop.unwrap_or(&enough::Unstoppable);
let mut enc = self.encode_from_rgb::<P>(width, height)?;
enc.push_packed(pixels, stop)?;
enc.finish()
}
pub fn encode_into<P: Pixel>(
self,
pixels: &[P],
width: u32,
height: u32,
output: &mut alloc::vec::Vec<u8>,
) -> Result<()> {
let stop = self.stop.unwrap_or(&enough::Unstoppable);
let mut enc = self.encode_from_rgb::<P>(width, height)?;
enc.push_packed(pixels, stop)?;
enc.finish_into(output)
}
pub fn encode_bytes(
self,
data: &[u8],
width: u32,
height: u32,
layout: PixelLayout,
) -> Result<alloc::vec::Vec<u8>> {
let stop = self.stop.unwrap_or(&enough::Unstoppable);
let mut enc = self.encode_from_bytes(width, height, layout)?;
enc.push_packed(data, stop)?;
enc.finish()
}
pub fn encode_bytes_into(
self,
data: &[u8],
width: u32,
height: u32,
layout: PixelLayout,
output: &mut alloc::vec::Vec<u8>,
) -> Result<()> {
let stop = self.stop.unwrap_or(&enough::Unstoppable);
let mut enc = self.encode_from_bytes(width, height, layout)?;
enc.push_packed(data, stop)?;
enc.finish_into(output)
}
fn extract_metadata(
self,
) -> (
EncoderConfig,
Option<alloc::vec::Vec<u8>>,
Option<Exif>,
Option<alloc::vec::Vec<u8>>,
Option<EncoderSegments>,
) {
let config = self.config.clone();
let icc = self.icc_profile.map(|c| c.into_owned());
let exif = self.exif;
let xmp = self.xmp.map(|c| c.into_owned());
let segments = self.segments;
(config, icc, exif, xmp, segments)
}
}