I’m writing a WPF image viewer, displaying a grid of images. I’m baffled because of the sluggish performance: Displaying even an 11 x 11 grid makes a VM unresponsive, slow and sluggish for long durations of times. Even on the powerful host the performance in non-snappy.
The program is based on the design in SO WPF: arranging collection items in a grid: An ItemsControl is bound to Items, an ObservableCollection. Each Item contains has a file-system absolute URI. The ItemsControl‘s DataTemplate contains an Image element whose Source is bound to the URI.
It seems the problem can’t be the disk (SSD), the memory (8GB VM, 24GB host), or CPU (i750). Moreover, most of the work is done by WPF, so it’s not even as if I could locate a problem in my code: My code simply loads URIs (i.e. the paths to the images, not the images) to the collection and quickly returns. Then there is a wait, and WPF displays the images.
The only problem I could think about is image processing – down scaling by WPF. But even on the host, which has a "good-enough" 5850 ATI Radeon HD card, the performance is not snappy.
So, my question is: How can I make displaying images on WPF more “snappy”?
Edit: The images are 1920x1080 22 bit HD JPEGs captured from HD m2ts video. I tried pre-scaling them (using FFmpeg) to 'ega' 640x350. There was a performance improvement but FFmpeg's scaled-down images looks much worse than WPF's.
Edit: Thanks to David Osborne the code now runs as x64. Still sluggish.
Edit What really improved the situation is what Matěj Zábský called scalling the images: reducing the resolution. For the benefit of future readers:
fullPath = new Uri(path, UriKind.Absolute);
BitmapImage smallerBitmapImage = new BitmapImage();
smallerBitmapImage.BeginInit();
smallerBitmapImage.DecodePixelWidth = (int) (theWidthOfTheGrid / theNumberOfColumns);
smallerBitmapImage.UriSource = fullPath;
smallerBitmapImage.EndInit();
FormatConvertedBitmap formatConvertedBitmap = new FormatConvertedBitmap();
formatConvertedBitmap.BeginInit();
formatConvertedBitmap.Source = smallerBitmapImage;
formatConvertedBitmap.DestinationFormat = PixelFormats.Gray16;
formatConvertedBitmap.EndInit();
formatConvertedBitmap.Freeze();
this.ImageSource = formatConvertedBitmap;
I have been in similar position (I had to display thumbnail versions of large images in real-time).
If you are using data binding to display the images, you can try two things:
The only other thing is to prescale the images - preferably separate thread. Possibly you could even prescale images which could be potentially used in the future while the processor is idle - for example if you are developing a map-like application, you could prescale images in areas to which the user is most likely to move.
You can try Virtualization for control, It help considerably when loading more images in listview. VirtualizingStackPanel
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
If want to use Viruatalization with wrap-panel, there is some from Codeplex, Virtualalizing Wrappanel
I know it is an old thread, but if someone is still interested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With