native_windows_gui2/resources/
image_decoder.rs

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