fe_image_widget/
lib.rs

1use fltk_egui::{
2    egui::{Image, TextureId, Vec2},
3    Painter,
4};
5
6#[cfg(any(
7    feature = "png",
8    feature = "jpeg",
9    feature = "jpeg_rayon",
10    feature = "bmp",
11    feature = "ico",
12    feature = "gif",
13    feature = "webp",
14    feature = "tga",
15    feature = "pnm",
16    feature = "hdr",
17    feature = "dxt",
18    feature = "dds",
19    feature = "farbfeld"
20))]
21use image::{GenericImageView, ImageError};
22
23#[cfg(any(
24    feature = "svg",
25    feature = "png",
26    feature = "jpeg",
27    feature = "jpeg_rayon",
28    feature = "bmp",
29    feature = "ico",
30    feature = "gif",
31    feature = "webp",
32    feature = "tga",
33    feature = "pnm",
34    feature = "hdr",
35    feature = "dxt",
36    feature = "dds",
37    feature = "farbfeld"
38))]
39pub struct ImageWidget {
40    texture_id: TextureId,
41    _size: Vec2,
42}
43
44#[cfg(any(
45    feature = "png",
46    feature = "jpeg",
47    feature = "jpeg_rayon",
48    feature = "bmp",
49    feature = "ico",
50    feature = "gif",
51    feature = "webp",
52    feature = "tga",
53    feature = "pnm",
54    feature = "hdr",
55    feature = "dxt",
56    feature = "dds",
57    feature = "farbfeld"
58))]
59impl Clone for ImageWidget {
60    fn clone(&self) -> Self {
61        Self {
62            texture_id: self.texture_id.clone(),
63            _size: self._size.clone(),
64        }
65    }
66}
67
68#[cfg(any(
69    feature = "png",
70    feature = "jpeg",
71    feature = "jpeg_rayon",
72    feature = "bmp",
73    feature = "ico",
74    feature = "gif",
75    feature = "webp",
76    feature = "tga",
77    feature = "pnm",
78    feature = "hdr",
79    feature = "dxt",
80    feature = "dds",
81    feature = "farbfeld"
82))]
83impl Drop for ImageWidget {
84    fn drop(&mut self) {}
85}
86
87#[cfg(any(
88    feature = "png",
89    feature = "jpeg",
90    feature = "jpeg_rayon",
91    feature = "bmp",
92    feature = "ico",
93    feature = "gif",
94    feature = "webp",
95    feature = "tga",
96    feature = "pnm",
97    feature = "hdr",
98    feature = "dxt",
99    feature = "dds",
100    feature = "farbfeld"
101))]
102impl ImageWidget {
103    pub fn texture_id(&self) -> TextureId {
104        self.texture_id
105    }
106
107    pub fn size(&self) -> Vec2 {
108        self._size
109    }
110
111    pub fn widget(&self) -> Image {
112        Image::new(self.texture_id, self.size())
113    }
114
115    pub fn resize(&mut self, x: f32, y: f32) {
116        self._size.x = x;
117        self._size.y = y
118    }
119
120    pub fn set_size_x(&mut self, x: f32) {
121        self._size.x = x;
122    }
123
124    pub fn set_size_y(&mut self, y: f32) {
125        self._size.y = y
126    }
127
128    /// Create new image from bytes (image-format support will adapt according to the enabled features).
129    pub fn new(painter: &mut Painter, bytes: &[u8]) -> Result<Self, ImageError> {
130        let pixels;
131        let size;
132        {
133            let dyn_image = image::load_from_memory(bytes)?;
134            size = (dyn_image.width() as usize, dyn_image.height() as usize);
135            pixels = dyn_image.into_rgba8().to_vec();
136        }
137        let tex = painter.new_user_texture_rgba8(size, pixels, true);
138        let feimage = Self {
139            texture_id: tex,
140            _size: Vec2::from((size.0 as f32, size.1 as f32)),
141        };
142        Ok(feimage)
143    }
144
145    /// Update with new image from bytes.
146    pub fn update_image(&mut self, painter: &mut Painter, bytes: &[u8]) -> Result<(), ImageError> {
147        let pixels;
148        let size;
149        {
150            let dyn_image = image::load_from_memory(bytes)?;
151            size = (dyn_image.width() as usize, dyn_image.height() as usize);
152            pixels = dyn_image.into_rgba8().to_vec();
153        }
154        painter.update_user_texture_rgba8_data(self.texture_id, pixels);
155        self._size = Vec2::from((size.0 as f32, size.1 as f32));
156        Ok(())
157    }
158}
159
160#[cfg(any(
161    feature = "png",
162    feature = "jpeg",
163    feature = "jpeg_rayon",
164    feature = "bmp",
165    feature = "ico",
166    feature = "gif",
167    feature = "webp",
168    feature = "tga",
169    feature = "pnm",
170    feature = "hdr",
171    feature = "dxt",
172    feature = "dds",
173    feature = "farbfeld"
174))]
175impl Into<SVGWidget> for ImageWidget {
176    fn into(self) -> SVGWidget {
177        SVGWidget {
178            texture_id: self.texture_id,
179            _size: self._size,
180        }
181    }
182}
183
184#[cfg(any(
185    feature = "png",
186    feature = "jpeg",
187    feature = "jpeg_rayon",
188    feature = "bmp",
189    feature = "ico",
190    feature = "gif",
191    feature = "webp",
192    feature = "tga",
193    feature = "pnm",
194    feature = "hdr",
195    feature = "dxt",
196    feature = "dds",
197    feature = "farbfeld"
198))]
199impl From<SVGWidget> for ImageWidget {
200    fn from(t: SVGWidget) -> ImageWidget {
201        ImageWidget {
202            texture_id: t.texture_id,
203            _size: t._size,
204        }
205    }
206}
207
208#[cfg(feature = "svg")]
209use resvg::render;
210#[cfg(feature = "svg")]
211use std::io::{Error, ErrorKind};
212#[cfg(feature = "svg")]
213use tiny_skia::Pixmap;
214#[cfg(feature = "svg")]
215pub use usvg::Options;
216#[cfg(feature = "svg")]
217use usvg::{OptionsRef, Tree};
218
219#[cfg(any(
220    feature = "svg",
221    feature = "png",
222    feature = "jpeg",
223    feature = "jpeg_rayon",
224    feature = "bmp",
225    feature = "ico",
226    feature = "gif",
227    feature = "webp",
228    feature = "tga",
229    feature = "pnm",
230    feature = "hdr",
231    feature = "dxt",
232    feature = "dds",
233    feature = "farbfeld"
234))]
235pub struct SVGWidget {
236    texture_id: TextureId,
237    _size: Vec2,
238}
239
240#[cfg(feature = "svg")]
241impl Clone for SVGWidget {
242    fn clone(&self) -> Self {
243        Self {
244            texture_id: self.texture_id.clone(),
245            _size: self._size.clone(),
246        }
247    }
248}
249
250#[cfg(feature = "svg")]
251impl Drop for SVGWidget {
252    fn drop(&mut self) {}
253}
254
255#[cfg(feature = "svg")]
256impl SVGWidget {
257    pub fn texture_id(&self) -> TextureId {
258        self.texture_id
259    }
260
261    pub fn size(&self) -> Vec2 {
262        self._size
263    }
264
265    pub fn widget(&self) -> Image {
266        Image::new(self.texture_id, self.size())
267    }
268
269    pub fn resize(&mut self, x: f32, y: f32) {
270        self._size.x = x;
271        self._size.y = y
272    }
273
274    pub fn set_size_x(&mut self, x: f32) {
275        self._size.x = x;
276    }
277
278    pub fn set_size_y(&mut self, y: f32) {
279        self._size.y = y
280    }
281
282    /// Create new svg image from bytes.
283    pub fn new(painter: &mut Painter, bytes: &[u8], opt_ref: OptionsRef) -> Result<Self, Error> {
284        let rtree = match Tree::from_data(&bytes, &opt_ref) {
285            Ok(rtree) => rtree,
286            Err(e) => {
287                let err = Error::new(ErrorKind::Other, e.to_string());
288                return Err(err);
289            }
290        };
291        let pixels;
292        let size;
293        {
294            let pixmap_size = rtree.svg_node().size.to_screen_size();
295            let mut pixmap = match Pixmap::new(pixmap_size.width(), pixmap_size.height()) {
296                Some(pixmap) => pixmap,
297                _ => {
298                    let err = Error::new(ErrorKind::Other, "while mapping SVG pixels!");
299                    return Err(err);
300                }
301            };
302
303            {
304                if render(&rtree, usvg::FitTo::Original, pixmap.as_mut()).is_none() {
305                    let err = Error::new(ErrorKind::Other, "while rendering SVG data!");
306                    return Err(err);
307                }
308            }
309            size = (pixmap_size.width() as usize, pixmap_size.height() as usize);
310            pixels = pixmap.data().to_vec();
311        }
312        let tex = painter.new_user_texture_rgba8(size, pixels, true);
313        let feimage = Self {
314            texture_id: tex,
315            _size: Vec2::from((size.0 as f32, size.1 as f32)),
316        };
317        Ok(feimage)
318    }
319
320    /// Update with new svg image from bytes.
321    pub fn update_svg(
322        &mut self,
323        painter: &mut Painter,
324        bytes: &[u8],
325        opt_ref: OptionsRef,
326    ) -> Result<(), Error> {
327        let rtree = match Tree::from_data(&bytes, &opt_ref) {
328            Ok(rtree) => rtree,
329            Err(e) => {
330                let err = Error::new(ErrorKind::Other, e.to_string());
331                return Err(err);
332            }
333        };
334        let pixels;
335        let size;
336        {
337            let pixmap_size = rtree.svg_node().size.to_screen_size();
338            let mut pixmap = match Pixmap::new(pixmap_size.width(), pixmap_size.height()) {
339                Some(pixmap) => pixmap,
340                _ => {
341                    let err = Error::new(ErrorKind::Other, "while mapping SVG pixels!");
342                    return Err(err);
343                }
344            };
345
346            {
347                if render(&rtree, usvg::FitTo::Original, pixmap.as_mut()).is_none() {
348                    let err = Error::new(ErrorKind::Other, "while rendering SVG data!");
349                    return Err(err);
350                }
351            }
352
353            size = (pixmap_size.width() as usize, pixmap_size.height() as usize);
354            pixels = pixmap.data().to_vec();
355        }
356        painter.update_user_texture_rgba8_data(self.texture_id, pixels);
357        self._size = Vec2::from((size.0 as f32, size.1 as f32));
358        Ok(())
359    }
360}
361
362#[cfg(feature = "svg")]
363impl Into<ImageWidget> for SVGWidget {
364    fn into(self) -> ImageWidget {
365        ImageWidget {
366            texture_id: self.texture_id,
367            _size: self._size,
368        }
369    }
370}
371
372#[cfg(feature = "svg")]
373impl From<ImageWidget> for SVGWidget {
374    fn from(t: ImageWidget) -> SVGWidget {
375        SVGWidget {
376            texture_id: t.texture_id,
377            _size: t._size,
378        }
379    }
380}