Making image-source swap faster - c#

I have 4 image controls and a button, which swaps all those images within those image-controls. But this is going too slow.
The image swap happens after a 1.5s Storyboard animation. So imagine those four-image controls making a move down and then calling this method:
BLOCK4.Source = stack[3];
BLOCK3.Source = stack[2];
BLOCK2.Source = stack[1];
BLOCK1.Source = stack[0];
stack is a private BitmapImage[] stack; array which contains random images after every animation-call.
Do you see a way to tune this code in order to make the swap seemingly faster?
This is what happens: Animation starts -> stops -> I can see old images -> milliseconds pass by -> I can see new images.

Changing image positions instead of changing sources will be more fancy visual effect on users

Related

WPF 2D in 3D view Animations : Performance issue

I've put a TextBlock in a 3D panel (Planerator) and I used a Storyboard to animate it. (as crawl text)
When the field of view is 1 everything works fine, But if I set the field of view to more than 50 the frame rate will drop sharply and rendering will be choppy.
I used theCompositionTarget.rendering.
Please see the following images:
I need to 2D animations in 3d view with good performance.
Please tell me how can I solve this problem? Should I leave WPF and go to the DirectX?
UPDATE 1 :
I just want to move ONE 2Dtext in 3D space , but the performance is poor.(rendering isn't smooth it is choppy)
This is a sample project.
UPDATE 2:
This is the sample project updated version based on cokeman19's answer. (the performance have been improved ~10 frames, But I need to perfect rendering)
UPDATE 3 :
Finally, I got an acceptable performance with the help of the cokeman19's answer and the contents of this page.
I'm not sure if it's just a byproduct of the sample app, but under Planerator.CreateVisualChild(), it doesn't seem to be necessary to set the GeometryModel3D.BackMaterial. For reference:
VisualBrush vb = new VisualBrush(_logicalChild);
SetCachingForObject(vb); // big perf wins by caching!!
Material backMaterial = new DiffuseMaterial(vb);
...
GeometryModel3D backModel = new GeometryModel3D() { ..., BackMaterial = backMaterial };
The BackMaterial is a VisualBrush wrapper around the logical child, which doesn't belong to the visual tree, so rendering doesn't seem to make sense here. Moreover, the logical child (the LayoutInvalidationCatcher class), is in turn a wrapper around the visual child, which is already rendered (using _logicalChild) in setting frontModel.Visual.
Removing the code for the creation and setting of BackMaterial brings the FPS up to ~55.
In addition, if it's an option, setting the following brings the FPS back up to 60, with no noticeable degradation in quality.
RenderOptions.SetEdgeMode(_viewport3d, EdgeMode.Aliased);
Update:
The only other gain I was able to make was to set the CacheMode to BitmapCache, which may not be appliable for your needs.
frontModel.CacheMode = new BitmapCache(20) { EnableClearType = false };
Even on my slowest machine, this allowed for maximum FPS, but there are some drawbacks. Because the zoom level is so high on the text element, and this technique creates a picture to use in the animation (instead of animating the UIElement itself), I had to set the scale level to 20 before it became almost visually imperceptible. This of course has memory implications, as well.

Imagemagick C# animated .gif

I was curious as to how to create an animated .gif in C# using the imagemagick library class. This is what i am using so far:
using (MagickImageCollection collection = new MagickImageCollection())
{
//collection.CacheDirectory = #"C:\MyProgram\MyTempDir";
// Add first image and set the animation delay to 100ms
//MagickNET.Initialize(#"C:\Users\johsam\Downloads\Magick\MagickScript.xsd");
collection.Add("Koala.jpg");
collection[0].AnimationDelay = 1;
// Add second image, set the animation delay to 100ms and flip the image
collection.Add("Desert.jpg");
collection[1].AnimationDelay = 100;
collection[1].Flip();
// Optionally reduce colors
QuantizeSettings settings = new QuantizeSettings();
settings.Colors = 256;
collection.Quantize(settings);
// Optionally optimize the images (images should have the same size).
collection.Optimize();
// Save gif
collection.Write("test.Animated.gif");
}
The issue is that although it creates a .gif there is no moving image when you open it. How do you go about stringing the images together to create a moving image?
The code you are using, appears to be the example provided with the codeplex site. The logic appears to work as intended, but my presumption is that the animation delay, on the initial image in the collection, is too small (1 ms). You would arguably only see the second image. Please increase your animation delay (to 100ms), and confirm. Once completed, you can adjust the delay appropriately, to an interval that produces the desired output.

More than 2 millions rectangles in a WPF canvas

I am creating a custom control for semiconductor wafermap
Each of those small rectangle need to satisfy following requirements;
1) Tooltip to show the index
2) clickable to include or exclude from the wafermap definition.
no of dies in the wafermap may cross 2 millions in the case of 1400 x 1450 dies.
at certain point i need to show all the dies in a window (most of the clicking will happen in zoomed view).
Currently I am adding each die separately using Rectangle shape and store the coordinate information (index like (10,10)) for the tooltip as an attached property.
I use different style to each die; depending on certain calculation and position of the die.
DieStyle1 = new Style { TargetType = typeof(Rectangle) };
DieStyle1.Setters.Add(new Setter(Shape.FillProperty, Brushes.MediumSlateBlue));
DieStyle1.Setters.Add(new Setter(Shape.StrokeProperty, Brushes.White));
DieStyle1.Setters.Add(new EventSetter(MouseDownEvent, new MouseButtonEventHandler(DieStyle1_MouseDown)));
this approach is slow and use high memory too. so suggest a better way to achieve this in WPF?
In creating a designer for christmas tree lights, I ran into the same problem. Using UIElement or Shapes is way too slow when you get to 100+ items. The best approach to handle a very large number of items entails using double-buffering with your own managed buffer of the image and a structure to handle the clicks. I have posted my project which should give you a good start. It can be obtained at:
http://sourceforge.net/projects/xlightsdesigner/
You are interested in the Controls\ChannelitemsCanvas.cs. It can be modified to suit your needs and uses a quad-tree to store the rectangles so that click events can be quickly determined.

Quick loading and display of images in a picturebox

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.

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

Categories