Better define the meaning of `SizeHint` (#7079)
This commit is contained in:
parent
ec8b41f7ec
commit
87de733da3
|
|
@ -151,14 +151,21 @@ pub enum SizeHint {
|
||||||
/// Scale original size by some factor.
|
/// Scale original size by some factor.
|
||||||
Scale(OrderedFloat<f32>),
|
Scale(OrderedFloat<f32>),
|
||||||
|
|
||||||
/// Scale to width.
|
/// Scale to exactly this pixel width, keeping the original aspect ratio.
|
||||||
Width(u32),
|
Width(u32),
|
||||||
|
|
||||||
/// Scale to height.
|
/// Scale to exactly this pixel height, keeping the original aspect ratio.
|
||||||
Height(u32),
|
Height(u32),
|
||||||
|
|
||||||
/// Scale to size.
|
/// Scale to this pixel size.
|
||||||
Size(u32, u32),
|
Size {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
|
||||||
|
/// If true, the image will be as large as possible
|
||||||
|
/// while still fitting within the given width/height.
|
||||||
|
maintain_aspect_ratio: bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SizeHint {
|
impl Default for SizeHint {
|
||||||
|
|
@ -168,13 +175,6 @@ impl Default for SizeHint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Vec2> for SizeHint {
|
|
||||||
#[inline]
|
|
||||||
fn from(value: Vec2) -> Self {
|
|
||||||
Self::Size(value.x.round() as u32, value.y.round() as u32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents a byte buffer.
|
/// Represents a byte buffer.
|
||||||
///
|
///
|
||||||
/// This is essentially `Cow<'static, [u8]>` but with the `Owned` variant being an `Arc`.
|
/// This is essentially `Cow<'static, [u8]>` but with the `Owned` variant being an `Arc`.
|
||||||
|
|
|
||||||
|
|
@ -384,7 +384,11 @@ impl<'a> Image<'a> {
|
||||||
let texture = self.source(ui.ctx()).clone().load(
|
let texture = self.source(ui.ctx()).clone().load(
|
||||||
ui.ctx(),
|
ui.ctx(),
|
||||||
self.texture_options,
|
self.texture_options,
|
||||||
SizeHint::Size(pixel_size.x as _, pixel_size.y as _),
|
SizeHint::Size {
|
||||||
|
width: pixel_size.x as _,
|
||||||
|
height: pixel_size.y as _,
|
||||||
|
maintain_aspect_ratio: false, // no - just get exactly what we asked for
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
paint_texture_load_result(
|
paint_texture_load_result(
|
||||||
|
|
@ -481,22 +485,30 @@ impl ImageFit {
|
||||||
impl ImageSize {
|
impl ImageSize {
|
||||||
/// Size hint for e.g. rasterizing an svg.
|
/// Size hint for e.g. rasterizing an svg.
|
||||||
pub fn hint(&self, available_size: Vec2, pixels_per_point: f32) -> SizeHint {
|
pub fn hint(&self, available_size: Vec2, pixels_per_point: f32) -> SizeHint {
|
||||||
let point_size = match self.fit {
|
let Self {
|
||||||
|
maintain_aspect_ratio,
|
||||||
|
max_size,
|
||||||
|
fit,
|
||||||
|
} = *self;
|
||||||
|
|
||||||
|
let point_size = match fit {
|
||||||
ImageFit::Original { scale } => {
|
ImageFit::Original { scale } => {
|
||||||
return SizeHint::Scale((pixels_per_point * scale).ord())
|
return SizeHint::Scale((pixels_per_point * scale).ord())
|
||||||
}
|
}
|
||||||
ImageFit::Fraction(fract) => available_size * fract,
|
ImageFit::Fraction(fract) => available_size * fract,
|
||||||
ImageFit::Exact(size) => size,
|
ImageFit::Exact(size) => size,
|
||||||
};
|
};
|
||||||
let point_size = point_size.at_most(self.max_size);
|
let point_size = point_size.at_most(max_size);
|
||||||
|
|
||||||
let pixel_size = pixels_per_point * point_size;
|
let pixel_size = pixels_per_point * point_size;
|
||||||
|
|
||||||
// `inf` on an axis means "any value"
|
// `inf` on an axis means "any value"
|
||||||
match (pixel_size.x.is_finite(), pixel_size.y.is_finite()) {
|
match (pixel_size.x.is_finite(), pixel_size.y.is_finite()) {
|
||||||
(true, true) => {
|
(true, true) => SizeHint::Size {
|
||||||
SizeHint::Size(pixel_size.x.round() as u32, pixel_size.y.round() as u32)
|
width: pixel_size.x.round() as u32,
|
||||||
}
|
height: pixel_size.y.round() as u32,
|
||||||
|
maintain_aspect_ratio,
|
||||||
|
},
|
||||||
(true, false) => SizeHint::Width(pixel_size.x.round() as u32),
|
(true, false) => SizeHint::Width(pixel_size.x.round() as u32),
|
||||||
(false, true) => SizeHint::Height(pixel_size.y.round() as u32),
|
(false, true) => SizeHint::Height(pixel_size.y.round() as u32),
|
||||||
(false, false) => SizeHint::Scale(pixels_per_point.ord()),
|
(false, false) => SizeHint::Scale(pixels_per_point.ord()),
|
||||||
|
|
|
||||||
|
|
@ -255,43 +255,51 @@ pub fn load_svg_bytes_with_size(
|
||||||
size_hint: Option<SizeHint>,
|
size_hint: Option<SizeHint>,
|
||||||
options: &resvg::usvg::Options<'_>,
|
options: &resvg::usvg::Options<'_>,
|
||||||
) -> Result<egui::ColorImage, String> {
|
) -> Result<egui::ColorImage, String> {
|
||||||
use resvg::tiny_skia::{IntSize, Pixmap};
|
use egui::Vec2;
|
||||||
use resvg::usvg::{Transform, Tree};
|
use resvg::{
|
||||||
|
tiny_skia::Pixmap,
|
||||||
|
usvg::{Transform, Tree},
|
||||||
|
};
|
||||||
|
|
||||||
profiling::function_scope!();
|
profiling::function_scope!();
|
||||||
|
|
||||||
let rtree = Tree::from_data(svg_bytes, options).map_err(|err| err.to_string())?;
|
let rtree = Tree::from_data(svg_bytes, options).map_err(|err| err.to_string())?;
|
||||||
|
|
||||||
let size = rtree.size().to_int_size();
|
let original_size = Vec2::new(rtree.size().width(), rtree.size().height());
|
||||||
|
|
||||||
let scaled_size = match size_hint {
|
let scaled_size = match size_hint {
|
||||||
None => size,
|
None => original_size,
|
||||||
Some(SizeHint::Size(w, h)) => size.scale_to(
|
Some(SizeHint::Size {
|
||||||
IntSize::from_wh(w, h).ok_or_else(|| format!("Failed to scale SVG to {w}x{h}"))?,
|
width,
|
||||||
),
|
height,
|
||||||
Some(SizeHint::Height(h)) => size
|
maintain_aspect_ratio,
|
||||||
.scale_to_height(h)
|
}) => {
|
||||||
.ok_or_else(|| format!("Failed to scale SVG to height {h}"))?,
|
if maintain_aspect_ratio {
|
||||||
Some(SizeHint::Width(w)) => size
|
// As large as possible, without exceeding the given size:
|
||||||
.scale_to_width(w)
|
let mut size = original_size;
|
||||||
.ok_or_else(|| format!("Failed to scale SVG to width {w}"))?,
|
size *= width as f32 / original_size.x;
|
||||||
Some(SizeHint::Scale(z)) => {
|
if size.y > height as f32 {
|
||||||
let z_inner = z.into_inner();
|
size *= height as f32 / size.y;
|
||||||
size.scale_by(z_inner)
|
}
|
||||||
.ok_or_else(|| format!("Failed to scale SVG by {z_inner}"))?
|
size
|
||||||
|
} else {
|
||||||
|
Vec2::new(width as _, height as _)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Some(SizeHint::Height(h)) => original_size * (h as f32 / original_size.y),
|
||||||
|
Some(SizeHint::Width(w)) => original_size * (w as f32 / original_size.x),
|
||||||
|
Some(SizeHint::Scale(scale)) => scale.into_inner() * original_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (w, h) = (scaled_size.width(), scaled_size.height());
|
let scaled_size = scaled_size.round();
|
||||||
|
let (w, h) = (scaled_size.x as u32, scaled_size.y as u32);
|
||||||
|
|
||||||
let mut pixmap =
|
let mut pixmap =
|
||||||
Pixmap::new(w, h).ok_or_else(|| format!("Failed to create SVG Pixmap of size {w}x{h}"))?;
|
Pixmap::new(w, h).ok_or_else(|| format!("Failed to create SVG Pixmap of size {w}x{h}"))?;
|
||||||
|
|
||||||
resvg::render(
|
resvg::render(
|
||||||
&rtree,
|
&rtree,
|
||||||
Transform::from_scale(
|
Transform::from_scale(w as f32 / original_size.x, h as f32 / original_size.y),
|
||||||
w as f32 / size.width() as f32,
|
|
||||||
h as f32 / size.height() as f32,
|
|
||||||
),
|
|
||||||
&mut pixmap.as_mut(),
|
&mut pixmap.as_mut(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue