本文介绍了WICBitmapSource.CopyPixels到GDI位图Scan0的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经修改了C# IWICBitmapSource.CopyPixels接口允许数组封送和传递指针:

I've modified the C# IWICBitmapSource.CopyPixels interface to allow both array marshaling and passing a pointer:

    void CopyPixels(
        WICRect prc,
        uint cbStride,
        uint cbBufferSize,
        [Out]
        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
        byte[] pbBuffer
    );
    new void CopyPixels(
        WICRect prc,
        uint cbStride,
        uint cbBufferSize,
        IntPtr pbBuffer
        );

我这样称呼

    public static Bitmap FromWic(IWICBitmapSource source) {
        Guid format;
        source.GetPixelFormat(out format);

        PixelFormat gdiFormat = ConversionUtils.GetPixelFormat(format);

        uint w, h;
        source.GetSize(out w, out h);

        Bitmap b = new Bitmap((int)w, (int)h, gdiFormat);


        BitmapData bd = b.LockBits(new Rectangle(0, 0, (int)w, (int)h),
                               ImageLockMode.ReadWrite, b.PixelFormat);
        try {
            //Copy unmanaged-to-unmanaged
            source.CopyPixels(
                   new WICRect { X = 0, Y = 0, Width = (int)w, Height = (int)h },
                   (uint)bd.Stride, (uint)(bd.Stride * bd.Height), bd.Scan0);
        } finally {
            b.UnlockBits(bd);
        }
        return b;
    }

代码执行没有错误,并且所有宽度,高度,步幅和缓冲区大小值都是正确的,但是位图保持黑色,就像WIC从未触摸过它一样.

The code executes without errors, and all the width, height, stride, and buffer size values are correct, but the bitmap remains black, as if WIC never touched it.

有什么想法可能会发生这种情况吗? .NET封送处理有问题吗?

Any ideas why this could be happening? Is there something wrong with the .NET marshalling?

推荐答案

似乎WPF使用代理方法将数据复制到非托管内存.基于此,我找到了解决方案.以下代码可以正常工作,并且应该非常高效.

It seems that WPF uses a proxy method to copy data to unmanaged memory. Based on that, I found a solution. The following code works and should be extremely efficient.

[DllImport("WindowsCodecs.dll", EntryPoint = "IWICBitmapSource_CopyPixels_Proxy")]
internal static extern int CopyPixels(IWICBitmapSource bitmap, IntPtr rect, uint cbStride, uint cbBufferSize, IntPtr pvPixels);

public static Bitmap FromWic(IWICBitmapSource source) {

    Guid format; //Get the WIC pixel format
    source.GetPixelFormat(out format);
    //Get the matching GDI format
    PixelFormat gdiFormat = ConversionUtils.GetPixelFormat(format);

    //If it's not GDI-supported format, convert it to one.
    IWICComponentFactory factory = null;
    IWICFormatConverter converter = null;
    try {
        if (gdiFormat == PixelFormat.Undefined) {
            factory = (IWICComponentFactory)new WICImagingFactory();
            converter = factory.CreateFormatConverter();
            converter.Initialize(source, Consts.GUID_WICPixelFormat32bppBGRA, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.9f, WICBitmapPaletteType.WICBitmapPaletteTypeCustom);
            gdiFormat = PixelFormat.Format32bppArgb;
        }
        IWICBitmapSource data = converter != null ? converter : source;

        //Get the dimensions of the WIC bitmap
        uint w, h;
        data.GetSize(out w, out h);

        Bitmap b = new Bitmap((int)w, (int)h, gdiFormat);
        BitmapData bd = b.LockBits(new Rectangle(0, 0, (int)w, (int)h), ImageLockMode.WriteOnly, b.PixelFormat);
        try {
            long result = CopyPixels(data, IntPtr.Zero, (uint)bd.Stride, (uint)(bd.Stride * bd.Height), bd.Scan0);
            if (result == 0x80070057) throw new ArgumentException();
            if (result < 0) throw new Exception("HRESULT " + result);
            return b;
        } finally {
            b.UnlockBits(bd);
        }
    } finally {
        if (converter != null) Marshal.ReleaseComObject(converter);
        if (source != null) Marshal.ReleaseComObject(factory);
    }
}

请注意,我将IWICBitmapSource_CopyPixels_Proxy dllimport修改为使用IWICBitmapSource而不是SafeMILHandle,并且将ref Int32Rect修改为IntPtr,这样我就可以合法地传递IntPtr.Zero(如果传递矩形进行复制,则会出现HRESULT错误-我知道我的课程很有价值,可以在其他CopyPixels调用中使用它.

Note that I modified the IWICBitmapSource_CopyPixels_Proxy dllimport to use IWICBitmapSource instead of SafeMILHandle, and I modified ref Int32Rect to IntPtr, so that I could legally pass IntPtr.Zero (I get an HRESULT error if I pass in a rectangle to copy - and I know my stucture is value, I use it in other CopyPixels calls.

这篇关于WICBitmapSource.CopyPixels到GDI位图Scan0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 14:31