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