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