#[cfg(feature = "asset-image")]
use super::ByteStepParams;
#[cfg(feature = "asset-image")]
use crate::proto::udb::core::asset::entity::v1 as asset_entity_pb;
#[cfg(feature = "asset-image")]
pub(crate) const MAX_IMAGE_INPUT_BYTES: u64 = 32 * 1024 * 1024;
#[cfg(feature = "asset-image")]
pub(crate) const MAX_IMAGE_PIXELS: u64 = 64_000_000;
#[cfg(feature = "asset-image")]
const DEFAULT_THUMBNAIL_EDGE: u32 = 256;
#[cfg(feature = "asset-image")]
pub(crate) fn check_input_bytes(len: u64) -> Result<(), String> {
if len > MAX_IMAGE_INPUT_BYTES {
return Err(format!(
"source image is {len} bytes, exceeds the {MAX_IMAGE_INPUT_BYTES}-byte image-step decode limit"
));
}
Ok(())
}
#[cfg(feature = "asset-image")]
pub(crate) fn check_image_pixels(width: u32, height: u32) -> Result<(), String> {
let pixels = u64::from(width) * u64::from(height);
if pixels > MAX_IMAGE_PIXELS {
return Err(format!(
"source image is {width}x{height} ({pixels} px), exceeds the {MAX_IMAGE_PIXELS}-pixel image-step decode limit"
));
}
Ok(())
}
#[cfg(feature = "asset-image")]
pub(crate) fn resolve_output_format(
requested: Option<&str>,
default: image::ImageFormat,
) -> Result<(image::ImageFormat, &'static str, &'static str), String> {
let triple = |fmt: image::ImageFormat| match fmt {
image::ImageFormat::Jpeg => (image::ImageFormat::Jpeg, "image/jpeg", "jpg"),
_ => (image::ImageFormat::Png, "image/png", "png"),
};
match requested {
None => Ok(triple(default)),
Some(f) => match f {
"png" => Ok(triple(image::ImageFormat::Png)),
"jpg" | "jpeg" => Ok(triple(image::ImageFormat::Jpeg)),
other => Err(format!(
"unsupported output image format '{other}' (this build supports: png, jpeg)"
)),
},
}
}
#[cfg(feature = "asset-image")]
pub(crate) fn apply_image_transform(
img: image::DynamicImage,
step_type: asset_entity_pb::StepType,
params: &ByteStepParams,
) -> Result<image::DynamicImage, String> {
use asset_entity_pb::StepType as T;
let out = match step_type {
T::Thumbnail => {
let w = params.width.unwrap_or(DEFAULT_THUMBNAIL_EDGE);
let h = params.height.unwrap_or(DEFAULT_THUMBNAIL_EDGE);
img.thumbnail(w, h)
}
T::Resize => match (params.width, params.height) {
(None, None) if params.format.is_some() => img,
(None, None) => {
return Err(
"RESIZE requires a width and/or height param (or a format param to convert only)"
.to_string(),
);
}
(w, h) => img.resize(
w.unwrap_or(u32::MAX),
h.unwrap_or(u32::MAX),
image::imageops::FilterType::Lanczos3,
),
},
other => {
return Err(format!(
"byte step {} is not an image transform",
other.as_str_name()
));
}
};
Ok(out)
}