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#[allow(missing_docs)]
11#[derive(Debug, Clone, PartialEq)]
12pub enum Image {
13 Raster {
15 image: image::Image,
16 bounds: Rectangle,
17 clip_bounds: Rectangle,
18 },
19
20 Vector {
22 svg: svg::Svg,
23 bounds: Rectangle,
24 clip_bounds: Rectangle,
25 },
26}
27
28impl Image {
29 pub fn bounds(&self) -> Rectangle {
31 match self {
32 Image::Raster { image, bounds, .. } => {
33 bounds.rotate(image.rotation)
34 }
35 Image::Vector { svg, bounds, .. } => bounds.rotate(svg.rotation),
36 }
37 }
38}
39
40#[cfg(feature = "image")]
42pub type Buffer = ::image::ImageBuffer<::image::Rgba<u8>, image::Bytes>;
43
44#[cfg(feature = "image")]
45pub fn load(handle: &image::Handle) -> Result<Buffer, image::Error> {
49 use bitflags::bitflags;
50
51 bitflags! {
52 struct Operation: u8 {
53 const FLIP_HORIZONTALLY = 0b1;
54 const ROTATE_180 = 0b10;
55 const FLIP_VERTICALLY= 0b100;
56 const ROTATE_90 = 0b1000;
57 const ROTATE_270 = 0b10000;
58 }
59 }
60
61 impl Operation {
62 fn from_exif<R>(reader: &mut R) -> Result<Self, exif::Error>
65 where
66 R: std::io::BufRead + std::io::Seek,
67 {
68 let exif = exif::Reader::new().read_from_container(reader)?;
69
70 Ok(exif
71 .get_field(exif::Tag::Orientation, exif::In::PRIMARY)
72 .and_then(|field| field.value.get_uint(0))
73 .and_then(|value| u8::try_from(value).ok())
74 .map(|value| match value {
75 1 => Operation::empty(),
76 2 => Operation::FLIP_HORIZONTALLY,
77 3 => Operation::ROTATE_180,
78 4 => Operation::FLIP_VERTICALLY,
79 5 => Operation::ROTATE_90 | Operation::FLIP_HORIZONTALLY,
80 6 => Operation::ROTATE_90,
81 7 => Operation::ROTATE_90 | Operation::FLIP_VERTICALLY,
82 8 => Operation::ROTATE_270,
83 _ => Operation::empty(),
84 })
85 .unwrap_or_else(Self::empty))
86 }
87
88 fn perform(
89 self,
90 mut image: ::image::DynamicImage,
91 ) -> ::image::DynamicImage {
92 use ::image::imageops;
93
94 if self.contains(Operation::ROTATE_90) {
95 image = imageops::rotate90(&image).into();
96 }
97
98 if self.contains(Self::ROTATE_180) {
99 imageops::rotate180_in_place(&mut image);
100 }
101
102 if self.contains(Operation::ROTATE_270) {
103 image = imageops::rotate270(&image).into();
104 }
105
106 if self.contains(Self::FLIP_VERTICALLY) {
107 imageops::flip_vertical_in_place(&mut image);
108 }
109
110 if self.contains(Self::FLIP_HORIZONTALLY) {
111 imageops::flip_horizontal_in_place(&mut image);
112 }
113
114 image
115 }
116 }
117
118 let (width, height, pixels) = match handle {
119 image::Handle::Path(_, path) => {
120 let image = ::image::open(path).map_err(to_error)?;
121
122 let operation = std::fs::File::open(path)
123 .ok()
124 .map(std::io::BufReader::new)
125 .and_then(|mut reader| Operation::from_exif(&mut reader).ok())
126 .unwrap_or_else(Operation::empty);
127
128 let rgba = operation.perform(image).into_rgba8();
129
130 (
131 rgba.width(),
132 rgba.height(),
133 image::Bytes::from(rgba.into_raw()),
134 )
135 }
136 image::Handle::Bytes(_, bytes) => {
137 let image = ::image::load_from_memory(bytes).map_err(to_error)?;
138
139 let operation =
140 Operation::from_exif(&mut std::io::Cursor::new(bytes))
141 .ok()
142 .unwrap_or_else(Operation::empty);
143
144 let rgba = operation.perform(image).into_rgba8();
145
146 (
147 rgba.width(),
148 rgba.height(),
149 image::Bytes::from(rgba.into_raw()),
150 )
151 }
152 image::Handle::Rgba {
153 width,
154 height,
155 pixels,
156 ..
157 } => (*width, *height, pixels.clone()),
158 };
159
160 if let Some(image) = ::image::ImageBuffer::from_raw(width, height, pixels) {
161 Ok(image)
162 } else {
163 Err(to_error(::image::error::ImageError::Limits(
164 ::image::error::LimitError::from_kind(
165 ::image::error::LimitErrorKind::DimensionError,
166 ),
167 )))
168 }
169}
170
171#[cfg(feature = "image")]
172fn to_error(error: ::image::ImageError) -> image::Error {
173 use std::sync::Arc;
174
175 match error {
176 ::image::ImageError::IoError(error) => {
177 image::Error::Inaccessible(Arc::new(error))
178 }
179 error => image::Error::Invalid(Arc::new(error)),
180 }
181}