native_windows_gui/resources/
bitmap.rs

1use winapi::um::winnt::HANDLE;
2use winapi::um::winuser::IMAGE_BITMAP;
3use crate::win32::resources_helper as rh;
4use crate::{OemBitmap, OemImage, NwgError};
5use std::ptr;
6
7#[cfg(feature = "embed-resource")]
8use super::EmbedResource;
9
10/** 
11A wrapper over a bitmap file (*.bmp)
12
13Note that Bitmap object are only used as display resources (ie: it's impossible to read pixels or resized it).
14If those features are needed, see the `image-decoder` feature.
15
16To display a bitmap in an application, see the `ImageFrame` control.
17
18By default, bitmap resources do not support transparency BUT if `image-decoder` is enabled, bitmaps can be loaded
19from any file type supported natively by Windows: `JPEG, PNG, BMP, ICO, DDS, TIFF`.
20
21Bitmaps can be converted to icons using the "copy_as_icon" function.
22
23
24**Builder parameters:**
25  * `source_file`:      The source of the bitmap if it is a file.
26  * `source_bin`:       The source of the bitmap if it is a binary blob. For example using `include_bytes!("my_icon.bmp")`.
27  * `source_system`:    The source of the bitmap if it is a system resource (see OemBitmap)
28  * `source_embed`:     The source of the bitmap if it is stored in an embedded file
29  * `source_embed_id`:  The number identifier of the icon in the embedded file
30  * `source_embed_str`: The string identifier of the icon in the embedded file
31  * `size`:             Optional. Resize the image to this size.
32  * `strict`:           Use a system placeholder instead of panicking if the image source do no exists.
33
34Example:
35
36```rust
37use native_windows_gui as nwg;
38
39fn load_bitmap() -> nwg::Bitmap {
40    nwg::Bitmap::from_file("Hello.bmp", true).unwrap()
41}
42
43fn load_bitmap_builder() -> nwg::Bitmap {
44    let mut bitmap = nwg::Bitmap::default();
45
46    nwg::Bitmap::builder()
47        .source_file(Some("Hello.bmp"))
48        .strict(true)
49        .build(&mut bitmap)
50        .unwrap();
51
52    bitmap
53}
54
55```
56
57*/
58#[allow(unused)]
59pub struct Bitmap {
60    pub handle: HANDLE,
61    pub(crate) owned: bool
62}
63
64impl Bitmap {
65
66    pub fn builder<'a>() -> BitmapBuilder<'a> {
67        BitmapBuilder {
68            source_text: None,
69            source_bin: None,
70            source_system: None,
71
72            #[cfg(feature = "embed-resource")]
73            source_embed: None,
74
75            #[cfg(feature = "embed-resource")]
76            source_embed_id: 0,
77
78            #[cfg(feature = "embed-resource")]
79            source_embed_str: None,
80
81            size: None,
82            strict: false
83        }
84    }
85
86    /**
87        Single line helper function over the bitmap builder api.
88
89        Use system resources.
90    */
91    pub fn from_system(sys_bitmap: OemBitmap) -> Bitmap {
92        let mut bitmap = Self::default();
93
94        // Default cursor creation cannot fail
95        Self::builder()
96            .source_system(Some(sys_bitmap))
97            .build(&mut bitmap)
98            .unwrap();
99
100            bitmap
101    }
102
103    /**
104        Single line helper function over the bitmap builder api.
105
106        Use a file resource.
107    */
108    pub fn from_file(path: &str, strict: bool) -> Result<Bitmap, NwgError> {
109        let mut bitmap = Bitmap::default();
110
111        Bitmap::builder()
112            .source_file(Some(path))
113            .strict(strict)
114            .build(&mut bitmap)?;
115
116        Ok(bitmap)
117    }
118
119    /**
120        Single line helper function over the bitmap builder api.
121
122        Use a binary resource.
123    */
124    pub fn from_bin(bin: &[u8]) -> Result<Bitmap, NwgError> {
125        let mut bitmap = Bitmap::default();
126
127        Bitmap::builder()
128            .source_bin(Some(bin))
129            .build(&mut bitmap)?;
130
131        Ok(bitmap)
132    }
133
134    /**
135        Single line helper function over the bitmap builder api.
136
137        Use an embedded resource. Either `embed_id` or `embed_str` must be defined, not both.
138
139        Requires the `embed-resource` feature.
140    */
141    #[cfg(feature = "embed-resource")]
142    pub fn from_embed(embed: &EmbedResource, embed_id: Option<usize>, embed_str: Option<&str>) -> Result<Bitmap, NwgError> {
143        let mut bitmap = Bitmap::default();
144
145        Bitmap::builder()
146            .source_embed(Some(embed))
147            .source_embed_id(embed_id.unwrap_or(0))
148            .source_embed_str(embed_str)
149            .build(&mut bitmap)?;
150
151        Ok(bitmap)
152    }
153
154    /**
155        Creates a new icon from the bitmap data.
156        
157        Panics if the bitmap is not initialized
158    */
159    pub fn copy_as_icon(&self) -> crate::Icon {
160        use winapi::um::winuser::CreateIconIndirect;
161        use winapi::um::winuser::ICONINFO;
162
163        if self.handle.is_null() {
164            panic!("Bitmap was not initialized");
165        }
166
167        let mut icon_info = ICONINFO {
168            fIcon: 1,
169            xHotspot: 0,
170            yHotspot: 0,
171            hbmMask: self.handle as _,
172            hbmColor: self.handle as _
173        };
174
175        let icon = unsafe { CreateIconIndirect(&mut icon_info) };
176
177        crate::Icon {
178            handle: icon as _,
179            owned: true
180        }
181    }
182
183}
184
185pub struct BitmapBuilder<'a> {
186    source_text: Option<&'a str>,
187    source_bin: Option<&'a [u8]>,
188    source_system: Option<OemBitmap>,
189
190    #[cfg(feature = "embed-resource")]
191    source_embed: Option<&'a EmbedResource>,
192
193    #[cfg(feature = "embed-resource")]
194    source_embed_id: usize,
195
196    #[cfg(feature = "embed-resource")]
197    source_embed_str: Option<&'a str>,
198    
199    size: Option<(u32, u32)>,
200    strict: bool,
201}
202
203impl<'a> BitmapBuilder<'a> {
204
205    pub fn source_file(mut self, t: Option<&'a str>) -> BitmapBuilder<'a> {
206        self.source_text = t;
207        self
208    }
209
210    pub fn source_bin(mut self, t: Option<&'a [u8]>) -> BitmapBuilder<'a> {
211        self.source_bin = t;
212        self
213    }
214
215    pub fn source_system(mut self, t: Option<OemBitmap>) -> BitmapBuilder<'a> {
216        self.source_system = t;
217        self
218    }
219
220    #[cfg(feature = "embed-resource")]
221    pub fn source_embed(mut self, em: Option<&'a EmbedResource>) -> BitmapBuilder<'a> {
222        self.source_embed = em;
223        self
224    }
225
226    #[cfg(feature = "embed-resource")]
227    pub fn source_embed_id(mut self, id: usize) -> BitmapBuilder<'a> {
228        self.source_embed_id = id;
229        self
230    }
231
232    #[cfg(feature = "embed-resource")]
233    pub fn source_embed_str(mut self, id: Option<&'a str>) -> BitmapBuilder<'a> {
234        self.source_embed_str = id;
235        self
236    }
237
238    pub fn size(mut self, s: Option<(u32, u32)>) -> BitmapBuilder<'a> {
239        self.size = s;
240        self
241    }
242
243    pub fn strict(mut self, s: bool) -> BitmapBuilder<'a> {
244        self.strict = s;
245        self
246    }
247
248    pub fn build(self, b: &mut Bitmap) -> Result<(), NwgError> {
249        if let Some(src) = self.source_text {
250            let handle = unsafe { 
251                #[cfg(feature="image-decoder")]
252                let handle = rh::build_image_decoder(src, self.size, self.strict, IMAGE_BITMAP);
253
254                #[cfg(not(feature="image-decoder"))]
255                let handle = rh::build_image(src, self.size, self.strict, IMAGE_BITMAP);
256
257                handle?
258            };
259
260            *b = Bitmap { handle, owned: true };
261        } else if let Some(src) = self.source_system {
262            let handle = unsafe { rh::build_oem_image(OemImage::Bitmap(src), self.size)? };
263            *b = Bitmap { handle, owned: true };
264        } else if let Some(src) = self.source_bin { 
265            let handle = unsafe { rh::bitmap_from_memory(src)? };
266
267            *b = Bitmap { handle, owned: true };
268        } else {
269            #[cfg(all(feature = "embed-resource", feature="image-decoder"))]
270            fn build_embed(builder: BitmapBuilder) -> Result<Bitmap, NwgError> {
271                match builder.source_embed {
272                    Some(embed) => {
273                        match builder.source_embed_str {
274                            Some(src) => embed.image_str(src, builder.size)
275                                .ok_or_else(|| NwgError::resource_create(format!("No bitmap in embed resource identified by {}", src))),
276                            None => embed.image(builder.source_embed_id, builder.size)
277                                .ok_or_else(|| NwgError::resource_create(format!("No bitmap in embed resource identified by {}", builder.source_embed_id)))
278                        }
279                    },
280                    None => Err(NwgError::resource_create("No source provided for Bitmap"))
281                }
282            }
283
284            #[cfg(feature = "embed-resource")]
285            #[cfg(not(feature = "image-decoder"))]
286            fn build_embed(builder: BitmapBuilder) -> Result<Bitmap, NwgError> {
287                match builder.source_embed {
288                    Some(embed) => {
289                        match builder.source_embed_str {
290                            Some(src) => embed.bitmap_str(src, builder.size)
291                                .ok_or_else(|| NwgError::resource_create(format!("No bitmap in embed resource identified by {}", src))),
292                            None => embed.bitmap(builder.source_embed_id, builder.size)
293                                .ok_or_else(|| NwgError::resource_create(format!("No bitmap in embed resource identified by {}", builder.source_embed_id)))
294                        }
295                    },
296                    None => Err(NwgError::resource_create("No source provided for Bitmap"))
297                }
298            }
299
300            #[cfg(not(feature = "embed-resource"))]
301            fn build_embed(_builder: BitmapBuilder) -> Result<Bitmap, NwgError> {
302                Err(NwgError::resource_create("No source provided for Bitmap"))
303            }
304
305            *b = build_embed(self)?;
306        }
307    
308        Ok(())
309    }
310
311}
312
313
314impl Default for Bitmap {
315
316    fn default() -> Bitmap {
317        Bitmap {
318            handle: ptr::null_mut(),
319            owned: false
320        }
321    }
322
323}
324
325impl PartialEq for Bitmap {
326
327    fn eq(&self, other: &Self) -> bool {
328        self.handle == other.handle
329    }
330
331}
332
333impl Drop for Bitmap {
334
335    fn drop(&mut self) {
336        if self.owned && !self.handle.is_null() {
337            rh::destroy_obj(self.handle);
338        }
339    }
340
341}