1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::*;
use std::path::{Path, PathBuf};
use windows::core::Interface;
use windows::Win32::{Graphics::Imaging::*, System::SystemServices::*};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u32)]
pub enum Interpolation {
NearestNeighbor = D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR.0,
Linear = D2D1_INTERPOLATION_MODE_LINEAR.0,
Cubic = D2D1_INTERPOLATION_MODE_CUBIC.0,
MultiSampleLinear = D2D1_INTERPOLATION_MODE_MULTI_SAMPLE_LINEAR.0,
Anisotropic = D2D1_INTERPOLATION_MODE_ANISOTROPIC.0,
HighQualityCubic = D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC.0,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Image(ID2D1Bitmap1);
impl Image {
#[inline]
pub(crate) fn new(
dc: &ID2D1DeviceContext,
factory: &IWICImagingFactory,
loader: impl ImageLoader,
) -> Result<Self> {
loader.load(dc, factory)
}
#[inline]
pub(crate) fn draw(
&self,
dc: &ID2D1DeviceContext,
dest_rect: Rect,
src_rect: Option<Rect>,
interpolation: Interpolation,
) {
let dest = Inner(dest_rect).into();
let src = src_rect.map(|src| Inner(src).into());
unsafe {
dc.DrawBitmap2(
&self.0,
&dest,
1.0,
D2D1_INTERPOLATION_MODE(interpolation as _),
if let Some(src) = src.as_ref() {
src as *const _
} else {
std::ptr::null()
},
std::ptr::null(),
);
}
}
#[inline]
pub fn size(&self) -> gecl::Size<u32> {
unsafe {
let size = self.0.GetPixelSize();
gecl::Size::new(size.width, size.height)
}
}
}
unsafe impl Send for Image {}
unsafe impl Sync for Image {}
pub trait ImageLoader {
fn load(&self, dc: &ID2D1DeviceContext, factory: &IWICImagingFactory) -> Result<Image>;
}
impl<'a> ImageLoader for &'a Path {
fn load(&self, dc: &ID2D1DeviceContext, factory: &IWICImagingFactory) -> Result<Image> {
unsafe {
let decoder = {
factory.CreateDecoderFromFilename(
self.to_str().unwrap(),
std::ptr::null(),
GENERIC_READ,
WICDecodeMetadataCacheOnDemand,
)?
};
let frame = decoder.GetFrame(0)?;
let converter = {
let converter = factory.CreateFormatConverter()?;
let mut guid = GUID_WICPixelFormat32bppPBGRA.clone();
converter.Initialize(
&frame,
&mut guid,
WICBitmapDitherTypeNone,
None,
1.0,
WICBitmapPaletteTypeMedianCut,
)?;
converter
};
let bitmap = {
dc.CreateBitmapFromWicBitmap(&converter, std::ptr::null())?
.cast()?
};
Ok(Image(bitmap))
}
}
}
impl ImageLoader for PathBuf {
fn load(&self, dc: &ID2D1DeviceContext, factory: &IWICImagingFactory) -> Result<Image> {
self.as_path().load(dc, factory)
}
}
impl<'a> ImageLoader for &'a str {
fn load(&self, dc: &ID2D1DeviceContext, factory: &IWICImagingFactory) -> Result<Image> {
Path::new(self).load(dc, factory)
}
}
impl<'a> ImageLoader for &'a String {
fn load(&self, dc: &ID2D1DeviceContext, factory: &IWICImagingFactory) -> Result<Image> {
Path::new(self).load(dc, factory)
}
}