Quickly loading, resizing, and displaying images from disk - c#

I'm learning my way around windows forms by making a little app to help clean up a folder on my PC with thousands of images. I'm currently storing the images as a List<FileInfo>. It works fine using
PicBox.Load(ImageFileList[count++].imgFile.FullName);
but that's a bit slow when I only need a second to look at each image.
So the problems are:
How to load the images quickly
How to do so in a folder where one image might be a 25kb png and the next might be a 1GB TIFF
If I open an image from the folder in Windows Photo Viewer and hold the right arrow key, it zips along with blurry images I assume are resized thumbnails and a loading message over them. In Win 10 Photos, it loads non-blurry images faster but hiccups when it hits larger files. Either of those behaviors would be fine for me.

Try to do your things using background tasks :
https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/walkthrough-implementing-a-form-that-uses-a-background-operation?view=netframeworkdesktop-4.8
Maybe this can help too :
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.application.doevents?view=windowsdesktop-6.0

Related

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

Why my images are taking too much time to load?

I've read about the LowProfileImageLoader. It will only load the image when the user can see it and will avoid blocking the UI thread.
I added it and tested on my application. All 25 images are from the exact same URL. With the default image it took a little to load but all other images were cached, and the scroll got super fast.
With the LowProfileImageLoader the images were not cached, it was loading 1 by 1 even though it was the exact same image. And when I scrolled down then up it would load the image all over again. And it takes a long time to load them.
Do I have to configure something to keep the images on cache? How do I configure this LowProfileImageLoader?
From what I understood by looking at a windows phone mango video presentation, images are automatically cached without you doing anything.
Video I'm talking about: http://www.wpcentral.com/multitasking-mango-demoed-detail

Windows 7 icon sizing problems

I'm trying to create an application icon. I took a bunch of created *.ico files (one for each size) and combined them into a single *.ico file. I can see them all fine. I have 16x16, 32x32, 48x48, 64x64, and 128x128 icons (all 32bit w/ transparency).
However, when I build my app (a standard Windows Forms app written in C#) and look at the icon in Windows explorer, it looks fine at the first few sizes (up to 48x48 I think.. "Medium"), but if I use the "Large" or "Extra Large" display modes in Windows Explorer, I just see the 48x48 (I think) icon in an ever larger box.
How can I get Windows Explorer to recognize the larger icons? What am I doing wrong? Has anyone seen this issue before, and point me in the correct direction? I'm assuming there's a problem with the way the *.ico file is built, or the formats... but I can't find any hints anywhere.
As far as I understand it, once you get above a certain size (and it may well be 48x48), Explorer will go looking for a 256x256 icon, and scale it to the desired size.
128x128 is not a standard icon size, and Explorer may not bother looking for it. You can show icons at up to 256x256 in Explorer ("Extra Large icons"), though you can do sizes in between. If you size your icons to, say, 192x192, then it's going to look better to take a large image and scale it down, rather than to take a small image and scale it up -- so you're better off adding a 256x256 image anyway, rather than a 128x128.

IShellItemImageFactory Icon\Thumbnails different from Windows 7 Desktop

I am using IShellItemImageFactory to get icons and thumbnails for files and directories. In most cases this works great, but in some cases I get an image that is quite different from the one in explorer.exe.
Folders in explorer.exe show some of their contents represented as pieces of paper. Whenever I request an image for a directory, I get an empty folder in my program.
Videos playable by Windows Media Player in explorer.exe show as a piece of filmstrip with a thumbnail as the cell. When I request an image for such a video file I get just a thumbnail with no movie strip border.
I am sure there are other examples, but in general I just want to know if there is a way to request an image from the system that looks exactly like whatever is displayed on the desktop or in a folder in explorer.exe. I want everything to look the same so my program isn't "sloppy."
The answer is here:
http://msdn.microsoft.com/en-us/library/cc144118(v=VS.85).aspx#adornments
The adornments are the effects I am missing and it seems I would have to render them manually.
TiKu on MSDN explained this to me and deserves the credit.

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