Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polish image API #3338

Merged
merged 16 commits into from
Sep 14, 2023
Prev Previous commit
Next Next commit
Use bytes:// schema for included bytes loader
emilk committed Sep 14, 2023

Verified

This commit was signed with the committer’s verified signature. The key has expired.
nikolaybotev Nikolay Botev
commit b3457456cb1fe9b982b81e5349e276e5a7676127
3 changes: 3 additions & 0 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
@@ -1912,6 +1912,9 @@ impl Context {
/// Associate some static bytes with a `uri`.
///
/// The same `uri` may be passed to [`Ui::image`] later to load the bytes as an image.
///
/// By convention, the `uri` should start wtih `bytes://`.
/// Following that convention will lead to better error messages.
pub fn include_bytes(&self, uri: impl Into<Cow<'static, str>>, bytes: impl Into<Bytes>) {
self.loaders().include.insert(uri, bytes);
}
5 changes: 4 additions & 1 deletion crates/egui/src/lib.rs
Original file line number Diff line number Diff line change
@@ -437,13 +437,16 @@ pub fn warn_if_debug_build(ui: &mut crate::Ui) {
/// egui::Image::new(egui::include_image!("../assets/ferris.png"))
/// .rounding(egui::Rounding::same(6.0))
/// );
///
/// let image_source: egui::ImageSource = egui::include_image!("../assets/ferris.png");
/// assert_eq!(image_source.uri(), Some("bytes://../assets/ferris.png"));
/// # });
/// ```
#[macro_export]
macro_rules! include_image {
($path: literal) => {
$crate::ImageSource::Bytes(
::std::borrow::Cow::Borrowed($path),
::std::borrow::Cow::Borrowed(concat!("bytes://", $path)), // uri
$crate::load::Bytes::Static(include_bytes!($path)),
)
};
14 changes: 13 additions & 1 deletion crates/egui/src/load/bytes_loader.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use super::*;

/// Maps URI:s to [`Bytes`], e.g. found with `include_bytes!`.
///
/// By convention, the URI:s should be prefixed with `bytes://`.
#[derive(Default)]
pub struct DefaultBytesLoader {
cache: Mutex<HashMap<Cow<'static, str>, Bytes>>,
@@ -27,13 +30,22 @@ impl BytesLoader for DefaultBytesLoader {
}

fn load(&self, _: &Context, uri: &str) -> BytesLoadResult {
// We accept uri:s that don't start with `bytes://` too… for now.
match self.cache.lock().get(uri).cloned() {
Some(bytes) => Ok(BytesPoll::Ready {
size: None,
bytes,
mime: None,
}),
None => Err(LoadError::NotSupported),
None => {
if uri.starts_with("bytes://") {
Err(LoadError::Loading(
"Bytes not found. Did you forget to call Context::include_bytes?".into(),
))
} else {
Err(LoadError::NotSupported)
}
}
}
}

4 changes: 4 additions & 0 deletions crates/egui/src/widgets/image.rs
Original file line number Diff line number Diff line change
@@ -74,6 +74,8 @@ impl<'a> Image<'a> {

/// Load the image from some raw bytes.
///
/// For better error messages, use the `bytes://` prefix for the URI.
///
/// See [`ImageSource::Bytes`].
pub fn from_bytes(uri: impl Into<Cow<'static, str>>, bytes: impl Into<Bytes>) -> Self {
Self::new(ImageSource::Bytes(uri.into(), bytes.into()))
@@ -472,6 +474,8 @@ pub enum ImageSource<'a> {

/// Load the image from some raw bytes.
///
/// For better error messages, use the `bytes://` prefix for the URI.
///
/// The [`Bytes`] may be:
/// - `'static`, obtained from `include_bytes!` or similar
/// - Anything that can be converted to `Arc<[u8]>`
8 changes: 2 additions & 6 deletions examples/images/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release

use eframe::egui;
use eframe::epaint::vec2;

fn main() -> Result<(), eframe::Error> {
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
let options = eframe::NativeOptions {
drag_and_drop_support: true,
initial_window_size: Some(egui::vec2(600.0, 800.0)),
..Default::default()
};
eframe::run_native(
@@ -27,10 +26,7 @@ impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
egui::ScrollArea::new([true, true]).show(ui, |ui| {
ui.add(
egui::Image::new(egui::include_image!("ferris.svg"))
.fit_to_fraction(vec2(1.0, 0.5)),
);
ui.image(egui::include_image!("ferris.svg"));
ui.add(
egui::Image::new("https://picsum.photos/seed/1.759706314/1024")
.rounding(egui::Rounding::same(10.0)),