native_windows_gui/resources/
image_decoder.rs

1use winapi::um::wincodec::{IWICImagingFactory, IWICBitmapDecoder, IWICBitmapSource, WICPixelFormatGUID};
2use winapi::shared::winerror::S_OK;
3use crate::win32::image_decoder as img;
4use crate::{NwgError, Bitmap};
5use std::{ptr, mem};
6
7
8/**
9    A image decoder. Can load an extended number of image file format from a filename, from a file handle, or from a stream.
10
11    ImageDecoder do not take any parameter to build, but it still provides a builder API to match the other component of NWG.
12    You can also use "ImageDecoder::new" to avoid the builder API.
13
14    There's not much reason to have more than 1 image decoder per application.
15
16    Images loaded from a decoder cannot be used as-is by an image frame. They must first be converted to a bitmap resource.
17
18    ```rust
19    use native_windows_gui as nwg;
20    fn open_image(decoder: &nwg::ImageDecoder) -> Result<nwg::ImageData, nwg::NwgError> {
21        decoder
22            .from_filename("corn.png")?
23            .frame(0)
24    }
25    ```
26
27    ```rust
28    use native_windows_gui as nwg;
29    fn build_image_decode(decode: &mut nwg::ImageDecoder) -> Result<(), nwg::NwgError> {
30        nwg::ImageDecoder::builder()
31            .build(decode)
32    }
33    ```
34*/
35pub struct ImageDecoder {
36    pub factory: *mut IWICImagingFactory,
37}
38
39impl ImageDecoder {
40    pub fn new() -> Result<ImageDecoder, NwgError> {
41        let factory = unsafe { img::create_image_factory() }?;
42        Ok(ImageDecoder { factory })
43    }
44
45    pub fn builder() -> ImageDecoderBuilder {
46        ImageDecoderBuilder {
47        }
48    }
49
50    /**
51        Try to read an image from a file path.
52        The file type can be any of the native WIC codecs (https://docs.microsoft.com/en-us/windows/win32/wic/native-wic-codecs)
53
54        * If there is an error during the decoding, returns a NwgError.
55        * If the image decoder was not initialized, this method panics
56
57        This method returns a ImageSource object
58    */
59    pub fn from_filename<'a>(&self, path: &'a str) -> Result<ImageSource, NwgError> {
60        if self.factory.is_null() {
61            panic!("ImageDecoder is not yet bound to a winapi object");
62        }
63
64        let decoder = unsafe { img::create_decoder_from_file(&*self.factory, path) }?;
65
66        Ok(ImageSource { decoder })
67    }
68
69    /**
70        Build an image from a stream of data.
71        The file type can be any of the native WIC codecs (https://docs.microsoft.com/en-us/windows/win32/wic/native-wic-codecs)
72
73        * If there is an error during the decoding, returns a NwgError.
74        * If the image decoder was not initialized, this method panics
75
76        This method copies the bytes and returns a ImageSource object
77    */
78    pub fn from_stream(&self, stream: &[u8]) -> Result<ImageSource, NwgError> {
79        if self.factory.is_null() {
80            panic!("ImageDecoder is not yet bound to a winapi object");
81        }
82
83        let decoder = unsafe { img::create_decoder_from_stream(&*self.factory, stream) }?;
84
85        Ok(ImageSource { decoder })
86    }
87
88    /**
89        Resize an image, returning the new resized image. The pixel format might change.
90    */
91    pub fn resize_image(&self, image: &ImageData, new_size: [u32;2]) -> Result<ImageData, NwgError> {
92        unsafe { img::resize_bitmap(&*self.factory, image, new_size) }
93    }
94
95}
96
97
98/**
99    Represents a image data source in read only mode.
100*/
101pub struct ImageSource {
102    pub decoder: *mut IWICBitmapDecoder,
103}
104
105impl ImageSource {
106
107    /**
108        Return the number of frame in the image. For most format (ex: PNG), this will be 1.
109        It might be more than 1 in animated image formats (such as GIFs).
110    */
111    pub fn frame_count(&self) -> u32 {
112        let mut frame_count = 0;
113        unsafe { (&*self.decoder).GetFrameCount(&mut frame_count); }
114        frame_count
115    }
116
117    /**
118        Return the image data of the requested frame in a ImageData object.
119    */
120    pub fn frame(&self, index: u32) -> Result<ImageData, NwgError> {
121        let mut bitmap = ptr::null_mut();
122        let hr = unsafe { (&*self.decoder).GetFrame(index, &mut bitmap) };
123        match hr {
124            S_OK => Ok(ImageData { frame: bitmap as *mut IWICBitmapSource }),
125            err => Err(NwgError::image_decoder(err, "Could not read image frame"))
126        }
127    }
128
129    /*  Retrieves the container format of the image source. 
130
131        See https://docs.microsoft.com/en-us/windows/win32/wic/-wic-guids-clsids#container-formats
132    */
133    pub fn container_format(&self) -> ContainerFormat {
134        use ContainerFormat::*;
135        let mut container = unsafe { mem::zeroed() };
136        unsafe { (&*self.decoder).GetContainerFormat(&mut container) };
137
138        // Just use the first field of the GUID because the winapi type does no implement EQ
139        match container.Data1 {
140            0xf3ff6d0d => Adng,
141            0xaf1d87e => Bmp,
142            0x1b7cfaf4 => Png,
143            0xa3a860c4 => Ico,
144            0x19e4a5aa => Jpeg,
145            0x163bcc30 => Tiff,
146            0x1f8a5601 => Gif,
147            0x57a37caa => Wmp,
148            _ => Unknown
149        }
150
151    }
152
153}
154
155
156/**
157    Represents a source of pixel that can be read, but cannot be written back to.
158*/
159pub struct ImageData {
160    pub frame: *mut IWICBitmapSource
161}
162
163impl ImageData {
164
165    /// Retrieves the sampling rate between pixels and physical world measurements.
166    pub fn resolution(&self) -> (f64, f64) {
167        let (mut rx, mut ry) = (0.0, 0.0);
168        unsafe { (&*self.frame).GetResolution(&mut rx, &mut ry) };
169        (rx, ry)
170    }  
171    
172    /// Retrieves the pixel width and height of the bitmap.
173    pub fn size(&self) -> (u32, u32) {
174        let (mut sx, mut sy) = (0, 0);
175        unsafe { (&*self.frame).GetSize(&mut sx, &mut sy) };
176        (sx, sy)
177    }
178
179    /*  Retrieves the pixel format of the bitmap source. Returns a GUID, Match it to the GUID defined in the link below:
180
181        See https://docs.microsoft.com/en-us/windows/win32/wic/-wic-codec-native-pixel-formats#undefined-pixel-formats
182    */
183    pub fn pixel_format(&self) -> WICPixelFormatGUID {
184        let mut fmt = unsafe { mem::zeroed() };
185        unsafe { (&*self.frame).GetPixelFormat(&mut fmt) };
186        fmt
187    }
188
189    /**
190        Copy the frame pixels into a buffer.
191
192        Parameters:
193            pixel_size: defines the size of a pixel in bytes. In a typical RGBA image, this would be 4 (1 byte for each component).
194                        If unsure, use the pixel_format.
195
196        May return an error if the pixel data could not be read
197    */
198    pub fn pixels(&self, pixel_size: u32) -> Result<Vec<u8>, NwgError> {
199        let (w, h) = self.size();
200        let scanline = w * pixel_size;
201        let buffer_size = (w * h * pixel_size) as usize;
202        let mut buffer: Vec<u8> = Vec::with_capacity(buffer_size);
203        
204        let hr = unsafe {
205            buffer.set_len(buffer_size);
206            (&*self.frame).CopyPixels(ptr::null(), scanline, buffer_size as u32, buffer.as_mut_ptr())
207        };
208
209        match hr {
210            S_OK => Ok(buffer),
211            err => Err(NwgError::image_decoder(err, "Could not read image pixels"))
212        }
213    }
214
215    /**
216        Copy a region of the frames pixel into a buffer.
217
218        Parameters:
219            offset: The [x,y] offset at which the region begins
220            size: The [width, height] size of the region
221            pixel_size: defines the size of a pixel in bytes. In a typical RGBA image, this would be 4 (1 byte for each component).
222                        If unsure, use the pixel_format.
223
224        May return an error if the pixel data could not be read
225    */
226    pub fn region_pixels(&self, offset: [i32;2], size: [i32;2], pixel_size: u32) -> Result<Vec<u8>, NwgError> {
227        use winapi::um::wincodec::WICRect;
228
229        let [x, y] = offset;
230        let [w, h] = size;
231        let scanline = (w as u32) * pixel_size;
232        let buffer_size = (scanline * (h as u32)) as usize;
233        let mut buffer: Vec<u8> = Vec::with_capacity(buffer_size);
234
235        let region = WICRect { X: x, Y: y, Width: w, Height: h };
236        
237        let hr = unsafe {
238            buffer.set_len(buffer_size);
239            (&*self.frame).CopyPixels(&region, scanline, buffer_size as u32, buffer.as_mut_ptr())
240        };
241
242        match hr {
243            S_OK => Ok(buffer),
244            err => Err(NwgError::image_decoder(err, "Could not read image pixels"))
245        }
246    }
247
248    /**
249        Create a bitmap resource the the image data. This resource can then be used in the other NWG component.
250        The bitmap returned is considered "owned".
251    */
252    pub fn as_bitmap(&self) -> Result<Bitmap, NwgError> {
253        unsafe { img::create_bitmap_from_wic(self) }
254    }
255
256}
257
258/// A list of container format implemented in WIC
259#[derive(Copy, Clone, Debug, PartialEq, Eq)]
260pub enum ContainerFormat {
261    Unknown,
262    Adng,
263    Bmp,
264    Png,
265    Ico,
266    Jpeg,
267    Tiff,
268    Gif,
269    Wmp,
270}
271
272//
273// IMPL
274//
275
276impl Default for ImageDecoder {
277    fn default() -> ImageDecoder {
278        ImageDecoder {
279            factory: ptr::null_mut()
280        }
281    }
282}
283
284impl Drop for ImageDecoder {
285    fn drop(&mut self) {
286        if !self.factory.is_null() {
287            unsafe { (&*self.factory).Release(); }
288        }
289    }
290}
291
292impl Drop for ImageSource {
293    fn drop(&mut self) {
294        unsafe { (&*self.decoder).Release(); }
295    }
296}
297
298impl Drop for ImageData {
299    fn drop(&mut self) {
300        unsafe { (&*self.frame).Release(); }
301    }
302}
303
304
305/**
306    A blank builder for the image decoder
307*/
308pub struct ImageDecoderBuilder {
309}
310
311impl ImageDecoderBuilder {
312    pub fn build(self, out: &mut ImageDecoder) -> Result<(), NwgError> {
313        let factory = unsafe { img::create_image_factory() }?;
314        *out = ImageDecoder { factory };
315        Ok(())
316    }
317}