#![allow(deprecated)]
use egui::{mutex::Mutex, TextureOptions};
#[cfg(feature = "svg")]
use egui::SizeHint;
#[deprecated = "consider using `egui::Image` instead"]
pub struct RetainedImage {
debug_name: String,
size: [usize; 2],
image: Mutex<egui::ColorImage>,
texture: Mutex<Option<egui::TextureHandle>>,
options: TextureOptions,
}
impl RetainedImage {
pub fn from_color_image(debug_name: impl Into<String>, image: ColorImage) -> Self {
Self {
debug_name: debug_name.into(),
size: image.size,
image: Mutex::new(image),
texture: Default::default(),
options: Default::default(),
}
}
#[cfg(feature = "image")]
pub fn from_image_bytes(
debug_name: impl Into<String>,
image_bytes: &[u8],
) -> Result<Self, String> {
Ok(Self::from_color_image(
debug_name,
load_image_bytes(image_bytes)?,
))
}
#[cfg(feature = "svg")]
pub fn from_svg_bytes(debug_name: impl Into<String>, svg_bytes: &[u8]) -> Result<Self, String> {
Self::from_svg_bytes_with_size(debug_name, svg_bytes, None)
}
#[cfg(feature = "svg")]
pub fn from_svg_str(debug_name: impl Into<String>, svg_str: &str) -> Result<Self, String> {
Self::from_svg_bytes(debug_name, svg_str.as_bytes())
}
#[cfg(feature = "svg")]
pub fn from_svg_bytes_with_size(
debug_name: impl Into<String>,
svg_bytes: &[u8],
size_hint: Option<SizeHint>,
) -> Result<Self, String> {
Ok(Self::from_color_image(
debug_name,
load_svg_bytes_with_size(svg_bytes, size_hint)?,
))
}
#[inline]
pub fn with_options(mut self, options: TextureOptions) -> Self {
self.options = options;
*self.texture.lock() = None;
self
}
pub fn size(&self) -> [usize; 2] {
self.size
}
pub fn width(&self) -> usize {
self.size[0]
}
pub fn height(&self) -> usize {
self.size[1]
}
pub fn size_vec2(&self) -> egui::Vec2 {
let [w, h] = self.size();
egui::vec2(w as f32, h as f32)
}
pub fn debug_name(&self) -> &str {
&self.debug_name
}
pub fn texture_id(&self, ctx: &egui::Context) -> egui::TextureId {
self.texture
.lock()
.get_or_insert_with(|| {
let image: &mut ColorImage = &mut self.image.lock();
let image = std::mem::take(image);
ctx.load_texture(&self.debug_name, image, self.options)
})
.id()
}
pub fn show_max_size(&self, ui: &mut egui::Ui, max_size: egui::Vec2) -> egui::Response {
let mut desired_size = self.size_vec2();
desired_size *= (max_size.x / desired_size.x).min(1.0);
desired_size *= (max_size.y / desired_size.y).min(1.0);
self.show_size(ui, desired_size)
}
pub fn show(&self, ui: &mut egui::Ui) -> egui::Response {
self.show_size(ui, self.size_vec2())
}
pub fn show_scaled(&self, ui: &mut egui::Ui, scale: f32) -> egui::Response {
self.show_size(ui, self.size_vec2() * scale)
}
pub fn show_size(&self, ui: &mut egui::Ui, desired_size: egui::Vec2) -> egui::Response {
ui.image((self.texture_id(ui.ctx()), desired_size))
}
}
use egui::ColorImage;
#[cfg(feature = "image")]
pub fn load_image_bytes(image_bytes: &[u8]) -> Result<egui::ColorImage, String> {
crate::profile_function!();
let image = image::load_from_memory(image_bytes).map_err(|err| err.to_string())?;
let size = [image.width() as _, image.height() as _];
let image_buffer = image.to_rgba8();
let pixels = image_buffer.as_flat_samples();
Ok(egui::ColorImage::from_rgba_unmultiplied(
size,
pixels.as_slice(),
))
}
#[cfg(feature = "svg")]
pub fn load_svg_bytes(svg_bytes: &[u8]) -> Result<egui::ColorImage, String> {
load_svg_bytes_with_size(svg_bytes, None)
}
#[cfg(feature = "svg")]
pub fn load_svg_bytes_with_size(
svg_bytes: &[u8],
size_hint: Option<SizeHint>,
) -> Result<egui::ColorImage, String> {
use resvg::tiny_skia::{IntSize, Pixmap};
use resvg::usvg::{Options, Tree, TreeParsing};
crate::profile_function!();
let opt = Options::default();
let mut rtree = Tree::from_data(svg_bytes, &opt).map_err(|err| err.to_string())?;
let mut size = rtree.size.to_int_size();
match size_hint {
None => (),
Some(SizeHint::Size(w, h)) => {
size = size.scale_to(
IntSize::from_wh(w, h).ok_or_else(|| format!("Failed to scale SVG to {w}x{h}"))?,
);
}
Some(SizeHint::Height(h)) => {
size = size
.scale_to_height(h)
.ok_or_else(|| format!("Failed to scale SVG to height {h}"))?;
}
Some(SizeHint::Width(w)) => {
size = size
.scale_to_width(w)
.ok_or_else(|| format!("Failed to scale SVG to width {w}"))?;
}
Some(SizeHint::Scale(z)) => {
let z_inner = z.into_inner();
size = size
.scale_by(z_inner)
.ok_or_else(|| format!("Failed to scale SVG by {z_inner}"))?;
}
};
let (w, h) = (size.width(), size.height());
let mut pixmap =
Pixmap::new(w, h).ok_or_else(|| format!("Failed to create SVG Pixmap of size {w}x{h}"))?;
rtree.size = size.to_size();
resvg::Tree::from_usvg(&rtree).render(Default::default(), &mut pixmap.as_mut());
let image = egui::ColorImage::from_rgba_unmultiplied([w as _, h as _], pixmap.data());
Ok(image)
}