wpf在image控件上快速顯示內存圖像


這是在博客園的第一篇文章

 

如果你在尋找能夠快速在image控件刷新大圖像(比如分辨率3000*3000的圖像)的辦法,尤其是想把內存中的裸數據(只有圖像的數據,不包含圖像頭等信息)快速顯示到界面,那么你來對地方了,看完這篇博客會解決困擾了你一天,或者一個禮拜,或者一年,或者一輩子的問題,時間的長短取決於你看到這篇博客的時間。

 

請注:如果本篇博客對於解決你的問題起到了決定性的作用,那么請在你的代碼里加上以下兩行內容,請尊重別人的努力。轉載請注明出處

// provide by zhangshaohui 

// 本文網址

 

以下是正文:

在你尋找解決方案的過程中,一定看到過這樣的代碼:

1、這個代碼最常見,網上到處都是,的確可以用,也簡單清晰,但是速度太慢,顯示一個3000*3000的大概要40ms,我跟蹤了一下代碼,主要是new stream,以及EndInit比較耗時,但是用這個方法又繞不過去這兩行代碼。

  public BitmapImage BitmapToBitmapImage(Bitmap bitmap)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                bitmap.Save(stream, ImageFormat.Png); 
                stream.Position = 0;
                BitmapImage result = new BitmapImage();
                result.BeginInit();
                result.CacheOption = BitmapCacheOption.OnLoad;
                result.StreamSource = stream;
                result.EndInit();
                result.Freeze();
                return result;
            }
           
        }

2、這個也是常見的辦法,好像還是msdn上推薦的,缺點是更慢

 public static ImageSource ChangeBitmapToImageSource(Bitmap bitmap)
        {
            IntPtr hBitmap = bitmap.GetHbitmap();
            ImageSource wpfBitmap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                hBitmap,
                IntPtr.Zero,
                Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());

            if (!APIConverter.DeleteObject(hBitmap))
            {
                throw new System.ComponentModel.Win32Exception();
            }
            return wpfBitmap;
        }

  

如果對於顯示速度沒有什么要求,那么這兩個辦法還是可以用用的,但是如果對於性能有要求,而且又數據量很大,比如接收超高清的視頻數據,那么這兩個方法是完全滿足不了需求的。

 

本文的方案是:

1、以顯示3000 * 3000的圖像為例,下面的代碼是偽代碼

2、定義ImageSource ImgSource,ImgSource綁定到image控件的Source屬性 

3、PixelFormats.Gray16,定義為PixelFormats.Gray8也是可以的,不過就需要在WriteableBitmap構造函數最后一個參數添加偽彩表,當然還可定義rgb的格式,這個看裸數據的格式以及需求來了,這里只是拋磚引玉,方法是通用的。

4、本方案的優點是沒有頻繁的內存分配和釋放,既節省時間,又不用擔心內存溢出,想更新哪里更新哪里,代碼簡單易懂,速度極快

 

ViewModel中
 public class MainWindowViewModel : ViewModelBase
    {
        private WriteableBitmap _wbBitmap;

        public MainWindowViewModel()
        {
        _wbBitmap = new WriteableBitmap(3000, 3000, 96, 96, PixelFormats.Gray16, null);
            ImgSource = _wbBitmap;
        }    
        public void ShowImage(short[] rawData)// rawData是存儲圖像裸數據的buffer
        {
         unsafe
            {
                _wbBitmap.Lock();
                Marshal.Copy(rawData,0,_wbBitmap.BackBuffer,3000*3000); //請注意_wbBitmap的數據格式以及buffer大小,以免溢出和顯示異常
_wbBitmap.AddDirtyRect(new System.Windows.Int32Rect(0, 0, 3000, 3000)); _wbBitmap.Unlock(); } } } 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM