2012-10-24 46 views
6

我有5個圖像全部相同的像素高度和像素寬度(2481 * 3508就此而言)。但是,一個是gif,一個jpeg,一個png和一個bmp。現在我將它們渲染成一個BitmapSource,其中(1)DecodePixelHeight的原始像素高度的三分之二和DecodePixelHeight的原始像素高度。BitmapImage解碼速度性能wpf

第一種方案:

bitmapImage.BeginInit(); 
bitmapImage.CreateOptions = BitmapCreateOptions.IgnoreColorProfile; 
bitmapImage.CacheOption = BitmapCacheOption.OnLoad; 
bitmapImage.DecodePixelHeight = 2/3 * originalHeight; 
bitmapImage.StreamSource = streamWithTheFile; 
bitmapImage.EndInit(); 
bitmapImage.Freeze(); 

BMP和JPEG同樣緩慢。 Png和Gif需要的時間不到一半。爲什麼?

第二種情況:

bitmapImage.BeginInit(); 
bitmapImage.CreateOptions = BitmapCreateOptions.IgnoreColorProfile; 
bitmapImage.CacheOption = BitmapCacheOption.OnLoad; 
bitmapImage.StreamSource = streamWithTheFile; 
bitmapImage.EndInit(); 
bitmapImage.Freeze(); 

巴半之前所需要的時間。 Jpeg和BMP是之前所需時間的五分之一。 Gif與以前一樣。

根據documentation我假定Png和Jpeg的性能在某種程度上會比其他格式更獨立於實際的解碼大小。可能是什麼原因,它不是?

+0

好的問題 - 有沒有人有任何線索爲什麼BitmapImage的行爲是這樣的? –

+2

RenderOptions.BitmapScalingMode屬性(應用於實際顯示圖像的任何控件,通常是XAML 元素)可以提供幫助嗎?我認爲默認情況下,它被設置爲.NET 3.5中的HighQuality和.NET 4中的LowQuality,但兩者在渲染速度上都會受到不同程度的損失... – Marko

+0

我正在研究一個大量(數千個)的圖像 - 無論是JPG或BMP,我試圖優化速度更快的播放速度。一方面,位圖更大,需要更長時間從磁盤或內存緩存中加載,但它們不需要解碼。使用jpgs,情況正好相反 - 解碼速度很慢,但從磁盤加載很快。最後,我最終選擇了圖像的原始格式(jpg),因爲這需要較少的初始處理。重點是緩存和磁盤加載可能會影響時間。 – Dean

回答

0

我實現了一個行爲,這是最佳的,性能明智..我用它來從流媒體家庭安全攝像機活飼料,就像有相當大的圖像的魅力..

嘗試了這一點,讓我知道你怎麼看。用法非常簡單,分配依賴項屬性,將行爲附加到圖像並完成它。乾杯。

注意:像素可能是IList,但是您也可以分配一個數組,因爲C#數組實現了IList。

注2:不要分配圖像源,因爲這會覆蓋行爲的分配,只能綁定到像素行爲的依賴屬性。

public class VideoBehavior : Behavior<Image> 
{ 

    public static readonly DependencyProperty PixelsProperty = DependencyProperty.Register(
     "Pixels", typeof (IList<byte>), typeof (VideoBehavior), new PropertyMetadata(default(IList<byte>),OnPixelsChanged)); 

    private static void OnPixelsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var b = (VideoBehavior) d; 
     var pixels = (IList<byte>) e.NewValue; 


