use crate::Error::UnsupportedImageFormat;
use crate::impl_style;
use crate::style::BoxStyle;
use crate::widgets::Widget;
use agape_core::{GlobalId, Size};
use agape_layout::{EmptyLayout, IntrinsicSize, Layout};
use agape_renderer::Renderer;
use image::{DynamicImage, ImageFormat, ImageReader};
use std::fs;
use std::io::Cursor;
use std::path::Path;
use std::sync::Arc;
pub struct Image {
id: GlobalId,
data: Arc<DynamicImage>,
style: BoxStyle,
}
impl Image {
pub fn open<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
let data = fs::read(path)?;
Self::bytes(&data)
}
pub fn bytes(bytes: &[u8]) -> crate::Result<Self> {
let buf = Cursor::new(bytes);
let reader = ImageReader::new(buf).with_guessed_format()?;
if !matches!(
reader.format(),
Some(ImageFormat::Png | ImageFormat::Jpeg | ImageFormat::WebP)
) {
return Err(UnsupportedImageFormat);
}
let image = reader.decode()?;
let width = image.width() as f32;
let height = image.height() as f32;
let mut style = BoxStyle::new();
style.intrinsic_size = IntrinsicSize::fixed(width, height);
Ok(Self {
id: GlobalId::new(),
data: Arc::new(image),
style,
})
}
pub fn dimensions(&self) -> Size {
Size::new(self.data.width() as f32, self.data.height() as f32)
}
impl_style! {}
}
impl Widget for Image {
fn id(&self) -> GlobalId {
self.id
}
fn children(&self) -> Vec<&dyn Widget> {
vec![]
}
fn traverse(&mut self, _: &mut dyn FnMut(&mut dyn Widget)) {}
fn layout(&self, _: &mut Renderer) -> Box<dyn Layout> {
let layout = EmptyLayout {
id: self.id,
intrinsic_size: self.style.intrinsic_size,
..Default::default()
};
Box::new(layout)
}
fn render(&self, renderer: &mut Renderer, layout: &dyn Layout) {
let layout = layout.get(self.id()).unwrap();
let size = layout.size();
let position = layout.position();
let mut image = agape_renderer::image::Image::new(self.data.clone());
image.size = size;
image.position = position;
renderer.draw_image(image);
}
}