Make `Image::paint_at` pixel-perfect crisp for SVG images (#7078)
This commit is contained in:
parent
b8334f365b
commit
ec8b41f7ec
|
|
@ -3114,6 +3114,8 @@ impl Context {
|
||||||
));
|
));
|
||||||
let max_preview_size = vec2(48.0, 32.0);
|
let max_preview_size = vec2(48.0, 32.0);
|
||||||
|
|
||||||
|
let pixels_per_point = self.pixels_per_point();
|
||||||
|
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ScrollArea::vertical()
|
ScrollArea::vertical()
|
||||||
.max_height(300.0)
|
.max_height(300.0)
|
||||||
|
|
@ -3128,15 +3130,16 @@ impl Context {
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
for (&texture_id, meta) in textures {
|
for (&texture_id, meta) in textures {
|
||||||
let [w, h] = meta.size;
|
let [w, h] = meta.size;
|
||||||
|
let point_size = vec2(w as f32, h as f32) / pixels_per_point;
|
||||||
|
|
||||||
let mut size = vec2(w as f32, h as f32);
|
let mut size = point_size;
|
||||||
size *= (max_preview_size.x / size.x).min(1.0);
|
size *= (max_preview_size.x / size.x).min(1.0);
|
||||||
size *= (max_preview_size.y / size.y).min(1.0);
|
size *= (max_preview_size.y / size.y).min(1.0);
|
||||||
ui.image(SizedTexture::new(texture_id, size))
|
ui.image(SizedTexture::new(texture_id, size))
|
||||||
.on_hover_ui(|ui| {
|
.on_hover_ui(|ui| {
|
||||||
// show larger on hover
|
// show larger on hover
|
||||||
let max_size = 0.5 * ui.ctx().screen_rect().size();
|
let max_size = 0.5 * ui.ctx().screen_rect().size();
|
||||||
let mut size = vec2(w as f32, h as f32);
|
let mut size = point_size;
|
||||||
size *= max_size.x / size.x.max(max_size.x);
|
size *= max_size.x / size.x.max(max_size.x);
|
||||||
size *= max_size.y / size.y.max(max_size.y);
|
size *= max_size.y / size.y.max(max_size.y);
|
||||||
ui.image(SizedTexture::new(texture_id, size));
|
ui.image(SizedTexture::new(texture_id, size));
|
||||||
|
|
|
||||||
|
|
@ -413,6 +413,8 @@ pub trait ImageLoader {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct SizedTexture {
|
pub struct SizedTexture {
|
||||||
pub id: TextureId,
|
pub id: TextureId,
|
||||||
|
|
||||||
|
/// Size in logical ui points.
|
||||||
pub size: Vec2,
|
pub size: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{borrow::Cow, slice::Iter, sync::Arc, time::Duration};
|
use std::{borrow::Cow, slice::Iter, sync::Arc, time::Duration};
|
||||||
|
|
||||||
use emath::{Align, Float as _, Rot2};
|
use emath::{Align, Float as _, GuiRounding as _, NumExt as _, Rot2};
|
||||||
use epaint::{
|
use epaint::{
|
||||||
text::{LayoutJob, TextFormat, TextWrapping},
|
text::{LayoutJob, TextFormat, TextWrapping},
|
||||||
RectShape,
|
RectShape,
|
||||||
|
|
@ -373,9 +373,23 @@ impl<'a> Image<'a> {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn paint_at(&self, ui: &Ui, rect: Rect) {
|
pub fn paint_at(&self, ui: &Ui, rect: Rect) {
|
||||||
|
let pixels_per_point = ui.pixels_per_point();
|
||||||
|
|
||||||
|
let rect = rect.round_to_pixels(pixels_per_point);
|
||||||
|
|
||||||
|
// Load exactly the size of the rectangle we are painting to.
|
||||||
|
// This is important for getting crisp SVG:s.
|
||||||
|
let pixel_size = (pixels_per_point * rect.size()).round();
|
||||||
|
|
||||||
|
let texture = self.source(ui.ctx()).clone().load(
|
||||||
|
ui.ctx(),
|
||||||
|
self.texture_options,
|
||||||
|
SizeHint::Size(pixel_size.x as _, pixel_size.y as _),
|
||||||
|
);
|
||||||
|
|
||||||
paint_texture_load_result(
|
paint_texture_load_result(
|
||||||
ui,
|
ui,
|
||||||
&self.load_for_size(ui.ctx(), rect.size()),
|
&texture,
|
||||||
rect,
|
rect,
|
||||||
self.show_loading_spinner,
|
self.show_loading_spinner,
|
||||||
&self.image_options,
|
&self.image_options,
|
||||||
|
|
@ -467,19 +481,24 @@ 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 size = match self.fit {
|
let point_size = match self.fit {
|
||||||
ImageFit::Original { scale } => return SizeHint::Scale(scale.ord()),
|
ImageFit::Original { scale } => {
|
||||||
|
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 size = size.min(self.max_size);
|
let point_size = point_size.at_most(self.max_size);
|
||||||
let size = size * pixels_per_point;
|
|
||||||
|
let pixel_size = pixels_per_point * point_size;
|
||||||
|
|
||||||
// `inf` on an axis means "any value"
|
// `inf` on an axis means "any value"
|
||||||
match (size.x.is_finite(), size.y.is_finite()) {
|
match (pixel_size.x.is_finite(), pixel_size.y.is_finite()) {
|
||||||
(true, true) => SizeHint::Size(size.x.round() as u32, size.y.round() as u32),
|
(true, true) => {
|
||||||
(true, false) => SizeHint::Width(size.x.round() as u32),
|
SizeHint::Size(pixel_size.x.round() as u32, pixel_size.y.round() as u32)
|
||||||
(false, true) => SizeHint::Height(size.y.round() as u32),
|
}
|
||||||
|
(true, false) => SizeHint::Width(pixel_size.x.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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue