How to handle 1000+ images in a C# Application? - c#

A winform control for displaying a list of images is currently implemented with a flowlayoutpanel and a collection of pictureboxes. But even at thumbnail scale (64x64) when we when start to approach 1000+ images we get OutOfMemory exceptions - our actual problem lies from the thumbnail generation part and the creation of the Image object.
I haven't been able to find any strategies from the existing image viewing examples on the net regarding a large number of images so does anybody have any links or strategies for solving this problem of displaying a list of 1000+ images?
As a starting point we really only need these image objects around when the thumbnail's picture box is in view. Then we would only have 10 image objects created but is there a smarter way of doing this other than loading and destroying image objects?
Thanks,
Edward

You should display only one screen of images at a time.
When the user drags the scrollbar, destroy those images and load new ones.

WPF handles this in a great way. If you have turned on Virtualization, the ListBox will create only the control that are visible to the screen.
In your case, keep reference to the images in a list. Put a pictureBox, and based on the Scrollbar, change the image on the pictureBox.

Related

Show multiple images in one picturebox

I am still very new to C# and I'm developing an application that holds all of my textures which are in a png format.
I am at a stage where I need to be able to show multiple textures within 1 picture box, could I ask how this is achieved?
you can do it by making array of images you want to show.
Consider this example and tutorial here to learn about it.

Drawing a lot of lines and other shapes in WinRT App

In my WinRT app I need to draw about 3000 objects on a canvas, where I can translate and zoom the view. Unfortunatley, after adding about 1500 lines to my canvas my Windows 8 App always crashes. What could be the best practice to achieve this?
One solution could be rendering everything on an image (how do I do this?). But then I loose comfort of easy access and editing of every element.
Also my scale and translate is very slow. But since I also need a big overview, it makes no sense to put only the objects of the visible area in the canvas, since on minimum zoom it's still everything and zoomed it's still very laggy cause of add and remove operations.
There are a couple of different things you should employ to have a smooth UX:
Use a Quadtree, whenever you add a shape to your canvas you also put it on your Quadtree. This will be helpful when you will zoom on a portion of the image: you will know what objects are in this portion of the image; you will render them again (against using a cached/pixellated version).
To overcome the potentially lengthy drawing process you could do the following:
display the portion of the cached image overview at the right scale
use a progress indicator to let know the user that the program is working render this portion
when the faint rendering is done, blit it on the screen
A concrete example: Google Maps does that.

Drawing a big number of images in C# Windows Forms

I'm creating a map editor for game in C# Windows Forms. What I need is a grid that will have to store even a few thousands of images.
My first approach was to create a Panel control and then add multiple PictureBoxes to it. Unfortunately 2000 images took about 3 seconds to draw.
Then I decided to try creating Rectangles and drawing Images on them in Panel's OnPaint() method in hope to get better results but it's still very slow.
Is there any better, efficient way to render so many images in Windows Forms?
Thanks in advance for any advices.
Use the Paint event as you have done but...
As part of the loading of the images, cache a zoomed out version where you merge 16 images into one, which is only 125 images, when you zoom out over a certain scale, switch to using the pre-rendered zoomed out version.
You can do that as often as you like for multiple zoom levels with the idea of keeping as few images as possible on screen at anyone time. So you could divide it by 4 again.
I do this for a project which has a map comprised of 65536 images (256 x 256). The cache is also writted to disk so each time you zoom out you see the same number of images. In my editior I can only view 16 images at any one time, even if I'm looking at the whole map.
You can further improve on the this by knowing the available options to the user (e.g. Pan and Zoom) this gives you a limited subset of images the user could potentially view next so you can preload these to improve performance.
You'll increased load time initially but I bet you already have a significant load time pulling 2000 images off disk

How to save Images in WPF

I am working on a wpf application. I am having one image, i have put some more images on it, with lowered transparency(sort of watermarking you can say). Is their any way to save the present look of the two or three images(watermarked images) into one new image??
You can use RenderTargetBitmap to render Visuals, to render your stack of images you should place them in some wrapping control (if only temporarily). This article might be helpful.

Is there a more performant alternative to ImageList.Images.Add?

I have a winforms ImageList which contains 200 256x256 images.
When I add the images, 1 by one, half of the programs time spent on the Add method according to ANTS .NET profiler.
So the program takes 10 secs to launch and 5 is spent there. That is very slow in my opinion.
I implemented the same thing using ImageList.Images.AddRange. The result did not change.
Does anyone know any alternatives or optimizations to solve this? Is the WPF ImageList any faster? Is there a faster winforms ImageList?
EDIT:
foreach (string imageFile in images)
{
imageList.Images.Add(Image.FromFile(imageFile)); // takes pretty much all of program's execution time.
}
Have a look at the album and list views in PhotoSuru, one of Microsoft's WPF sample applications. They have a couple different thumbnail view screens that load pretty quickly (all the images are loaded asynchronously, and only the images necessary are loaded). And there's full source code to get you started if it's what you are looking for.
It not precisely like Picasa (they decided only to show full rows of photos instead of a partially covered row like Picasa), but by implementing your own virtualizing IScrollInfo panel (reasonably straightforward, and Ben Constable has a great series of posts on it), you should be able to get the performance you're looking for and the behaviour you want.
A final note: You might be doing this already (are your images stored as 256x256 pixel images?), but whenever you're trying to display image thumbnails, you'll want to avoid loading the full image. Reading 2 MB+ image files off of the disk just to render an entire screenful of 256x256 pixel thumbnails always has a bigger performance hit than reading an appropriately sized small thumbnail image instead. If you can, cache the thumbnails somewhere (like Windows and Picasa do), or at the very least, try to use the embedded thumbnails in any JPEG files you encounter.
Are you using a ListView for the UI part using that ImageList?
The general solution to these kind of problems is to only load some of the images, because only some of them are shown at a time, and then load the other as needed. ListView has a VirtualMode property for this kind of scenarios.
Loading and adding 200 images at once may be too much to do, you could load the first shown images and then use a background thread to load the others. Have a look at how Win7 display images, it shows some placeholder when you scroll and then, when the image is loaded it shows the real picture. Be warned that this is not a simple thing to do.
try my code here to scale-down your image and make a thumbnail out of it.
Yes it is. Load images to List<Image>. Then call ImageList.Images.AddRange(list).
List<Image> list = new List<Image>();
foreach (string imageFile in images)
{
list.Add(Image.FromFile(imageFile));
}
imageList.Images.AddRange(list.ToArray());

Categories