2012-10-24 6 views
6

5 픽셀의 픽셀 높이와 픽셀 너비가 모두 동일합니다 (2481 * 3508). 그러나 하나는 gif, 하나는 jpeg, 하나는 png, 하나는 bmp입니다. 이제 DecodePixelHeight의 원래 픽셀 높이의 2/3과 DecodePixelHeight의 원래 픽셀 높이로 (2) BitmapSource로 렌더링합니다.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(); 

PNG로 절반. Jpeg 및 BMP는 이전에 필요한 시간의 5 분의 1입니다. 이전과 같은 시간에 GIF.

documentation에 따르면 PNG 및 Jpeg 성능이 어떻게 든 다른 형식보다 실제 디코드 크기에 더 독립적이라고 가정했을 것입니다. 그 이유가 무엇일까요? 내가 최적 인 동작을 구현 한

+0

좋은 질문 - BitmapImage가 그런 식으로 행동하는 이유는 누구에게 들리니? –

+2

RenderOptions.BitmapScalingMode 속성 (어떤 컨트롤이 실제로 이미지를 보여 주는지, 보통 XAML 요소)이 속도에 도움이 될까요? 나는 기본적으로 .NET 3.5 및 HighQuality .NET 4에 대한 LowQuality로 설정되어 있지만 둘 다 렌더링 속도의 종류의 패널티가 발생한다고 생각합니다 ... – Marko

+0

나는 많은 수 (수천) 시리즈를 재생하는 응용 프로그램에서 일하고있었습니다. 이미지 중 - jpg 또는 bmp 중 하나를 선택하고 빠른 재생 속도를 위해 속도를 최적화하려고했습니다. 한편으로는 비트 맵이 더 크고 디스크 또는 mem 캐시에서로드하는 데 시간이 오래 걸리지 만 디코딩이 필요하지 않습니다. jpg의 경우 반대가 사실이었습니다. 디코딩 속도는 느리지 만 디스크에서로드하는 속도는 빠릅니다. 결국 초기 이미지 작업이 덜 필요하기 때문에 원래 형식의 이미지 (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); 
    } 
}