1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use eframe::egui::mutex::RwLock;
use eframe::egui::{ColorImage, ImageData, TextureFilter, Vec2};
use eframe::{egui, epaint};
use egui::TextureId;
use eyre::{eyre, Context, Result};
use std::fs;
use std::path::Path;
use std::sync::Arc;

pub fn image_from_file(
    tex_manager: Arc<RwLock<epaint::TextureManager>>,
    path: &Path,
) -> Result<(TextureId, Vec2)> {
    let bytes = fs::read(path).wrap_err_with(|| format!("Failed to read image file: {path:?}"))?;
    image_from_bytes(tex_manager, &bytes, path)
}

#[inline]
pub fn image_from_bytes(
    tex_manager: Arc<RwLock<epaint::TextureManager>>,
    bytes: &[u8],
    path: &Path,
) -> Result<(TextureId, Vec2)> {
    let image = image::load_from_memory(bytes)
        .wrap_err_with(|| format!("Failed to decode image: {path:?}"))?;
    let size = [image.width() as _, image.height() as _];
    let image_buffer = image.to_rgba8();
    let pixels = image_buffer.as_flat_samples();
    let image = ColorImage::from_rgba_unmultiplied(size, pixels.as_slice());

    Ok((
        tex_manager.write().alloc(
            path.to_str().unwrap().to_owned(),
            ImageData::Color(image),
            TextureFilter::Nearest,
        ),
        Vec2::new(size[0] as _, size[1] as _),
    ))
}

pub fn svg_from_file(
    tex_manager: Arc<RwLock<epaint::TextureManager>>,
    path: &Path,
) -> Result<(TextureId, Vec2)> {
    let bytes = fs::read(path).wrap_err_with(|| format!("Failed to read image file: {path:?}"))?;
    svg_from_bytes(tex_manager, &bytes, path)
}

#[inline]
pub fn svg_from_bytes(
    tex_manager: Arc<RwLock<epaint::TextureManager>>,
    bytes: &[u8],
    path: &Path,
) -> Result<(TextureId, Vec2)> {
    let mut opt = usvg::Options::default();
    opt.fontdb.load_system_fonts();

    let rtree = usvg::Tree::from_data(bytes, &opt.to_ref())
        .wrap_err_with(|| format!("Failed to decode SVG: {path:?}"))?;
    let orig_size = rtree.svg_node().size;

    let [width, height] = [1920, 1080];
    let scale = (width as f64 / orig_size.width()).min(height as f64 / orig_size.height());
    let [width, height] = [
        (scale * orig_size.width() as f64).round() as _,
        (scale * orig_size.height() as f64).round() as _,
    ];

    let mut pixmap = tiny_skia::Pixmap::new(width, height)
        .ok_or_else(|| eyre!("Failed to create SVG Pixmap of size {width}x{height}: {path:?}"))?;

    resvg::render(
        &rtree,
        usvg::FitTo::Size(width, height),
        Default::default(),
        pixmap.as_mut(),
    )
    .ok_or_else(|| eyre!("Failed to decode SVG: {path:?}"))?;

    let image = ColorImage::from_rgba_unmultiplied([width as _, height as _], pixmap.data());

    Ok((
        tex_manager.write().alloc(
            path.to_str().unwrap().to_owned(),
            ImageData::Color(image),
            TextureFilter::Nearest,
        ),
        Vec2::new(orig_size.width() as _, orig_size.height() as _),
    ))
}