I am getting an image error that I'm guessing is dimension-related, since the left and right change whenever I change the image loading size variables. The program compiles but crashes on start.
This is my code, I'm inserting a PNG image into an existing Grid. [apologies for the verbose :: syntax, I use it while I'm learning a library]
use std::include_bytes;
const ICONB: &[u8; 3860] = include_bytes!("2.png");
(.. egui boilerplate ..)
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
egui::Grid::new("")
.striped(true)
.show(ui, |ui| {
ui.label("name");
ui.add(egui::Image::new(
egui::TextureId::from(
&egui::Context::load_texture(
&ctx,
"",
egui::ColorImage::from_rgba_unmultiplied(
[109usize, 462usize], //those are factual dimensions
ICONB
),
egui::TextureFilter::Linear
)
), [109.0, 462.0]
));
Backtrace:
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `201432`,
right: `3860`', /home/tommy/.cargo/registry/src/github.com-1ecc6299db9ec823/epaint-0.19.0/src/image.rs:96:9
stack backtrace:
0: rust_begin_unwind
at /rustc/ca122c7ebb3ab50149c9d3d24ddb59c252b32272/library/std/src/panicking.rs:584:5
1: core::panicking::panic_fmt
at /rustc/ca122c7ebb3ab50149c9d3d24ddb59c252b32272/library/core/src/panicking.rs:142:14
2: core::panicking::assert_failed_inner
3: core::panicking::assert_failed
4: epaint::image::ColorImage::from_rgba_unmultiplied
5: core::ops::function::FnOnce::call_once{{vtable.shim}}
6: core::ops::function::FnOnce::call_once{{vtable.shim}}
7: egui::ui::Ui::allocate_ui_at_rect
8: core::ops::function::FnOnce::call_once{{vtable.shim}}
9: egui::containers::frame::Frame::show
10: egui::containers::panel::CentralPanel::show
11: <win::MyApp as eframe::epi::App>::update
12: eframe::native::epi_integration::EpiIntegration::update
13: <eframe::native::run::glow_integration::GlowWinitApp as eframe::native::run::WinitApp>::paint
14: eframe::native::run::run_and_return::{{closure}}
15: winit::platform_impl::platform::x11::EventLoop<T>::run_return::single_iteration
16: winit::platform_impl::platform::x11::EventLoop<T>::run_return
17: eframe::native::run::run_and_return
18: std::thread::local::LocalKey<T>::with
19: eframe::native::run::glow_integration::run_glow
20: eframe::run_native
21: win::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
That's the source code of epaint
's from_rgba_unmultiplied
that fails:
pub fn from_rgba_unmultiplied(size: [usize; 2], rgba: &[u8]) -> Self {
assert_eq!(size[0] * size[1] * 4, rgba.len());
let pixels = rgba
.chunks_exact(4)
.map(|p| Color32::from_rgba_unmultiplied(p[0], p[1], p[2], p[3]))
.collect();
Self { size, pixels }
}
Can I load the image this way, how to understand the internals of loading an image better?
Follow-up issue: How can I implement rescaling in a fast way here?
The from_rgba_unmultiplied()
function that is panicking expects raw RGBA data, but you're passing in PNG-encoded image data. The PNG format compresses the image data, which is why the size is off and the assert fails.
To fix this, you need to decode the PNG data into raw RGBA before passing it to from_rgba_unmultiplied()
. The documentation for that function shows exactly how to do that, with the help of the image
crate:
fn load_image_from_memory(image_data: &[u8]) -> Result<ColorImage, image::ImageError> {
let image = image::load_from_memory(image_data)?;
let size = [image.width() as _, image.height() as _];
let image_buffer = image.to_rgba8();
let pixels = image_buffer.as_flat_samples();
Ok(ColorImage::from_rgba_unmultiplied(
size,
pixels.as_slice(),
))
}