BitmapImage wpf decoding speed performance

I have 5 images with the same pixel height and pixel width (2481 * 3508, for that matter). But one of them is gif, one jpeg, one png and one BMP. Now I pass them to BitmapSource with (1) two thirds of the original pixel height for DecodePixelHeight and (2) the original pixel height for DecodePixelHeight.

The first scenario:

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

BMP and Jpeg are equally slow. Png and Gif need less than half the time. Why?

Second scenario:

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

Png half the time needed before that. Jpeg and BMP are the fifth time that was needed before. Gif at the same time as before.

According to the documentation, I would suggest that the performance of Png and Jpeg is somehow more independent of the actual decoding size than other formats. What could be the reason that this is not so?

+6
source share
1 answer

I implemented a behavior that is optimal in terms of performance. I use it to stream live tape from home security cameras, it works like a charm with fairly large images.

Try this and let me know what you think. Usage is quite simple, assign dependency properties, attach behavior to the image and do with it. amuses.

Note. Pixels can be an IList, but you can also assign an array, since a C # array implements IList.

Note 2: Do not assign an image source, as this will override the purpose of the behavior, just bind the Pixels dependency property of the behavior.

 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); } } 
0
source

All Articles