use winapi::um::wincodec::{IWICImagingFactory, IWICBitmapDecoder, IWICBitmapSource, WICPixelFormatGUID};
use winapi::shared::winerror::S_OK;
use crate::win32::image_decoder as img;
use crate::{NwgError, Bitmap};
use std::{ptr, mem};
pub struct ImageDecoder {
pub factory: *mut IWICImagingFactory,
}
impl ImageDecoder {
pub fn new() -> Result<ImageDecoder, NwgError> {
let factory = unsafe { img::create_image_factory() }?;
Ok(ImageDecoder { factory })
}
pub fn builder() -> ImageDecoderBuilder {
ImageDecoderBuilder {
}
}
pub fn from_filename<'a>(&self, path: &'a str) -> Result<ImageSource, NwgError> {
if self.factory.is_null() {
panic!("ImageDecoder is not yet bound to a winapi object");
}
let decoder = unsafe { img::create_decoder_from_file(&*self.factory, path) }?;
Ok(ImageSource { decoder })
}
pub fn from_stream(&self, stream: &[u8]) -> Result<ImageSource, NwgError> {
if self.factory.is_null() {
panic!("ImageDecoder is not yet bound to a winapi object");
}
let decoder = unsafe { img::create_decoder_from_stream(&*self.factory, stream) }?;
Ok(ImageSource { decoder })
}
pub fn resize_image(&self, image: &ImageData, new_size: [u32;2]) -> Result<ImageData, NwgError> {
unsafe { img::resize_bitmap(&*self.factory, image, new_size) }
}
}
pub struct ImageSource {
pub decoder: *mut IWICBitmapDecoder,
}
impl ImageSource {
pub fn frame_count(&self) -> u32 {
let mut frame_count = 0;
unsafe { (&*self.decoder).GetFrameCount(&mut frame_count); }
frame_count
}
pub fn frame(&self, index: u32) -> Result<ImageData, NwgError> {
let mut bitmap = ptr::null_mut();
let hr = unsafe { (&*self.decoder).GetFrame(index, &mut bitmap) };
match hr {
S_OK => Ok(ImageData { frame: bitmap as *mut IWICBitmapSource }),
err => Err(NwgError::image_decoder(err, "Could not read image frame"))
}
}
pub fn container_format(&self) -> ContainerFormat {
use ContainerFormat::*;
let mut container = unsafe { mem::zeroed() };
unsafe { (&*self.decoder).GetContainerFormat(&mut container) };
match container.Data1 {
0xf3ff6d0d => Adng,
0xaf1d87e => Bmp,
0x1b7cfaf4 => Png,
0xa3a860c4 => Ico,
0x19e4a5aa => Jpeg,
0x163bcc30 => Tiff,
0x1f8a5601 => Gif,
0x57a37caa => Wmp,
_ => Unknown
}
}
}
pub struct ImageData {
pub frame: *mut IWICBitmapSource
}
impl ImageData {
pub fn resolution(&self) -> (f64, f64) {
let (mut rx, mut ry) = (0.0, 0.0);
unsafe { (&*self.frame).GetResolution(&mut rx, &mut ry) };
(rx, ry)
}
pub fn size(&self) -> (u32, u32) {
let (mut sx, mut sy) = (0, 0);
unsafe { (&*self.frame).GetSize(&mut sx, &mut sy) };
(sx, sy)
}
pub fn pixel_format(&self) -> WICPixelFormatGUID {
let mut fmt = unsafe { mem::zeroed() };
unsafe { (&*self.frame).GetPixelFormat(&mut fmt) };
fmt
}
pub fn pixels(&self, pixel_size: u32) -> Result<Vec<u8>, NwgError> {
let (w, h) = self.size();
let scanline = w * pixel_size;
let buffer_size = (w * h * pixel_size) as usize;
let mut buffer: Vec<u8> = Vec::with_capacity(buffer_size);
let hr = unsafe {
buffer.set_len(buffer_size);
(&*self.frame).CopyPixels(ptr::null(), scanline, buffer_size as u32, buffer.as_mut_ptr())
};
match hr {
S_OK => Ok(buffer),
err => Err(NwgError::image_decoder(err, "Could not read image pixels"))
}
}
pub fn region_pixels(&self, offset: [i32;2], size: [i32;2], pixel_size: u32) -> Result<Vec<u8>, NwgError> {
use winapi::um::wincodec::WICRect;
let [x, y] = offset;
let [w, h] = size;
let scanline = (w as u32) * pixel_size;
let buffer_size = (scanline * (h as u32)) as usize;
let mut buffer: Vec<u8> = Vec::with_capacity(buffer_size);
let region = WICRect { X: x, Y: y, Width: w, Height: h };
let hr = unsafe {
buffer.set_len(buffer_size);
(&*self.frame).CopyPixels(®ion, scanline, buffer_size as u32, buffer.as_mut_ptr())
};
match hr {
S_OK => Ok(buffer),
err => Err(NwgError::image_decoder(err, "Could not read image pixels"))
}
}
pub fn as_bitmap(&self) -> Result<Bitmap, NwgError> {
unsafe { img::create_bitmap_from_wic(self) }
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ContainerFormat {
Unknown,
Adng,
Bmp,
Png,
Ico,
Jpeg,
Tiff,
Gif,
Wmp,
}
impl Default for ImageDecoder {
fn default() -> ImageDecoder {
ImageDecoder {
factory: ptr::null_mut()
}
}
}
impl Drop for ImageDecoder {
fn drop(&mut self) {
if !self.factory.is_null() {
unsafe { (&*self.factory).Release(); }
}
}
}
impl Drop for ImageSource {
fn drop(&mut self) {
unsafe { (&*self.decoder).Release(); }
}
}
impl Drop for ImageData {
fn drop(&mut self) {
unsafe { (&*self.frame).Release(); }
}
}
pub struct ImageDecoderBuilder {
}
impl ImageDecoderBuilder {
pub fn build(self, out: &mut ImageDecoder) -> Result<(), NwgError> {
let factory = unsafe { img::create_image_factory() }?;
*out = ImageDecoder { factory };
Ok(())
}
}