From 5934459b93c996946773622e28a23bc880d926f5 Mon Sep 17 00:00:00 2001 From: argenis de la rosa Date: Mon, 1 Jun 2026 23:40:34 -0400 Subject: [PATCH] feat(manganis): add with_width/with_height for auto aspect-ratio image sizing Add WidthOnly and HeightOnly variants to ImageSize enum, enabling users to specify only one dimension and have the other derived from the image's aspect ratio at build time. Closes #5458 --- packages/cli/src/opt/image.rs | 20 +++++++++- packages/manganis/manganis-core/src/images.rs | 40 +++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/opt/image.rs b/packages/cli/src/opt/image.rs index 1d6044811e..13a6983aeb 100644 --- a/packages/cli/src/opt/image.rs +++ b/packages/cli/src/opt/image.rs @@ -15,8 +15,24 @@ pub(crate) fn process_image( .decode(); if let Ok(image) = &mut image { - if let ImageSize::Manual { width, height } = image_options.size() { - *image = image.resize_exact(width, height, image::imageops::FilterType::Lanczos3); + match image_options.size() { + ImageSize::Manual { width, height } => { + *image = + image.resize_exact(*width, *height, image::imageops::FilterType::Lanczos3); + } + ImageSize::WidthOnly { width } => { + let ratio = image.height() as f64 / image.width() as f64; + let height = (*width as f64 * ratio).round() as u32; + *image = + image.resize_exact(*width, height, image::imageops::FilterType::Lanczos3); + } + ImageSize::HeightOnly { height } => { + let ratio = image.width() as f64 / image.height() as f64; + let width = (*height as f64 * ratio).round() as u32; + *image = + image.resize_exact(width, *height, image::imageops::FilterType::Lanczos3); + } + ImageSize::Automatic => {} } } diff --git a/packages/manganis/manganis-core/src/images.rs b/packages/manganis/manganis-core/src/images.rs index f3a4f00a36..d85c721567 100644 --- a/packages/manganis/manganis-core/src/images.rs +++ b/packages/manganis/manganis-core/src/images.rs @@ -51,6 +51,16 @@ pub enum ImageSize { /// The height of the image in pixels height: u32, }, + /// Only the width is specified; the height will be derived from the image's aspect ratio + WidthOnly { + /// The width of the image in pixels + width: u32, + }, + /// Only the height is specified; the width will be derived from the image's aspect ratio + HeightOnly { + /// The height of the image in pixels + height: u32, + }, /// The size will be automatically determined from the image source Automatic, } @@ -225,6 +235,36 @@ impl AssetOptionsBuilder { self } + /// Sets the width of the image and derives the height from the aspect ratio + /// + /// This is useful when you want to resize an image to a specific width but maintain + /// its original aspect ratio. The height will be computed at build time from the + /// actual image dimensions. + /// + /// ```rust + /// # use manganis::{asset, Asset, AssetOptions}; + /// const _: Asset = asset!("/assets/image.png", AssetOptions::image().with_width(52)); + /// ``` + pub const fn with_width(mut self, width: u32) -> Self { + self.variant.size = ImageSize::WidthOnly { width }; + self + } + + /// Sets the height of the image and derives the width from the aspect ratio + /// + /// This is useful when you want to resize an image to a specific height but maintain + /// its original aspect ratio. The width will be computed at build time from the + /// actual image dimensions. + /// + /// ```rust + /// # use manganis::{asset, Asset, AssetOptions}; + /// const _: Asset = asset!("/assets/image.png", AssetOptions::image().with_height(52)); + /// ``` + pub const fn with_height(mut self, height: u32) -> Self { + self.variant.size = ImageSize::HeightOnly { height }; + self + } + /// Convert the options into options for a generic asset pub const fn into_asset_options(self) -> AssetOptions { AssetOptions {