1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-02 06:40:06 -04:00

Texture loading in egui (#1110)

* Move texture allocation into epaint/egui proper
* Add TextureHandle
* egui_glow: cast using bytemuck instead of unsafe code
* Optimize glium painter
* Optimize WebGL
* Add example of loading an image from file
This commit is contained in:
Emil Ernerfeldt
2022-01-15 13:59:52 +01:00
committed by GitHub
parent 6c616a1b69
commit 66d80e2519
59 changed files with 1297 additions and 860 deletions

View File

@@ -7,7 +7,7 @@ struct Resource {
text: Option<String>,
/// If set, the response was an image.
image: Option<epi::Image>,
image: Option<egui::ImageData>,
/// If set, the response was text with some supported syntax highlighting (e.g. ".rs" or ".md").
colored_text: Option<ColoredText>,
@@ -17,7 +17,7 @@ impl Resource {
fn from_response(ctx: &egui::Context, response: ehttp::Response) -> Self {
let content_type = response.content_type().unwrap_or_default();
let image = if content_type.starts_with("image/") {
decode_image(&response.bytes)
load_image(&response.bytes).ok().map(|img| img.into())
} else {
None
};
@@ -112,7 +112,7 @@ impl epi::App for HttpApp {
} else if let Some(result) = &self.result {
match result {
Ok(resource) => {
ui_resource(ui, frame, &mut self.tex_mngr, resource);
ui_resource(ui, &mut self.tex_mngr, resource);
}
Err(error) => {
// This should only happen if the fetch API isn't available or something similar.
@@ -160,7 +160,7 @@ fn ui_url(ui: &mut egui::Ui, frame: &epi::Frame, url: &mut String) -> bool {
trigger_fetch
}
fn ui_resource(ui: &mut egui::Ui, frame: &epi::Frame, tex_mngr: &mut TexMngr, resource: &Resource) {
fn ui_resource(ui: &mut egui::Ui, tex_mngr: &mut TexMngr, resource: &Resource) {
let Resource {
response,
text,
@@ -212,11 +212,10 @@ fn ui_resource(ui: &mut egui::Ui, frame: &epi::Frame, tex_mngr: &mut TexMngr, re
}
if let Some(image) = image {
if let Some(texture_id) = tex_mngr.texture(frame, &response.url, image) {
let mut size = egui::Vec2::new(image.size[0] as f32, image.size[1] as f32);
size *= (ui.available_width() / size.x).min(1.0);
ui.image(texture_id, size);
}
let texture = tex_mngr.texture(ui.ctx(), &response.url, image);
let mut size = texture.size_vec2();
size *= (ui.available_width() / size.x).min(1.0);
ui.image(texture, size);
} else if let Some(colored_text) = colored_text {
colored_text.ui(ui);
} else if let Some(text) = &text {
@@ -293,33 +292,32 @@ impl ColoredText {
#[derive(Default)]
struct TexMngr {
loaded_url: String,
texture_id: Option<egui::TextureId>,
texture: Option<egui::TextureHandle>,
}
impl TexMngr {
fn texture(
&mut self,
frame: &epi::Frame,
ctx: &egui::Context,
url: &str,
image: &epi::Image,
) -> Option<egui::TextureId> {
if self.loaded_url != url {
if let Some(texture_id) = self.texture_id.take() {
frame.free_texture(texture_id);
}
self.texture_id = Some(frame.alloc_texture(image.clone()));
image: &egui::ImageData,
) -> &egui::TextureHandle {
if self.loaded_url != url || self.texture.is_none() {
self.texture = Some(ctx.load_texture(url, image.clone()));
self.loaded_url = url.to_owned();
}
self.texture_id
self.texture.as_ref().unwrap()
}
}
fn decode_image(bytes: &[u8]) -> Option<epi::Image> {
use image::GenericImageView;
let image = image::load_from_memory(bytes).ok()?;
fn load_image(image_data: &[u8]) -> Result<egui::ColorImage, image::ImageError> {
use image::GenericImageView as _;
let image = image::load_from_memory(image_data)?;
let size = [image.width() as _, image.height() as _];
let image_buffer = image.to_rgba8();
let size = [image.width() as usize, image.height() as usize];
let pixels = image_buffer.into_vec();
Some(epi::Image::from_rgba_unmultiplied(size, &pixels))
let pixels = image_buffer.as_flat_samples();
Ok(egui::ColorImage::from_rgba_unmultiplied(
size,
pixels.as_slice(),
))
}