使用 WIC 从流中加载图像的结果颠倒了
The result of loading image from stream using WIC is flipped upside down
我尝试从 IStream 加载图像并将它们渲染到 dc 上。下面的代码工作正常
pub fn to_GDI_bitmap(&mut self, ctx: *mut HDC__, hMEM_BUFF: &MEM_BUFF, (flip_hor, flip_vert): (bool, bool)) -> *mut HBITMAP__ {
let hStream: HIStream = unsafe {
SHCreateMemStream(hMEM_BUFF.get_buf_ptr(), hMEM_BUFF.get_size() as u32)
};
self.reset_converter();
let decoder: *mut IWICBitmapDecoder = unsafe {
let mut ret: *mut IWICBitmapDecoder = zeroed() ;
let hr = self.factory
.as_ref()
.unwrap()
.CreateDecoderFromStream(
hStream,
null_mut(),
WICDecodeMetadataCacheOnDemand, &mut ret as *mut *mut IWICBitmapDecoder,
);
assert_eq!(hr, S_OK);
ret
};
let frame = unsafe {
let mut pFrame: *mut IWICBitmapFrameDecode = zeroed();
let hr = decoder.as_ref()
.unwrap().GetFrame(
{
let mut idx: UINT = zeroed();
let hr = decoder.as_ref()
.unwrap()
.GetFrameCount(&mut idx as *mut UINT);
assert_eq!(hr, S_OK);
idx-1
},
&mut pFrame as *mut *mut IWICBitmapFrameDecode
);
assert_eq!(hr, S_OK);
pFrame
};
let (width, height) = unsafe {
let (mut width, mut height): (UINT, UINT) = (0, 0);
frame.as_ref().unwrap().GetSize(&mut width as *mut UINT, &mut height as *mut UINT);
(width, height)
};
let hr = unsafe {
self.fmt_converter
.as_ref()
.unwrap()
.Initialize(
&**frame
.as_ref()
.unwrap() as *const IWICBitmapSource,
&GUID_WICPixelFormat24bppBGR,
WICBitmapDitherTypeNone,
null_mut(),
0.0 as c_double,
WICBitmapPaletteTypeMedianCut
)
};
assert_eq!(hr, S_OK);
let flip = |thing: u32| {
let mut pFlipRotator: *mut IWICBitmapFlipRotator = unsafe { zeroed() };
let hr = unsafe {
self.factory.as_ref().unwrap().CreateBitmapFlipRotator(
&mut pFlipRotator as *mut *mut IWICBitmapFlipRotator
)
};
assert_eq!(hr, S_OK);
assert!(!pFlipRotator.is_null());
let hr = unsafe {
pFlipRotator
.as_ref()
.unwrap()
.Initialize(
&**frame
.as_ref()
.unwrap() as *const IWICBitmapSource,
thing,
)
};
assert_eq!(hr, S_OK);
};
if flip_hor {
flip(0x00000008);
}
if flip_vert {
flip(0x00000010);
}
let mut buff = unsafe {
let mut buff: Vec<u8> = Vec::with_capacity(width as usize * height as usize * 3);
buff.fill(0);
let rect: WICRect = WICRect {
X: 0,
Y: 0,
Width: width as i32,
Height: height as i32,
};
let hr = frame
.as_ref()
.unwrap()
.CopyPixels(
&rect,
width * 3,
width * height * 3,
buff.as_mut_ptr()
);
assert_eq!(hr, S_OK);
buff
};
unsafe {
let bmp_iheader: BITMAPINFOHEADER = BITMAPINFOHEADER {
biSize: size_of::<BITMAPINFOHEADER>() as u32,
biWidth: width as i32,
biHeight: height as i32,
biPlanes: 1,
biBitCount: 24,
biCompression: BI_RGB,
biSizeImage: 0,
biXPelsPerMeter: GetDeviceCaps(ctx, HORZRES),
biYPelsPerMeter: GetDeviceCaps(ctx, VERTRES),
biClrUsed: 0,
biClrImportant: 0
};
let bmp_i: BITMAPINFO = BITMAPINFO {
bmiHeader: bmp_iheader.clone(),
bmiColors: [RGBQUAD::default();1],
};
CreateDIBitmap(ctx,
&bmp_iheader,
CBM_INIT,
buff.as_ptr() as *const _ as *const c_void,
&bmp_i,
DIB_RGB_COLORS)
}
}
pub fn transfer(&self, srcBmp: *mut HBITMAP__ , destDC: *mut HDC__, (x, y): (c_int, c_int), size: SIZE) {
let temp_dc = unsafe { CreateCompatibleDC(null_mut()) };
unsafe {
DeleteObject(SelectObject(temp_dc, srcBmp as HGDIOBJ));
};
let outcome: BOOL = unsafe {
GdiTransparentBlt(destDC,
x.into(),
y.into(),
size.cx,
size.cy,
temp_dc,
0,
0,
size.cx,
size.cy,
RGB(255, 255, 255),
)
};
assert!(outcome.is_positive());
let outcome: BOOL = unsafe { DeleteDC(temp_dc) };
}
除了渲染的图像像这样颠倒了:
正如您在代码中看到的那样,我试图实现一个系统来翻转图像以进行“脏”修复,奇怪的是,它似乎没有产生任何可见的效果(这可能表明出了点问题——但如果我能弄明白了,我不会在这里问的。
我试图解决该错误的另一件事是反转用于将像素从 WICFrameDecode 复制到 DIBitmap 的像素缓冲区。
参见BITMAPINFOHEADER
结构参考:
biHeight
Specifies the height of the bitmap, in pixels.
For uncompressed RGB bitmaps, if biHeight is positive, the bitmap is a bottom-up DIB with the origin at the lower left corner. If biHeight is negative, the bitmap is a top-down DIB with the origin at the upper left corner.
因此,您可以更改此字段的符号,以垂直翻转图像进行显示,而无需在内存中转换整个图像。
我尝试从 IStream 加载图像并将它们渲染到 dc 上。下面的代码工作正常
pub fn to_GDI_bitmap(&mut self, ctx: *mut HDC__, hMEM_BUFF: &MEM_BUFF, (flip_hor, flip_vert): (bool, bool)) -> *mut HBITMAP__ {
let hStream: HIStream = unsafe {
SHCreateMemStream(hMEM_BUFF.get_buf_ptr(), hMEM_BUFF.get_size() as u32)
};
self.reset_converter();
let decoder: *mut IWICBitmapDecoder = unsafe {
let mut ret: *mut IWICBitmapDecoder = zeroed() ;
let hr = self.factory
.as_ref()
.unwrap()
.CreateDecoderFromStream(
hStream,
null_mut(),
WICDecodeMetadataCacheOnDemand, &mut ret as *mut *mut IWICBitmapDecoder,
);
assert_eq!(hr, S_OK);
ret
};
let frame = unsafe {
let mut pFrame: *mut IWICBitmapFrameDecode = zeroed();
let hr = decoder.as_ref()
.unwrap().GetFrame(
{
let mut idx: UINT = zeroed();
let hr = decoder.as_ref()
.unwrap()
.GetFrameCount(&mut idx as *mut UINT);
assert_eq!(hr, S_OK);
idx-1
},
&mut pFrame as *mut *mut IWICBitmapFrameDecode
);
assert_eq!(hr, S_OK);
pFrame
};
let (width, height) = unsafe {
let (mut width, mut height): (UINT, UINT) = (0, 0);
frame.as_ref().unwrap().GetSize(&mut width as *mut UINT, &mut height as *mut UINT);
(width, height)
};
let hr = unsafe {
self.fmt_converter
.as_ref()
.unwrap()
.Initialize(
&**frame
.as_ref()
.unwrap() as *const IWICBitmapSource,
&GUID_WICPixelFormat24bppBGR,
WICBitmapDitherTypeNone,
null_mut(),
0.0 as c_double,
WICBitmapPaletteTypeMedianCut
)
};
assert_eq!(hr, S_OK);
let flip = |thing: u32| {
let mut pFlipRotator: *mut IWICBitmapFlipRotator = unsafe { zeroed() };
let hr = unsafe {
self.factory.as_ref().unwrap().CreateBitmapFlipRotator(
&mut pFlipRotator as *mut *mut IWICBitmapFlipRotator
)
};
assert_eq!(hr, S_OK);
assert!(!pFlipRotator.is_null());
let hr = unsafe {
pFlipRotator
.as_ref()
.unwrap()
.Initialize(
&**frame
.as_ref()
.unwrap() as *const IWICBitmapSource,
thing,
)
};
assert_eq!(hr, S_OK);
};
if flip_hor {
flip(0x00000008);
}
if flip_vert {
flip(0x00000010);
}
let mut buff = unsafe {
let mut buff: Vec<u8> = Vec::with_capacity(width as usize * height as usize * 3);
buff.fill(0);
let rect: WICRect = WICRect {
X: 0,
Y: 0,
Width: width as i32,
Height: height as i32,
};
let hr = frame
.as_ref()
.unwrap()
.CopyPixels(
&rect,
width * 3,
width * height * 3,
buff.as_mut_ptr()
);
assert_eq!(hr, S_OK);
buff
};
unsafe {
let bmp_iheader: BITMAPINFOHEADER = BITMAPINFOHEADER {
biSize: size_of::<BITMAPINFOHEADER>() as u32,
biWidth: width as i32,
biHeight: height as i32,
biPlanes: 1,
biBitCount: 24,
biCompression: BI_RGB,
biSizeImage: 0,
biXPelsPerMeter: GetDeviceCaps(ctx, HORZRES),
biYPelsPerMeter: GetDeviceCaps(ctx, VERTRES),
biClrUsed: 0,
biClrImportant: 0
};
let bmp_i: BITMAPINFO = BITMAPINFO {
bmiHeader: bmp_iheader.clone(),
bmiColors: [RGBQUAD::default();1],
};
CreateDIBitmap(ctx,
&bmp_iheader,
CBM_INIT,
buff.as_ptr() as *const _ as *const c_void,
&bmp_i,
DIB_RGB_COLORS)
}
}
pub fn transfer(&self, srcBmp: *mut HBITMAP__ , destDC: *mut HDC__, (x, y): (c_int, c_int), size: SIZE) {
let temp_dc = unsafe { CreateCompatibleDC(null_mut()) };
unsafe {
DeleteObject(SelectObject(temp_dc, srcBmp as HGDIOBJ));
};
let outcome: BOOL = unsafe {
GdiTransparentBlt(destDC,
x.into(),
y.into(),
size.cx,
size.cy,
temp_dc,
0,
0,
size.cx,
size.cy,
RGB(255, 255, 255),
)
};
assert!(outcome.is_positive());
let outcome: BOOL = unsafe { DeleteDC(temp_dc) };
}
除了渲染的图像像这样颠倒了:
我试图解决该错误的另一件事是反转用于将像素从 WICFrameDecode 复制到 DIBitmap 的像素缓冲区。
参见BITMAPINFOHEADER
结构参考:
biHeight
Specifies the height of the bitmap, in pixels.
For uncompressed RGB bitmaps, if biHeight is positive, the bitmap is a bottom-up DIB with the origin at the lower left corner. If biHeight is negative, the bitmap is a top-down DIB with the origin at the upper left corner.
因此,您可以更改此字段的符号,以垂直翻转图像进行显示,而无需在内存中转换整个图像。