iced_graphics/
image.rs
1#[cfg(feature = "image")]
3pub use ::image as image_rs;
4
5use crate::core::image;
6use crate::core::svg;
7use crate::core::Rectangle;
8
9#[derive(Debug, Clone, PartialEq)]
11pub enum Image {
12 Raster {
14 handle: image::Image,
16
17 bounds: Rectangle,
19 },
20 Vector {
22 handle: svg::Svg,
24
25 bounds: Rectangle,
27 },
28}
29
30impl Image {
31 pub fn bounds(&self) -> Rectangle {
33 match self {
34 Image::Raster { handle, bounds } => bounds.rotate(handle.rotation),
35 Image::Vector { handle, bounds, .. } => {
36 bounds.rotate(handle.rotation)
37 }
38 }
39 }
40}
41
42#[cfg(feature = "image")]
43pub fn load(
47 handle: &image::Handle,
48) -> ::image::ImageResult<::image::ImageBuffer<::image::Rgba<u8>, image::Bytes>>
49{
50 use bitflags::bitflags;
51
52 bitflags! {
53 struct Operation: u8 {
54 const FLIP_HORIZONTALLY = 0b001;
55 const ROTATE_180 = 0b010;
56 const FLIP_DIAGONALLY = 0b100;
57 }
58 }
59
60 impl Operation {
61 fn from_exif<R>(reader: &mut R) -> Result<Self, exif::Error>
64 where
65 R: std::io::BufRead + std::io::Seek,
66 {
67 let exif = exif::Reader::new().read_from_container(reader)?;
68
69 Ok(exif
70 .get_field(exif::Tag::Orientation, exif::In::PRIMARY)
71 .and_then(|field| field.value.get_uint(0))
72 .and_then(|value| u8::try_from(value).ok())
73 .and_then(|value| Self::from_bits(value.saturating_sub(1)))
74 .unwrap_or_else(Self::empty))
75 }
76
77 fn perform(
78 self,
79 mut image: ::image::DynamicImage,
80 ) -> ::image::DynamicImage {
81 use ::image::imageops;
82
83 if self.contains(Self::FLIP_DIAGONALLY) {
84 imageops::flip_vertical_in_place(&mut image);
85 }
86
87 if self.contains(Self::ROTATE_180) {
88 imageops::rotate180_in_place(&mut image);
89 }
90
91 if self.contains(Self::FLIP_HORIZONTALLY) {
92 imageops::flip_horizontal_in_place(&mut image);
93 }
94
95 image
96 }
97 }
98
99 let (width, height, pixels) = match handle {
100 image::Handle::Path(_, path) => {
101 let image = ::image::io::Reader::open(&path)?
102 .with_guessed_format()?
103 .decode()?;
104
105 let operation = std::fs::File::open(path)
106 .ok()
107 .map(std::io::BufReader::new)
108 .and_then(|mut reader| Operation::from_exif(&mut reader).ok())
109 .unwrap_or_else(Operation::empty);
110
111 let rgba = operation.perform(image).into_rgba8();
112
113 (
114 rgba.width(),
115 rgba.height(),
116 image::Bytes::from(rgba.into_raw()),
117 )
118 }
119 image::Handle::Bytes(_, bytes) => {
120 let image = ::image::load_from_memory(bytes)?;
121 let operation =
122 Operation::from_exif(&mut std::io::Cursor::new(bytes))
123 .ok()
124 .unwrap_or_else(Operation::empty);
125
126 let rgba = operation.perform(image).into_rgba8();
127
128 (
129 rgba.width(),
130 rgba.height(),
131 image::Bytes::from(rgba.into_raw()),
132 )
133 }
134 image::Handle::Rgba {
135 width,
136 height,
137 pixels,
138 ..
139 } => (*width, *height, pixels.clone()),
140 };
141
142 if let Some(image) = ::image::ImageBuffer::from_raw(width, height, pixels) {
143 Ok(image)
144 } else {
145 Err(::image::error::ImageError::Limits(
146 ::image::error::LimitError::from_kind(
147 ::image::error::LimitErrorKind::DimensionError,
148 ),
149 ))
150 }
151}