cog_task/resource/
image.rs

1use eframe::egui::mutex::RwLock;
2use eframe::egui::{ColorImage, ImageData, TextureFilter, Vec2};
3use eframe::{egui, epaint};
4use egui::TextureId;
5use eyre::{eyre, Context, Result};
6use std::fs;
7use std::path::Path;
8use std::sync::Arc;
9
10pub fn image_from_file(
11    tex_manager: Arc<RwLock<epaint::TextureManager>>,
12    path: &Path,
13) -> Result<(TextureId, Vec2)> {
14    let bytes = fs::read(path).wrap_err_with(|| format!("Failed to read image file: {path:?}"))?;
15    image_from_bytes(tex_manager, &bytes, path)
16}
17
18#[inline]
19pub fn image_from_bytes(
20    tex_manager: Arc<RwLock<epaint::TextureManager>>,
21    bytes: &[u8],
22    path: &Path,
23) -> Result<(TextureId, Vec2)> {
24    let image = image::load_from_memory(bytes)
25        .wrap_err_with(|| format!("Failed to decode image: {path:?}"))?;
26    let size = [image.width() as _, image.height() as _];
27    let image_buffer = image.to_rgba8();
28    let pixels = image_buffer.as_flat_samples();
29    let image = ColorImage::from_rgba_unmultiplied(size, pixels.as_slice());
30
31    Ok((
32        tex_manager.write().alloc(
33            path.to_str().unwrap().to_owned(),
34            ImageData::Color(image),
35            TextureFilter::Nearest,
36        ),
37        Vec2::new(size[0] as _, size[1] as _),
38    ))
39}
40
41pub fn svg_from_file(
42    tex_manager: Arc<RwLock<epaint::TextureManager>>,
43    path: &Path,
44) -> Result<(TextureId, Vec2)> {
45    let bytes = fs::read(path).wrap_err_with(|| format!("Failed to read image file: {path:?}"))?;
46    svg_from_bytes(tex_manager, &bytes, path)
47}
48
49#[inline]
50pub fn svg_from_bytes(
51    tex_manager: Arc<RwLock<epaint::TextureManager>>,
52    bytes: &[u8],
53    path: &Path,
54) -> Result<(TextureId, Vec2)> {
55    let mut opt = usvg::Options::default();
56    opt.fontdb.load_system_fonts();
57
58    let rtree = usvg::Tree::from_data(bytes, &opt.to_ref())
59        .wrap_err_with(|| format!("Failed to decode SVG: {path:?}"))?;
60    let orig_size = rtree.svg_node().size;
61
62    let [width, height] = [1920, 1080];
63    let scale = (width as f64 / orig_size.width()).min(height as f64 / orig_size.height());
64    let [width, height] = [
65        (scale * orig_size.width() as f64).round() as _,
66        (scale * orig_size.height() as f64).round() as _,
67    ];
68
69    let mut pixmap = tiny_skia::Pixmap::new(width, height)
70        .ok_or_else(|| eyre!("Failed to create SVG Pixmap of size {width}x{height}: {path:?}"))?;
71
72    resvg::render(
73        &rtree,
74        usvg::FitTo::Size(width, height),
75        Default::default(),
76        pixmap.as_mut(),
77    )
78    .ok_or_else(|| eyre!("Failed to decode SVG: {path:?}"))?;
79
80    let image = ColorImage::from_rgba_unmultiplied([width as _, height as _], pixmap.data());
81
82    Ok((
83        tex_manager.write().alloc(
84            path.to_str().unwrap().to_owned(),
85            ImageData::Color(image),
86            TextureFilter::Nearest,
87        ),
88        Vec2::new(orig_size.width() as _, orig_size.height() as _),
89    ))
90}