Add explicit error handling to image loading

This commit is contained in:
Héctor Ramón Jiménez 2025-10-28 21:19:25 +01:00
parent 7c11ccb046
commit 867fe819c0
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
17 changed files with 357 additions and 118 deletions

View file

@ -232,11 +232,17 @@ impl core::Renderer for Renderer {
fn allocate_image(
&mut self,
handle: &core::image::Handle,
callback: impl FnOnce(core::image::Allocation) + Send + 'static,
callback: impl FnOnce(Result<core::image::Allocation, core::image::Error>)
+ Send
+ 'static,
) {
// TODO: Concurrency
#[cfg(feature = "image")]
#[allow(unsafe_code)]
callback(unsafe { core::image::allocate(handle) });
// TODO: Concurrency
callback(self.engine.raster_pipeline.load(handle));
#[cfg(not(feature = "image"))]
callback(Err(core::image::Error::Unsupported))
}
}
@ -360,7 +366,17 @@ impl graphics::mesh::Renderer for Renderer {
impl core::image::Renderer for Renderer {
type Handle = core::image::Handle;
fn measure_image(&self, handle: &Self::Handle) -> crate::core::Size<u32> {
fn load_image(
&self,
handle: &Self::Handle,
) -> Result<core::image::Allocation, core::image::Error> {
self.engine.raster_pipeline.load(handle)
}
fn measure_image(
&self,
handle: &Self::Handle,
) -> Option<crate::core::Size<u32>> {
self.engine.raster_pipeline.dimensions(handle)
}

View file

@ -18,12 +18,24 @@ impl Pipeline {
}
}
pub fn dimensions(&self, handle: &raster::Handle) -> Size<u32> {
if let Some(image) = self.cache.borrow_mut().allocate(handle) {
Size::new(image.width(), image.height())
} else {
Size::new(0, 0)
}
pub fn load(
&self,
handle: &raster::Handle,
) -> Result<raster::Allocation, raster::Error> {
let mut cache = self.cache.borrow_mut();
let image = cache.allocate(handle)?;
#[allow(unsafe_code)]
Ok(unsafe {
raster::allocate(handle, Size::new(image.width(), image.height()))
})
}
pub fn dimensions(&self, handle: &raster::Handle) -> Option<Size<u32>> {
let mut cache = self.cache.borrow_mut();
let image = cache.allocate(handle).ok()?;
Some(Size::new(image.width(), image.height()))
}
pub fn draw(
@ -36,34 +48,34 @@ impl Pipeline {
transform: tiny_skia::Transform,
clip_mask: Option<&tiny_skia::Mask>,
) {
if let Some(image) = self.cache.borrow_mut().allocate(handle) {
let width_scale = bounds.width / image.width() as f32;
let height_scale = bounds.height / image.height() as f32;
let mut cache = self.cache.borrow_mut();
let transform = transform.pre_scale(width_scale, height_scale);
let Ok(image) = cache.allocate(handle) else {
return;
};
let quality = match filter_method {
raster::FilterMethod::Linear => {
tiny_skia::FilterQuality::Bilinear
}
raster::FilterMethod::Nearest => {
tiny_skia::FilterQuality::Nearest
}
};
let width_scale = bounds.width / image.width() as f32;
let height_scale = bounds.height / image.height() as f32;
pixels.draw_pixmap(
(bounds.x / width_scale) as i32,
(bounds.y / height_scale) as i32,
image,
&tiny_skia::PixmapPaint {
quality,
opacity,
..Default::default()
},
transform,
clip_mask,
);
}
let transform = transform.pre_scale(width_scale, height_scale);
let quality = match filter_method {
raster::FilterMethod::Linear => tiny_skia::FilterQuality::Bilinear,
raster::FilterMethod::Nearest => tiny_skia::FilterQuality::Nearest,
};
pixels.draw_pixmap(
(bounds.x / width_scale) as i32,
(bounds.y / height_scale) as i32,
image,
&tiny_skia::PixmapPaint {
quality,
opacity,
..Default::default()
},
transform,
clip_mask,
);
}
pub fn trim_cache(&mut self) {
@ -81,11 +93,18 @@ impl Cache {
pub fn allocate(
&mut self,
handle: &raster::Handle,
) -> Option<tiny_skia::PixmapRef<'_>> {
) -> Result<tiny_skia::PixmapRef<'_>, raster::Error> {
let id = handle.id();
if let hash_map::Entry::Vacant(entry) = self.entries.entry(id) {
let image = graphics::image::load(handle).ok()?;
let image = match graphics::image::load(handle) {
Ok(image) => image,
Err(error) => {
let _ = entry.insert(None);
return Err(error);
}
};
let mut buffer =
vec![0u32; image.width() as usize * image.height() as usize];
@ -106,14 +125,21 @@ impl Cache {
}
let _ = self.hits.insert(id);
self.entries.get(&id).unwrap().as_ref().map(|entry| {
tiny_skia::PixmapRef::from_bytes(
bytemuck::cast_slice(&entry.pixels),
entry.width,
entry.height,
)
.expect("Build pixmap from image bytes")
})
Ok(self
.entries
.get(&id)
.unwrap()
.as_ref()
.map(|entry| {
tiny_skia::PixmapRef::from_bytes(
bytemuck::cast_slice(&entry.pixels),
entry.width,
entry.height,
)
.expect("Build pixmap from image bytes")
})
.expect("Image should be allocated"))
}
fn trim(&mut self) {