Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Speed up loading an image from disk in a windows forms (c#.net) app

Tags:

c#

image

winforms

I'm currently working on an app that allows the user to play (automatically scroll) through a series of local images. Usually there will be five or six on screen at once.

The major bottleneck at the moment seems to be the actual loading of the image data from disk. A timer thread calls for the images to be updated every 1/6 of a second and the app is struggling to keep up with that speed. Each image is around 25Kb.

I tried creating a rolling cache to try and preload images but this was also getting caught up with itself so ended up slowing down just as much.

Every beat of the timer, I'm looping through the six image placeholders loading the next image using the standard

Image img = Image.FromFile("filename");

method but thought someone might know of a faster way to get the images off disk.

There are between 500 and 20,000 images in each of the six sets so it's too large to load the whole thing into memory at the start.

If anyone has suggestions for a faster way to pull these images through, it would be greatly appreciated.


Edit to add some more detail of application flow.

Okay, this is what's happening:

User hits 'play' button. Timer thread starts with 1/6 second timeout.

Timer callback:

Update image index (_index++)
for each viewer in list of visible viewers (the forms to display images)
{
    get the filename from the id stored in the viewer
    check to see if the file exists
    if it does exist,
        create new bitmap from image
        and return that image
    otherwise return null

    if returned image isn't null, display it on screen
}

That's obviously going across a few layers - the image loading goes on in the services layer and then passes this through to presentation and then to the UI but that's the gist of what's happening.

like image 931
Kevin Wilson Avatar asked Jul 29 '09 15:07

Kevin Wilson


3 Answers

I came across this page which describes how to use the GDI+ API directly to load images. Very simple to use:

ImageFast.FromFile(@"C:\MyPhoto.JPG");

Added to show speed of ImageFast over Image From File method

This uses the source code found here. The code was copied and pasted and required no changes.

Stopwatch watch = Stopwatch.StartNew();

string filePath = @"C:\TestImage25k.png";

Image fromFile = Image.FromFile(filePath);

watch.Stop();

Console.WriteLine("Image.FromFile     Ticks = {0:n}", watch.ElapsedTicks);

long fromFileTicks = watch.ElapsedTicks;

watch.Reset();
watch.Start();

Image fastImage = ImageFast.FromFile(filePath);

watch.Stop();

long fastFileTicks = watch.ElapsedTicks;

Console.WriteLine("ImageFast.FromFile Ticks = {0:n}", watch.ElapsedTicks);

Console.WriteLine("fromFileTicks - fastFileTicks = {0:n}", fromFileTicks - fastFileTicks);

The console output was

Image.FromFile     Ticks = 19,281,605.00

ImageFast.FromFile Ticks = 7,557,403.00

fromFileTicks - fastFileTicks = 11,724,202.00

You can see the impact of the ImageFast. Over time those 11 million saved ticks will add up.

like image 123
bernhof Avatar answered Oct 06 '22 19:10

bernhof


Easiest might be to put a 'next' and 'previous' button to limit the number of images and preload.

like image 36
Gert Avatar answered Oct 06 '22 19:10

Gert


Check out the concept of double buffering. What you want to be doing is have a second thread that can be loading the next set of images while you are displaying the first set. Once the 1/6 time gate hits, you switch the one set of images out and start loading the next set.

like image 43
Joel Martinez Avatar answered Oct 06 '22 19:10

Joel Martinez