     b.RenderPixels(pixels); 
    } 


    public IList<byte> Pixels 
    { 
     get { return (IList<byte>) GetValue(PixelsProperty); } 
     set { SetValue(PixelsProperty, value); } 
    } 

    public static readonly DependencyProperty PixelFormatProperty = DependencyProperty.Register(
     "PixelFormat", typeof (PixelFormat), typeof (VideoBehavior), new PropertyMetadata(PixelFormats.Default,OnPixelFormatChanged)); 


    private static void OnPixelFormatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var b = (VideoBehavior) d; 
     var pixelFormat = (PixelFormat) e.NewValue; 

     if(pixelFormat==PixelFormats.Default) 
      return; 

     b._pixelFormat = pixelFormat; 

     b.InitializeBufferIfAttached(); 
    } 

    public PixelFormat PixelFormat 
    { 
     get { return (PixelFormat) GetValue(PixelFormatProperty); } 
     set { SetValue(PixelFormatProperty, value); } 
    } 

    public static readonly DependencyProperty PixelWidthProperty = DependencyProperty.Register(
     "PixelWidth", typeof (int), typeof (VideoBehavior), new PropertyMetadata(default(int),OnPixelWidthChanged)); 

    private static void OnPixelWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var b = (VideoBehavior)d; 
     var value = (int)e.NewValue; 

     if(value<=0) 
      return; 

     b._pixelWidth = value; 

     b.InitializeBufferIfAttached(); 
    } 

    public int PixelWidth 
    { 
     get { return (int) GetValue(PixelWidthProperty); } 
     set { SetValue(PixelWidthProperty, value); } 
    } 


    public static readonly DependencyProperty PixelHeightProperty = DependencyProperty.Register(
     "PixelHeight", typeof (int), typeof (VideoBehavior), new PropertyMetadata(default(int),OnPixelHeightChanged)); 

    private static void OnPixelHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var b = (VideoBehavior)d; 
     var value = (int)e.NewValue; 

     if (value <= 0) 
      return; 


     b._pixelHeight = value; 

     b.InitializeBufferIfAttached(); 
    } 

    public int PixelHeight 
    { 
     get { return (int) GetValue(PixelHeightProperty); } 
     set { SetValue(PixelHeightProperty, value); } 
    } 

    public static readonly DependencyProperty DpiXProperty = DependencyProperty.Register(
     "DpiX", typeof (int), typeof (VideoBehavior), new PropertyMetadata(96,OnDpiXChanged)); 

    private static void OnDpiXChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var b = (VideoBehavior)d; 
     var value = (int)e.NewValue; 

     if (value <= 0) 
      return; 


     b._dpiX = value; 

     b.InitializeBufferIfAttached(); 
    } 

    public int DpiX 
    { 
     get { return (int) GetValue(DpiXProperty); } 
     set { SetValue(DpiXProperty, value); } 
    } 

    public static readonly DependencyProperty DpiYProperty = DependencyProperty.Register(
     "DpiY", typeof (int), typeof (VideoBehavior), new PropertyMetadata(96,OnDpiYChanged)); 

    private static void OnDpiYChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var b = (VideoBehavior)d; 
     var value = (int)e.NewValue; 

     if (value <= 0) 
      return; 


     b._dpiY = value; 

     b.InitializeBufferIfAttached(); 
    } 

    public int DpiY 
    { 
     get { return (int) GetValue(DpiYProperty); } 
     set { SetValue(DpiYProperty, value); } 
    } 

    [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")] 
    public static extern void CopyMemory(IntPtr destination, IntPtr source, uint length); 

    private IntPtr _backBuffer = IntPtr.Zero; 
    private int _bytesPerPixel; 
    private const int BitsPerByte = 8; 
    private int _pixelWidth; 
    private int _pixelHeight; 
    private int _dpiX; 
    private int _dpiY; 
    private PixelFormat _pixelFormat; 
    private Int32Rect _rect; 

    private uint _byteArraySize; 
    private WriteableBitmap _bitMap; 

    private bool _attached; 

    protected override void OnAttached() 
    { 
     _attached = true; 
     InitializeBufferIfAttached(); 
    } 

    private void InitializeBufferIfAttached() 
    { 
     if(_attached==false) 
      return; 

     ReevaluateBitsPerPixel(); 

     RecomputeByteArraySize(); 

     ReinitializeImageSource(); 
    } 

    private void ReevaluateBitsPerPixel() 
    { 
     if(_pixelFormat==PixelFormats.Default) 
      return; 

     _bytesPerPixel = _pixelFormat.BitsPerPixel/BitsPerByte; 
    } 

    private void ReinitializeImageSource() 
    { 
     if(_pixelHeight<=0|| _pixelHeight<=0) 
      return; 

     _bitMap = new WriteableBitmap(_pixelWidth, _pixelHeight, _dpiX, _dpiY, _pixelFormat, null); 
     _backBuffer = _bitMap.BackBuffer; 
     _rect = new Int32Rect(0, 0, _pixelWidth, _pixelHeight); 
     AssociatedObject.Source = _bitMap; 
    } 

    private async void RenderPixels(IList<byte> pixels) 
    { 
     if (_backBuffer == IntPtr.Zero) 
      return; 

     if (pixels == null) 
     { 
      return; 
     } 

     await Task.Factory.StartNew(() => 
     { 
      var h = new GCHandle(); 
      var allocated = false; 

      try 
      { 
       h = GCHandle.Alloc(pixels, GCHandleType.Pinned); 
       allocated = true; 
       var ptr = h.AddrOfPinnedObject(); 
       CopyMemory(_backBuffer, ptr, _byteArraySize); 
      } 
      finally 
      { 
       if (allocated) 
        h.Free(); 
      } 
     }); 

     _bitMap.Lock(); 

     _bitMap.AddDirtyRect(_rect); 
     _bitMap.Unlock(); 
    } 

    private void RecomputeByteArraySize() 
    { 
     _byteArraySize = (uint)(_pixelWidth * _pixelHeight * _bytesPerPixel); 
    } 
}