使用 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.

因此,您可以更改此字段的符号,以垂直翻转图像进行显示,而无需在内存中转换整个图像。