2023-07-13 03:12:21 +00:00
|
|
|
mod animation;
|
|
|
|
mod image;
|
|
|
|
pub(crate) mod mimes;
|
|
|
|
mod video;
|
2023-07-12 04:11:23 +00:00
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
use std::str::FromStr;
|
2023-07-12 04:11:23 +00:00
|
|
|
|
2023-07-13 22:42:21 +00:00
|
|
|
pub(crate) use animation::{AnimationFormat, AnimationOutput};
|
2023-07-13 03:12:21 +00:00
|
|
|
pub(crate) use image::{ImageFormat, ImageInput, ImageOutput};
|
2023-07-13 22:42:21 +00:00
|
|
|
pub(crate) use video::{InternalVideoFormat, OutputVideoFormat, VideoFormat, VideoCodec, AudioCodec};
|
2023-07-12 04:11:23 +00:00
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2023-07-13 22:42:21 +00:00
|
|
|
pub(crate) struct Validations<'a> {
|
|
|
|
pub(crate) image: &'a crate::config::Image,
|
|
|
|
pub(crate) animation: &'a crate::config::Animation,
|
|
|
|
pub(crate) video: &'a crate::config::Video,
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
|
2023-07-13 19:34:40 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
2023-07-13 03:12:21 +00:00
|
|
|
pub(crate) enum InputFile {
|
|
|
|
Image(ImageInput),
|
2023-07-13 22:42:21 +00:00
|
|
|
Animation(AnimationFormat),
|
2023-07-13 03:12:21 +00:00
|
|
|
Video(VideoFormat),
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
|
2023-07-13 19:34:40 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
2023-07-13 03:12:21 +00:00
|
|
|
pub(crate) enum InternalFormat {
|
|
|
|
Image(ImageFormat),
|
|
|
|
Animation(AnimationFormat),
|
|
|
|
Video(InternalVideoFormat),
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
|
|
|
|
pub(crate) enum ProcessableFormat {
|
|
|
|
Image(ImageFormat),
|
|
|
|
Animation(AnimationFormat),
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
#[derive(
|
|
|
|
Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
|
|
|
|
)]
|
|
|
|
pub(crate) enum InputProcessableFormat {
|
2023-07-12 04:11:23 +00:00
|
|
|
#[serde(rename = "apng")]
|
|
|
|
Apng,
|
|
|
|
#[serde(rename = "avif")]
|
|
|
|
Avif,
|
|
|
|
#[serde(rename = "gif")]
|
|
|
|
Gif,
|
2023-07-13 03:12:21 +00:00
|
|
|
#[serde(rename = "jpeg")]
|
|
|
|
Jpeg,
|
|
|
|
#[serde(rename = "jxl")]
|
|
|
|
Jxl,
|
|
|
|
#[serde(rename = "png")]
|
|
|
|
Png,
|
2023-07-12 04:11:23 +00:00
|
|
|
#[serde(rename = "webp")]
|
|
|
|
Webp,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InputFile {
|
2023-07-13 03:12:21 +00:00
|
|
|
pub(crate) const fn internal_format(&self) -> InternalFormat {
|
2023-07-12 04:11:23 +00:00
|
|
|
match self {
|
2023-07-13 03:12:21 +00:00
|
|
|
Self::Image(ImageInput { format, .. }) => InternalFormat::Image(*format),
|
2023-07-13 22:42:21 +00:00
|
|
|
Self::Animation(format) => InternalFormat::Animation(*format),
|
2023-07-13 03:12:21 +00:00
|
|
|
Self::Video(format) => InternalFormat::Video(format.internal_format()),
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
impl InternalFormat {
|
|
|
|
pub(crate) fn media_type(self) -> mime::Mime {
|
2023-07-12 04:11:23 +00:00
|
|
|
match self {
|
2023-07-13 03:12:21 +00:00
|
|
|
Self::Image(format) => format.media_type(),
|
|
|
|
Self::Animation(format) => format.media_type(),
|
|
|
|
Self::Video(format) => format.media_type(),
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-13 18:48:59 +00:00
|
|
|
pub(crate) fn maybe_from_media_type(mime: &mime::Mime, has_frames: bool) -> Option<Self> {
|
|
|
|
match (mime.type_(), mime.subtype().as_str(), has_frames) {
|
|
|
|
(mime::IMAGE, "apng", _) => Some(Self::Animation(AnimationFormat::Apng)),
|
|
|
|
(mime::IMAGE, "avif", true) => Some(Self::Animation(AnimationFormat::Avif)),
|
|
|
|
(mime::IMAGE, "avif", false) => Some(Self::Image(ImageFormat::Avif)),
|
|
|
|
(mime::IMAGE, "gif", _) => Some(Self::Animation(AnimationFormat::Gif)),
|
|
|
|
(mime::IMAGE, "jpeg", _) => Some(Self::Image(ImageFormat::Jpeg)),
|
|
|
|
(mime::IMAGE, "jxl", _) => Some(Self::Image(ImageFormat::Jxl)),
|
|
|
|
(mime::IMAGE, "png", _) => Some(Self::Image(ImageFormat::Png)),
|
|
|
|
(mime::IMAGE, "webp", true) => Some(Self::Animation(AnimationFormat::Webp)),
|
|
|
|
(mime::IMAGE, "webp", false) => Some(Self::Image(ImageFormat::Webp)),
|
|
|
|
(mime::VIDEO, "mp4", _) => Some(Self::Video(InternalVideoFormat::Mp4)),
|
|
|
|
(mime::VIDEO, "webm", _) => Some(Self::Video(InternalVideoFormat::Webm)),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
pub(crate) const fn file_extension(self) -> &'static str {
|
2023-07-12 04:11:23 +00:00
|
|
|
match self {
|
2023-07-13 03:12:21 +00:00
|
|
|
Self::Image(format) => format.file_extension(),
|
|
|
|
Self::Animation(format) => format.file_extension(),
|
|
|
|
Self::Video(format) => format.file_extension(),
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
pub(crate) const fn processable_format(self) -> Option<ProcessableFormat> {
|
2023-07-12 04:11:23 +00:00
|
|
|
match self {
|
2023-07-13 03:12:21 +00:00
|
|
|
Self::Image(format) => Some(ProcessableFormat::Image(format)),
|
|
|
|
Self::Animation(format) => Some(ProcessableFormat::Animation(format)),
|
|
|
|
Self::Video(_) => None,
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
impl ProcessableFormat {
|
|
|
|
pub(crate) const fn file_extension(self) -> &'static str {
|
2023-07-12 04:11:23 +00:00
|
|
|
match self {
|
2023-07-13 03:12:21 +00:00
|
|
|
Self::Image(format) => format.file_extension(),
|
|
|
|
Self::Animation(format) => format.file_extension(),
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
pub(crate) const fn coalesce(self) -> bool {
|
|
|
|
matches!(self, Self::Animation(_))
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
pub(crate) fn magick_format(self) -> &'static str {
|
2023-07-12 04:11:23 +00:00
|
|
|
match self {
|
2023-07-13 03:12:21 +00:00
|
|
|
Self::Image(format) => format.magick_format(),
|
|
|
|
Self::Animation(format) => format.magick_format(),
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-13 18:48:59 +00:00
|
|
|
|
|
|
|
pub(crate) fn process_to(self, output: InputProcessableFormat) -> Option<Self> {
|
|
|
|
match (self, output) {
|
|
|
|
(Self::Image(_), InputProcessableFormat::Avif) => Some(Self::Image(ImageFormat::Avif)),
|
|
|
|
(Self::Image(_), InputProcessableFormat::Jpeg) => Some(Self::Image(ImageFormat::Jpeg)),
|
|
|
|
(Self::Image(_), InputProcessableFormat::Jxl) => Some(Self::Image(ImageFormat::Jxl)),
|
|
|
|
(Self::Image(_), InputProcessableFormat::Png) => Some(Self::Image(ImageFormat::Png)),
|
|
|
|
(Self::Image(_), InputProcessableFormat::Webp) => Some(Self::Image(ImageFormat::Webp)),
|
|
|
|
(Self::Animation(_), InputProcessableFormat::Apng) => {
|
|
|
|
Some(Self::Animation(AnimationFormat::Apng))
|
|
|
|
}
|
|
|
|
(Self::Animation(_), InputProcessableFormat::Avif) => {
|
|
|
|
Some(Self::Animation(AnimationFormat::Avif))
|
|
|
|
}
|
|
|
|
(Self::Animation(_), InputProcessableFormat::Gif) => {
|
|
|
|
Some(Self::Animation(AnimationFormat::Gif))
|
|
|
|
}
|
|
|
|
(Self::Animation(_), InputProcessableFormat::Webp) => {
|
|
|
|
Some(Self::Animation(AnimationFormat::Webp))
|
|
|
|
}
|
|
|
|
(Self::Image(_), InputProcessableFormat::Apng) => None,
|
|
|
|
(Self::Image(_), InputProcessableFormat::Gif) => None,
|
|
|
|
(Self::Animation(_), InputProcessableFormat::Jpeg) => None,
|
|
|
|
(Self::Animation(_), InputProcessableFormat::Jxl) => None,
|
|
|
|
(Self::Animation(_), InputProcessableFormat::Png) => None,
|
|
|
|
}
|
|
|
|
}
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
impl FromStr for InputProcessableFormat {
|
|
|
|
type Err = String;
|
2023-07-12 04:11:23 +00:00
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
match s {
|
|
|
|
"apng" => Ok(Self::Apng),
|
|
|
|
"avif" => Ok(Self::Avif),
|
|
|
|
"gif" => Ok(Self::Gif),
|
|
|
|
"jpeg" => Ok(Self::Jpeg),
|
|
|
|
"jpg" => Ok(Self::Jpeg),
|
|
|
|
"jxl" => Ok(Self::Jxl),
|
|
|
|
"png" => Ok(Self::Png),
|
|
|
|
"webp" => Ok(Self::Webp),
|
|
|
|
otherwise => Err(format!("Invalid format: {otherwise}")),
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
impl std::fmt::Display for InputProcessableFormat {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
2023-07-12 04:11:23 +00:00
|
|
|
match self {
|
2023-07-13 03:12:21 +00:00
|
|
|
Self::Apng => write!(f, "apng"),
|
|
|
|
Self::Avif => write!(f, "avif"),
|
|
|
|
Self::Gif => write!(f, "gif"),
|
|
|
|
Self::Jpeg => write!(f, "jpeg"),
|
|
|
|
Self::Jxl => write!(f, "jxl"),
|
|
|
|
Self::Png => write!(f, "png"),
|
|
|
|
Self::Webp => write!(f, "webp"),
|
2023-07-12 04:11:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|