Skip to main content

native_windows_gui2/resources/
bitmap.rs

1use crate::win32::resources_helper as rh;
2use crate::{NwgError, OemBitmap, OemImage};
3use std::ptr;
4use winapi::um::winnt::HANDLE;
5use winapi::um::winuser::IMAGE_BITMAP;
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_gui2 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    pub fn builder<'a>() -> BitmapBuilder<'a> {
66        BitmapBuilder {
67            source_text: None,
68            source_bin: None,
69            source_system: None,
70
71            #[cfg(feature = "embed-resource")]
72            source_embed: None,
73
74            #[cfg(feature = "embed-resource")]
75            source_embed_id: 0,
76
77            #[cfg(feature = "embed-resource")]
78            source_embed_str: None,
79
80            size: None,
81            strict: false,
82        }
83    }
84
85    /**
86        Single line helper function over the bitmap builder api.
87
88        Use system resources.
89    */
90    pub fn from_system(sys_bitmap: OemBitmap) -> Bitmap {
91        let mut bitmap = Self::default();
92
93        // Default cursor creation cannot fail
94        Self::builder()
95            .source_system(Some(sys_bitmap))
96            .build(&mut bitmap)
97            .unwrap();
98
99        bitmap
100    }
101
102    /**
103        Single line helper function over the bitmap builder api.
104
105        Use a file resource.
106    */
107    pub fn from_file(path: &str, strict: bool) -> Result<Bitmap, NwgError> {
108        let mut bitmap = Bitmap::default();
109
110        Bitmap::builder()
111            .source_file(Some(path))
112            .strict(strict)
113            .build(&mut bitmap)?;
114
115        Ok(bitmap)
116    }
117
118    /**
119        Single line helper function over the bitmap builder api.
120
121        Use a binary resource.
122    */
123    pub fn from_bin(bin: &[u8]) -> Result<Bitmap, NwgError> {
124        let mut bitmap = Bitmap::default();
125
126        Bitmap::builder().source_bin(Some(bin)).build(&mut bitmap)?;
127
128        Ok(bitmap)
129    }
130
131    /**
132        Single line helper function over the bitmap builder api.
133
134        Use an embedded resource. Either `embed_id` or `embed_str` must be defined, not both.
135
136        Requires the `embed-resource` feature.
137    */
138    #[cfg(feature = "embed-resource")]
139    pub fn from_embed(
140        embed: &EmbedResource,
141        embed_id: Option<usize>,
142        embed_str: Option<&str>,
143    ) -> Result<Bitmap, NwgError> {
144        let mut bitmap = Bitmap::default();
145
146        Bitmap::builder()
147            .source_embed(Some(embed))
148            .source_embed_id(embed_id.unwrap_or(0))
149            .source_embed_str(embed_str)
150            .build(&mut bitmap)?;
151
152        Ok(bitmap)
153    }
154
155    /**
156        Creates a new icon from the bitmap data.
157
158        Panics if the bitmap is not initialized
159    */
160    pub fn copy_as_icon(&self) -> crate::Icon {
161        use winapi::um::winuser::CreateIconIndirect;
162        use winapi::um::winuser::ICONINFO;
163
164        if self.handle.is_null() {
165            panic!("Bitmap was not initialized");
166        }
167
168        let mut icon_info = ICONINFO {
169            fIcon: 1,
170            xHotspot: 0,
171            yHotspot: 0,
172            hbmMask: self.handle as _,
173            hbmColor: self.handle as _,
174        };
175
176        let icon = unsafe { CreateIconIndirect(&mut icon_info) };
177
178        crate::Icon {
179            handle: icon as _,
180            owned: true,
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    pub fn source_file(mut self, t: Option<&'a str>) -> BitmapBuilder<'a> {
205        self.source_text = t;
206        self
207    }
208
209    pub fn source_bin(mut self, t: Option<&'a [u8]>) -> BitmapBuilder<'a> {
210        self.source_bin = t;
211        self
212    }
213
214    pub fn source_system(mut self, t: Option<OemBitmap>) -> BitmapBuilder<'a> {
215        self.source_system = t;
216        self
217    }
218
219    #[cfg(feature = "embed-resource")]
220    pub fn source_embed(mut self, em: Option<&'a EmbedResource>) -> BitmapBuilder<'a> {
221        self.source_embed = em;
222        self
223    }
224
225    #[cfg(feature = "embed-resource")]
226    pub fn source_embed_id(mut self, id: usize) -> BitmapBuilder<'a> {
227        self.source_embed_id = id;
228        self
229    }
230
231    #[cfg(feature = "embed-resource")]
232    pub fn source_embed_str(mut self, id: Option<&'a str>) -> BitmapBuilder<'a> {
233        self.source_embed_str = id;
234        self
235    }
236
237    pub fn size(mut self, s: Option<(u32, u32)>) -> BitmapBuilder<'a> {
238        self.size = s;
239        self
240    }
241
242    pub fn strict(mut self, s: bool) -> BitmapBuilder<'a> {
243        self.strict = s;
244        self
245    }
246
247    pub fn build(self, b: &mut Bitmap) -> Result<(), NwgError> {
248        if let Some(src) = self.source_text {
249            let handle = unsafe {
250                #[cfg(feature = "image-decoder")]
251                let handle = rh::build_image_decoder(src, self.size, self.strict, IMAGE_BITMAP);
252
253                #[cfg(not(feature = "image-decoder"))]
254                let handle = rh::build_image(src, self.size, self.strict, IMAGE_BITMAP);
255
256                handle?
257            };
258
259            *b = Bitmap {
260                handle,
261                owned: true,
262            };
263        } else if let Some(src) = self.source_system {
264            let handle = unsafe { rh::build_oem_image(OemImage::Bitmap(src), self.size)? };
265            *b = Bitmap {
266                handle,
267                owned: true,
268            };
269        } else if let Some(src) = self.source_bin {
270            let handle = unsafe { rh::bitmap_from_memory(src)? };
271
272            *b = Bitmap {
273                handle,
274                owned: true,
275            };
276        } else {
277            #[cfg(all(feature = "embed-resource", feature = "image-decoder"))]
278            fn build_embed(builder: BitmapBuilder) -> Result<Bitmap, NwgError> {
279                match builder.source_embed {
280                    Some(embed) => match builder.source_embed_str {
281                        Some(src) => embed.image_str(src, builder.size).ok_or_else(|| {
282                            NwgError::resource_create(format!(
283                                "No bitmap in embed resource identified by {}",
284                                src
285                            ))
286                        }),
287                        None => embed
288                            .image(builder.source_embed_id, builder.size)
289                            .ok_or_else(|| {
290                                NwgError::resource_create(format!(
291                                    "No bitmap in embed resource identified by {}",
292                                    builder.source_embed_id
293                                ))
294                            }),
295                    },
296                    None => Err(NwgError::resource_create("No source provided for Bitmap")),
297                }
298            }
299
300            #[cfg(feature = "embed-resource")]
301            #[cfg(not(feature = "image-decoder"))]
302            fn build_embed(builder: BitmapBuilder) -> Result<Bitmap, NwgError> {
303                match builder.source_embed {
304                    Some(embed) => match builder.source_embed_str {
305                        Some(src) => embed.bitmap_str(src, builder.size).ok_or_else(|| {
306                            NwgError::resource_create(format!(
307                                "No bitmap in embed resource identified by {}",
308                                src
309                            ))
310                        }),
311                        None => embed
312                            .bitmap(builder.source_embed_id, builder.size)
313                            .ok_or_else(|| {
314                                NwgError::resource_create(format!(
315                                    "No bitmap in embed resource identified by {}",
316                                    builder.source_embed_id
317                                ))
318                            }),
319                    },
320                    None => Err(NwgError::resource_create("No source provided for Bitmap")),
321                }
322            }
323
324            #[cfg(not(feature = "embed-resource"))]
325            fn build_embed(_builder: BitmapBuilder) -> Result<Bitmap, NwgError> {
326                Err(NwgError::resource_create("No source provided for Bitmap"))
327            }
328
329            *b = build_embed(self)?;
330        }
331
332        Ok(())
333    }
334}
335
336impl Default for Bitmap {
337    fn default() -> Bitmap {
338        Bitmap {
339            handle: ptr::null_mut(),
340            owned: false,
341        }
342    }
343}
344
345impl PartialEq for Bitmap {
346    fn eq(&self, other: &Self) -> bool {
347        self.handle == other.handle
348    }
349}
350
351impl Drop for Bitmap {
352    fn drop(&mut self) {
353        if self.owned && !self.handle.is_null() {
354            rh::destroy_obj(self.handle);
355        }
356    }
357}