Quick loading and display of images in a picturebox - c#

I need to load 101 bitmaps from the filesystem (they can't be built into the app as a resource as they will be changed for each run of the program) into a windows form application picturebox sequentially based on short duration timer events (500ms give or take) .
Essentially it should work like a slow animation but it is critical that every image be shown.
I've roughed out a simple application in C# to do this however it seems that the image loading and displaying is taking longer than the 500ms so some images are never displayed.
Is there some way I can avoid this? Preloading or creating 101 pictureboxes and showing and hiding?
Anybody have any suggestions?

What's taking the longest? Image loading or displaying? Are you loading each image when it needs displaying? A look at your code would be really valuable.
If you are certain that it will always be exactly 101 images, load them all into an array of System.Drawing.Bitmap first then have an iterator variable that gets incremented on each call of the Tick event of a Timer. Have this Tick event load the image from the array into the PictureBox using PictureBox.Image = myBitmapArray[iterator] If you increment the iterator using ++i%=101; you won't get an OutOfBounds error and the animation will loop.

Populate an array of Bitmap objects before starting the animation.

A couple of options... pick one or combine them:
(1) Use a lock and a counter to guarantee that when the event fires it's loading the next image in line.
(2) Disable the timer in the Tick event, then re-enable it after you've loaded the image. The result is that the images arrive 500ms after the last one is drawn, so if a picture takes one second to load, the images are drawn at t=1000ms, t=1500ms, t=3000ms, etc. All the images are drawn, and 500ms is guaranteed to pass between pictures, but the animation might appear slow.
(3) Do the above, but track the time the event starts, and after the image is drawn, set the next timer tick to be 500 - (Now - eventStart)... so that if the image takes 250ms to draw, the next timer tick will fire in 250ms. If Now - eventStart < 0, the next timer tick should fire immediately. The animation will take the minimum amount of time possible, but images could potentially flash by, appearing only for a few milliseconds.
(4) Use PictureBox.LoadAsync() to give you some multi-threading... the next event can be loading the image while the previous event is drawing. But you'll need a Mutex that you release in the LoadCompleted event that you wait on before calling LoadAsync(), if you need to guarantee the images are all drawn.
(5) I'm not sure if the drawing of the picture falls under the Layout category, but you can try calling SuspendLayout() and ResumeLayout() before/after loading the image
(6) Use an array of images, lock a counter, and use the .Image property of the PictureBox to let you pre-load the images. I believe this was suggested in another answer, also
HTH,
James

I don't have a concrete answer for you, but I would approach this by first determining if it's image loading, image display, or both actions that are taking too much time.
I would imagine that image loading is going to be relatively quick, even with pretty large image sizes, provided that the images are local and you have relatively decent hardware. My first attempt would involve loading all images from a thread sequentially so that you application doesn't have to wait for image display to complete before the next image loads.
If image display is taking a long time (and even on my really powerful workstation it's not all that fast for large images), then is it possible for you to scale the images before the application displays everything? Does your application need to deal with full resolution images? With the megapixel cameras these days, I can't image that you'd want to have all of the data present in the image files anyway, since the sizes can easily exceed monitor resolutions by a factor of 6.

Another thing that may be a concern is the size of the images. If the are all 18 Megapixel Images, I can see it taking either a lot of time or a lot of room.
You may want to resize them to the size of your display area when you initially load them up so that you aren't using 2 gigs of ram or waiting to read off the disk depending on how you implement it.

Related

How to render a very large image or document that is drawn without any performance issues

I want to make a control that acts as a time ruler with a wave form for sound wav files like that in movie maker or in camtasia studio video editor
i have a method to parse the sound wav file
i have a method to draw the wave of a specified time period
the problem is that the duration is long how to render all of it??one time or when the user is scrolling to a point if it isn't rendered I'll render it? what after its all rendered ? it will be so long user will zoom in and so on how to do it without effecting the performance
If you're dealing with a big image and lots of data I would sugest this:
render/display what user is currently looking at
render rest of if in a background thread into a memory image
Once you have the whole image rendered in an image kept in memory, any scrolling and/or zooming would be just to position your display window.
Render your image in an unzoomed scale into a Bitmap object. When you need to display part of if use Bitmap.Clone to copy section of that bitmap into a picture displayed to user. A bit difficult part will be to render part of your base Bitmap which is currently demanded to be viewed.
This could be memory demanding. It is effectively a caching mechanism and as always in cases like that you get speed by using more memory.
Something similar to how google maps works.
We do not know how you are rendering your graphic, but I presume you are using unsafe lockbits to generate directly into a bitmap. As Maciej says, just render the part you need to display - when zoomed, either render again (should be fast). You can preempt by rendering current, zoom in 1, zoom out 1, left 1/2 a screen, right 1/2 screen etc in the background, but then you need to manage these (they can be rendered in parallel of course using background worker threads). The key to memory is to keep the bitmaps to a minimum (you have the algorithm of the graph and the renderer) and the key to speed is to keep it low level and prefetch what you can and parallelism.

C# Load Bitmap into PictureBox - slow and blocks UI .. any alternatives?

I am loading 640x480 Bitmaps into a picture box one after the other. When I do that my UI gets blocked. For example, if I was typing something in a text box which is on the same form where my picture box is, I would not be able to see the key that pressed right away, because the bitmap loading makes the UI very slow ..
How would one handle that ? is there any way around it ?
Any sample code would be great.
Thanks
A Picturebox is actually a fairly 'heavy' control in what it provides; it may not be the appropriate thing to use here. You might consider a much simpler container control, or drawing on the surface of the form itself.
If you want to consider BackgroundWorker or any other threaded technique here, keep in mind that the drawing itself must happen on the UI thread; there's no way around that.
If the loading of the images from disk is the source of the latency, you might consider loading the images into an in-memory bitmap on another thread, then signaling somehow to indicate that a new item is ready to be drawn. You would then invalidate the drawing surface, and add the new item as appropriate.
Also; if you are doing any scaling to the images, doing this in the background thread would be appropriate - that way, the drawing code itself only needs to draw an unscaled rect; Using the GDI+ DrawUnscaled functionality to copy a bitmap to an area of the exact same size is actually quite fast.
To get into anything more specific, like actual code, I would want to see code for how you are doing it now. I'm not even sure you are 'drawing' the images in the first place, rather than simply setting Picture/Image properties.
Use background worker so the gui is not freezed (async invoke the image display).
http://www.dreamincode.net/forums/topic/112547-using-the-backgroundworker-in-c%23/
Your second request is a bit more tricky, I guess short answer would be not to rely on gdi+ if that's what you are doing be cause it's known to be slow. How exactly do you load the image into the imagebox?

Frames per second using WPF's DrawingContext class

I've got an example app which draws Rectangles, Lines etc. using the DrawContext instance of the OnRender override of a Control class. This control is repainted every 10 milliseconds by calling InvalidateVisual (I can post the source to anybody who's interested). I calculate the Frames per second (FPS) by measuring the time between each call of OnRender.
However, this figure for FPS is incorrect. Just by looking at the app I can see that the figure given for FPS is higher than the number of times per second that the app repaints itself. This is because "When you use a DrawingContext object's draw commands, you are actually storing a set of rendering instructions (although the exact storage mechanism depends on the type of object that supplies the DrawingContext) that will later be used by the graphics system; you are not drawing to the screen in real-time."
So what I would like to know is if there is any event I can subscribe to, or any other way, to ascertain how many times per second my WPF app/control is generating a new bitmap and drawing it to the screen? Is there any bitmap buffer held by the "graphics system" which we can access?
Many thanks!
What you need to use is the CompositionTarget.Rendering event that is called every frame.

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

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.
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.
Easiest might be to put a 'next' and 'previous' button to limit the number of images and preload.
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.
I think concept of double buffering will be useful. Set "Double Buffer" property of the form to True. This will help you little bit. Following links may be useful to you
http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/f15ae586-b63f-4afb-90a7-d9067ccc19d5
How to speed up .NET winforms rendering
If you have 6 images displayed at once, and you change them all every 1/6 of a second, you should be running into performance issues. Loading 150 kb from disk should be a trivial activity even without caching. It sounds like you may be overdoing the file loads. Are you sure you are only loading 6 images at a time? Are you reading images from disk that are not displayed?
If you can you provide a little more detail of the application flow, I may be able to be a little more helpful.
i would probably create a background thread to continously fetch all the images from disk (keeps the ui responsive) and then publish each newly loaded image via an event

Simultaneous updates across two display contexts in openGL

I have a C# .NET application with which I've created a custom image display control. Each image display represents its own display context and draws the image using glDrawPixels (Yes I know it would be better to use textures, I plan to in the futures but this app is already too far along and my time is limited).
I am now trying to have both images pan simultaneously. That is, when one image is moved down ten pixels, the second image moves down ten pixels. Like so:
imageOne.YPan -= 10;
imageTwo.YPan -= 10;
imageOne.Invalidate(); //This forces a redraw.
imageTwo.Invalidate(); //This forces a redraw.
Alright so here is the problem I am having. Only one of the images displays is redrawing. If I place a pause in between the two Invalidate calls and make the pause duration at least 110 milliseconds both will redraw, but not simultaneously. So it looks as if the second image is always trying to catch up to the first. Plus, a 110 millisecond pause slows down the motion too much.
I have tried placing the updating and invalidating of each image in its own thread but this did not help.
At the beginning of drawing I make the appropriate context is current, and at the end I am calling swapbuffers(). I tried adding a glFinish to the end of the draw function, but there was no change.
Could it be that its the graphics card that is the problem? I am stuck using an integrated gpu that only has openGL 1.4.
Hopefully, I have provided enough detail that the answer to my problem can be found.
Its difficult telling what's wrong with what you do since you give so little detail. Here are some pointers which may help.
- before doing something in a context, make sure you make it the current one. If you want to pan two contexts, make the first one current, pan it and then make the second one current and pan it. These is no real reason why this should not work.
- If it looks like there is a timing problem, adding glFinish() at strategic places may help weed the problem out
- As should always be done, on occasions call glError() and see that everything went well.
- I'm not sure how this is done in the framework you're talking about but you should make sure that both contexts get a swapBuffers() call for every frame.
Invalidate doesn't force an immediate redraw. It marks the window invalid, and when the message queue runs out of other messages, a paint message will be created and processed. But that won't happen until you finish processing the current message and return to the main message loop, and it may be delayed even more than that.
Generally OpenGL animation is an exception to the rule of doing all drawing inside Control.OnPaint (or in a handler for the Control.Paint event).

Categories