使用 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 个结果?

在搜索栏iOS swift3中加载带有条目的单元格时,图像无法正确显示

如何在搜索栏swift的表格视图结果中加载数据

Java IO流-Properties

调整图像大小 - WIC 与 GDI