use std::path::Path;
use windows::Win32::Foundation::*;
use windows::Win32::Graphics::Imaging::{D2D::*, *};
use windows::Win32::System::Com::*;
use windows::core::*;
pub fn wic_factory() -> Result<IWICImagingFactory2> {
unsafe { CoCreateInstance(&CLSID_WICImagingFactory, None, CLSCTX_INPROC_SERVER) }
}
pub fn load_bitmap_source(
factory: &IWICImagingFactory2,
path: &Path,
) -> Result<(IWICBitmapSource, bool)> {
let path_str = path.to_string_lossy();
let path_hstring = HSTRING::from(path_str.as_ref());
let decoder = factory.create_decoder_from_filename(
&path_hstring,
None,
GENERIC_READ,
WICDecodeMetadataCacheOnDemand,
)?;
let frame = decoder.frame(0)?;
let pre_format = unsafe { frame.GetPixelFormat()? };
let has_alpha = pixel_format_has_alpha(&pre_format);
let converter = factory.create_format_converter()?;
converter.init(
&frame.cast::<IWICBitmapSource>()?,
&GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
None,
0.0,
WICBitmapPaletteTypeMedianCut,
)?;
Ok((converter.cast()?, has_alpha))
}
fn pixel_format_has_alpha(format: &GUID) -> bool {
const ALPHA_FORMATS: &[GUID] = &[
GUID_WICPixelFormat32bppBGRA,
GUID_WICPixelFormat32bppPBGRA,
GUID_WICPixelFormat32bppRGBA,
GUID_WICPixelFormat32bppPRGBA,
GUID_WICPixelFormat64bppRGBA,
GUID_WICPixelFormat64bppPRGBA,
GUID_WICPixelFormat64bppBGRA,
GUID_WICPixelFormat64bppPBGRA,
GUID_WICPixelFormat32bppRGBA1010102,
GUID_WICPixelFormat32bppRGBA1010102XR,
GUID_WICPixelFormat128bppRGBAFloat,
GUID_WICPixelFormat128bppPRGBAFloat,
];
ALPHA_FORMATS.contains(format)
}
pub trait WICImagingFactoryExt {
fn create_decoder_from_filename<P0>(
&self,
wzfilename: P0,
pguidvendor: Option<&GUID>,
dwdesiredaccess: GENERIC_ACCESS_RIGHTS,
metadataoptions: WICDecodeOptions,
) -> Result<IWICBitmapDecoder>
where
P0: Param<PCWSTR>;
fn create_format_converter(&self) -> Result<IWICFormatConverter>;
}
impl WICImagingFactoryExt for IWICImagingFactory2 {
#[inline(always)]
fn create_decoder_from_filename<P0>(
&self,
wzfilename: P0,
pguidvendor: Option<&GUID>,
dwdesiredaccess: GENERIC_ACCESS_RIGHTS,
metadataoptions: WICDecodeOptions,
) -> Result<IWICBitmapDecoder>
where
P0: Param<PCWSTR>,
{
unsafe {
self.CreateDecoderFromFilename(
wzfilename,
pguidvendor.map(|guid| guid as *const GUID),
dwdesiredaccess,
metadataoptions,
)
}
}
#[inline(always)]
fn create_format_converter(&self) -> Result<IWICFormatConverter> {
unsafe { self.CreateFormatConverter() }
}
}
pub trait WICBitmapDecoderExt {
fn frame(&self, index: u32) -> Result<IWICBitmapFrameDecode>;
}
impl WICBitmapDecoderExt for IWICBitmapDecoder {
#[inline(always)]
fn frame(&self, index: u32) -> Result<IWICBitmapFrameDecode> {
unsafe { self.GetFrame(index) }
}
}
pub trait WICFormatConverterExt {
fn init(
&self,
pisource: &IWICBitmapSource,
dstformat: &GUID,
dither: WICBitmapDitherType,
pipalette: Option<&IWICPalette>,
alpha_threshold_percent: f64,
palette_translate: WICBitmapPaletteType,
) -> Result<()>;
}
impl WICFormatConverterExt for IWICFormatConverter {
#[inline(always)]
fn init(
&self,
pisource: &IWICBitmapSource,
dstformat: &GUID,
dither: WICBitmapDitherType,
pipalette: Option<&IWICPalette>,
alpha_threshold_percent: f64,
palette_translate: WICBitmapPaletteType,
) -> Result<()> {
unsafe {
self.Initialize(
pisource,
dstformat as *const GUID,
dither,
pipalette,
alpha_threshold_percent,
palette_translate,
)
}
}
}
pub trait WICBitmapSourceExt {
fn get_size(&self) -> Result<(u32, u32)>;
fn copy_pixels(&self, rect: Option<&WICRect>, stride: u32, buffer: &mut [u8]) -> Result<()>;
}
impl WICBitmapSourceExt for IWICBitmapSource {
#[inline(always)]
fn get_size(&self) -> Result<(u32, u32)> {
let mut width = 0u32;
let mut height = 0u32;
unsafe {
self.GetSize(&mut width, &mut height)?;
}
Ok((width, height))
}
#[inline(always)]
fn copy_pixels(&self, rect: Option<&WICRect>, stride: u32, buffer: &mut [u8]) -> Result<()> {
let rect_ptr = rect
.map(|r| r as *const WICRect)
.unwrap_or(std::ptr::null());
unsafe { self.CopyPixels(rect_ptr, stride, buffer) }
}
}