如何在 WPF 应用程序中使用 SharpDX.WIC.Bitmap?

How do I use a SharpDX.WIC.Bitmap in a WPF application?

我需要在 WPF 应用程序中展示来自 SharpDX 的 WIC Bitmap。 WIC 位图继承自 BitmapSource,但它与 WPF 使用的 BitmapSource 不同,尽管 class 名称相同。我怎样才能从一种转换成另一种?

您可以做的是从 WPF 的 BitmapSource 创建自定义派生 class。

例如,对于这个 XAML:

<Window x:Class="SharpDXWpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Image Name="MyImage"></Image>
    </Grid>
</Window>

此 Window 代码使用自定义 "WicBitmapSource"。

public partial class MainWindow : Window
{
    private WicBitmapSource _bmp;

    public MainWindow()
    {
        InitializeComponent();
        _bmp = new WicBitmapSource(@"c:\path\killroy_was_here.png");
        MyImage.Source = _bmp;
    }

    protected override void OnClosed(EventArgs e)
    {
        _bmp.Dispose();
    }
}

这里是这个 SharpDX/Wic 自定义 BitmapSource 的一些示例代码(一些信息是从这里抓取的:https://blogs.msdn.microsoft.com/dwayneneed/2008/06/20/implementing-a-custom-bitmapsource/)。

public class WicBitmapSource : System.Windows.Media.Imaging.BitmapSource, IDisposable
{
    public WicBitmapSource(string filePath)
    {
        if (filePath == null)
            throw new ArgumentNullException(nameof(filePath));

        using (var fac = new ImagingFactory())
        {
            using (var dec = new SharpDX.WIC.BitmapDecoder(fac, filePath, DecodeOptions.CacheOnDemand))
            {
                Frame = dec.GetFrame(0);
            }
        }
    }

    public WicBitmapSource(BitmapFrameDecode frame)
    {
        if (frame == null)
            throw new ArgumentNullException(nameof(frame));

        Frame = frame;
    }

    public BitmapFrameDecode Frame { get; }
    public override int PixelWidth => Frame.Size.Width;
    public override int PixelHeight => Frame.Size.Height;
    public override double Height => PixelHeight;
    public override double Width => PixelWidth;

    public override double DpiX
    {
        get
        {
            Frame.GetResolution(out double dpix, out double dpiy);
            return dpix;
        }
    }

    public override double DpiY
    {
        get
        {
            Frame.GetResolution(out double dpix, out double dpiy);
            return dpiy;
        }
    }

    public override System.Windows.Media.PixelFormat Format
    {
        get
        {
            // this is a hack as PixelFormat is not public...
            // it would be better to do proper matching
            var ct = typeof(System.Windows.Media.PixelFormat).GetConstructor(
                BindingFlags.Instance | BindingFlags.NonPublic,
                null,
                new[] { typeof(Guid) },
                null);
            return (System.Windows.Media.PixelFormat)ct.Invoke(new object[] { Frame.PixelFormat });
        }
    }

    // mostly for GIFs support (indexed palette of 256 colors)
    public override BitmapPalette Palette
    {
        get
        {
            using (var fac = new ImagingFactory())
            {
                var palette = new Palette(fac);
                try
                {
                    Frame.CopyPalette(palette);
                }
                catch
                {
                    // no indexed palette (PNG, JPG, etc.)
                    // it's a pity SharpDX throws here,
                    // it would be better to return null more gracefully as this is not really an error
                    // if you only want to support non indexed palette images, just return null for the property w/o trying to get a palette
                    return null;
                }

                var list = new List<Color>();
                foreach (var c in palette.GetColors<int>())
                {
                    var bytes = BitConverter.GetBytes(c);
                    var color = Color.FromArgb(bytes[3], bytes[2], bytes[1], bytes[0]);
                    list.Add(color);
                }
                return new BitmapPalette(list);
            }
        }
    }

    public override void CopyPixels(Int32Rect sourceRect, Array pixels, int stride, int offset)
    {
        if (offset != 0)
            throw new NotSupportedException();

        Frame.CopyPixels(
            new SharpDX.Mathematics.Interop.RawRectangle(sourceRect.X, sourceRect.Y, sourceRect.Width, sourceRect.Height),
            (byte[])pixels, stride);
    }

    public void Dispose() => Frame.Dispose();

    public override event EventHandler<ExceptionEventArgs> DecodeFailed;
    public override event EventHandler DownloadCompleted;
    public override event EventHandler<ExceptionEventArgs> DownloadFailed;
    public override event EventHandler<DownloadProgressEventArgs> DownloadProgress;

    protected override Freezable CreateInstanceCore() => throw new NotImplementedException();
}