【问题标题】:How do I use a SharpDX.WIC.Bitmap in a WPF application?如何在 WPF 应用程序中使用 SharpDX.WIC.Bitmap?
【发布时间】:2017-09-30 07:15:20
【问题描述】:

我需要在 WPF 应用程序中提供来自 SharpDX 的 WIC Bitmap。 WIC 位图继承自 BitmapSource,但它与 WPF 使用的 BitmapSource 不同,尽管类名相同。如何从一种转换为另一种?

【问题讨论】:

    标签: c# wpf bitmap sharpdx wic


    【解决方案1】:

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

    例如,对于这个 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>
    

    此窗口代码使用自定义“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();
    }
    

    【讨论】:

    • 谢谢,但是 &lt;Image&gt; 应该改为 WicBitmapSource 吗?
    • Image 是可以显示 BitmapSource 实例的标准 WPF FrameworkElement,无论该 BitmapSource 是什么类型。
    • 谢谢,这行得通。现在,有什么方法可以避免编码-解码步骤?
    • 如果你的意思是避免调用 DecodeFrame(没有编码),我不这么认为。 WPF 在内部使用 WIC,但不公开任何句柄、引用等,只公开抽象 BitmapSource 类。
    猜你喜欢
    • 2010-09-23
    • 2014-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-02
    相关资源
    最近更新 更多