使用 WIC 从流中加载图像的结果颠倒了
Posted
技术标签:
【中文标题】使用 WIC 从流中加载图像的结果颠倒了【英文标题】:The result of loading image from stream using WIC is flipped upside down 【发布时间】:2021-10-26 11:46:29 【问题描述】:我尝试从 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 描述: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.
@AlexF 非常感谢 - 合法错过了我的视线 smh。您可以将其作为答案,以便我批准和投票吗?
【参考方案1】:
见BITMAPINFOHEADER
结构参考:
双高
指定位图的高度,以像素为单位。
对于未压缩的 RGB 位图,如果 biHeight 为正,则位图是自底向上的 DIB,原点位于左下角。如果biHeight 为负数,则位图为自上而下的DIB,原点位于左上角。
因此,您可以更改此字段的符号以垂直翻转图像以进行显示,而无需在内存中转换整个图像。
【讨论】:
以上是关于使用 WIC 从流中加载图像的结果颠倒了的主要内容,如果未能解决你的问题,请参考以下文章
URLImage 从不在 SwiftUI 的小部件应用程序中加载图像 [重复]
是否可以在 Backoffice 搜索中加载超过 50 个结果?