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.
Related
I need to show an animated gif, which I retrieve as a BLOB from a database (rather than a file), on a PictureBox, but I can't block the UI. The user can press a button that stops the referred animation.
So I create a UserControl that contains the PictureBox, where I can set the image to be shown. When I put this control on the form and starts the animation, everything occurs as expected, except for the fact that I can't press the button, 'cause the form is blocked.
When I start the animation from a Thread, the button are enabled and clickable, but in this case the animation "flickers".
I can easily change the PictureBox to another component, since it can show animated gifs. I can also transform the animated gif to some other format, if needed...
Note that
My images are animated gifs that came from BLOB's on a database and not normal files
I do not want (in fact, It's forbidden, by requirements) create a file with the images (even a temporary file)
Any thoughts?
My images are retrieved from a SQLite database, where they are stored as BLOBs. My requirements forbid the creation of files, even temporary ones. So I did it working exclusively on memory.
This code gets the image, decomposes it on frames and sets the image of the PictureBox to be each frame at a time:
byte[] img = limg.getImage();
if (img != null)
{
MemoryStream ms = new MemoryStream(img);
newImg = System.Drawing.Image.FromStream(ms);
GifImage gi = new GifImage(newImg);
for (int i = 0; i < gi.GetFrameCount; i++)
{
this.SetPicture(gi.GetNextFrame(), limg.getWord());
}
}
And this is the code that sets the image to the PictureBox (note the Sleep, that allows adjust the speed of the animation):
private void SetPicture(System.Drawing.Image img, string label)
{
if (pbOutput.InvokeRequired)
{
pbOutput.Invoke(new MethodInvoker(
delegate()
{
pbOutput.Image = img;
pbOutput.Refresh();
Thread.Sleep(Interval);
}));
}
else
{
pbOutput.Image = img;
pbOutput.Invalidate();
Thread.Sleep(Interval);
}
}
The problem, as said on the question, is the flickering of the image caused by this code.
The solution: substitutes the call of SetPicture by the code of the function. That way, I don't call a function, and put the code of it "inline" the main loop.
The flickering does not occurs anymore.
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
I was wondering if someone can direct me or guide me in order to use a .gif image and convert it into a .bmp strip image file.
First, you need to get the gif's size. Then you need to find out how many frames there are.
After that you need to create a new image with Height = original height, and Width = Frames * Gif Width.
Then you must paste the original Gif's frames into the strip like so: Frame N starts at pixel N*Width.
That is if you're making a horizontal strip.
And here is the complete code for a console application:
using System.Drawing;
using System.Drawing.Imaging;
foreach (var arg in args)
{
Image gif = Image.FromFile(arg);
FrameDimension dim = new FrameDimension(gif.FrameDimensionsList[0]);
int frames = gif.GetFrameCount(dim);
Bitmap resultingImage = new Bitmap(gif.Width * frames, gif.Height);
for (int i = 0; i < frames; i++)
{
gif.SelectActiveFrame(dim, i);
Rectangle destRegion = new Rectangle(gif.Width * i, 0, gif.Width, gif.Height);
Rectangle srcRegion = new Rectangle(0, 0, gif.Width, gif.Height);
using (Graphics grD = Graphics.FromImage(resultingImage))
{
grD.DrawImage(gif, destRegion, srcRegion, GraphicsUnit.Pixel);
}
}
resultingImage.Save("res.png", ImageFormat.Png);
}
The resulting image is saved in the compiled console app binary file directory under the name res.png. You can make the app save the resulting image right where the source file is, ask whether to make a horizontal or vertical strip, etc.
Making an image strip can be easily done with Photoshop (you can get a free trial version, or Elements)
Open .gif - Photoshop will open each frame as a layer
Resize canvas to (height of the gif * layers) pixels
Remove all frame information, keep layers
Select last layer, and move it to very bottom
Select all layers and click 'Distribute vertical centers'. Now you have a perfectly arranged strip.
If you are using Photoshop, you can just export as BMP. Thats it.
The method what works for sure is:
Download an install Easy GIF Animator
Open tour gif with it and export the frames to separate files
Download and install any program which can create the layers (eg. Photoshop CS3 Little)
Create a new file width as your picture; Height = Height of Your pic. X number of pictures
Copy each pic. as a layers in to Your new file and move them one after the other.
Save it as a .png file
Download an install iPAQ 31x Image Explorer
Open Your .png in it
Save it as aRGB file (normal BMP may don't work)
DONE!!
Maybe it's not the easiest method but it gives the possibility of precise editing and allows you to make strips of icons that are on a transparent background (but not limited to icons)
Just load .gif in Bitmap and save it in .bmp. If you want to export the frames of .gif I have no idea how to do this. You can have look at this www.eggheadcafe.com/articles/stripimagefromanimatedgif.asp, it seems to be what what you're looking for.
How can I use trackview or timeline in Naudio in C#?
Here is my code and it's not working.
I want to see my line going as track is playing.
NAudio.Wave.WaveStream pcm = NAudio.Wave.WaveFormatConversionStream.CreatePcmStream(new NAudio.Wave.Mp3FileReader(open.FileName));
customWaveViewer2.WaveStream = pcm;
stream = new NAudio.Wave.BlockAlignReductionStream(pcm);
trackView1.NowTime = stream.CurrentTime;
Unfortunately, TrackView and TimeLine are not completed controls, and you would be better off writing your own custom control to place a vertical line at a position that represents the now playing time.
You would probably be best using a timer to invalidate your custom wave viewer, and in the Paint method, drawing a vertical line that represents the current play time.
So I have a custom Button class in a Winforms app written in C# 4.0. The button holds a static image normally, but when a refresh operation takes place it switches to an animated AJAX-style button. In order to animate the image I have a timer set up that advances the image animation on every tick and sets that as the button image. That's the only way I can get it to work. The solution I have isn't that efficient; any advice would be helpful.
So two questions:
1. Is there an easier way - as in am I overlooking some feature I should be using?
2. Is there a better way to manually animate the image?
Find code below of what I'm doing on each tick. The first area of improvement: maybe copy each frame of the image to a list? Note the _image.Dispose(); failing to dispose of a local Image was causing memory leaks.
Thanks for any advice here. I will post something online and link it once I have an efficient solution.
private void TickImage()
{
if (!_stop)
{
_ticks++;
this.SuspendLayout();
Image = null;
if(_image != null)
_image.Dispose();
//Get the animated image from resources and the info
//required to grab a frame
_image = Resources.Progress16;
var dimension = new FrameDimension(_image.FrameDimensionsList[0]);
int frameCount = _image.GetFrameCount(dimension);
//Reset to zero if we're at the end of the image frames
if (_activeFrame >= frameCount)
{
_activeFrame = 0;
}
//Select the frame of the animated image we want to show
_image.SelectActiveFrame(dimension, _activeFrame);
//Assign our frame to the Image property of the button
Image = _image;
this.ResumeLayout();
_activeFrame++;
_ticks--;
}
}
I guess Winforms is not so reach in animation capabilities on its own. If you want more advanced animation use may consider some third-party solutions.
I think you should not load image from resource every tick. The better way is to preload image frames one and hold the reference. Then use it to set appropriate frame every tick.
As I've recently tested, animated gifs are animating well without any additional coding, at least on standard buttons. But if you still need to aminate frames manually, you may try something like this:
// put this somewhere in initialization
private void Init()
{
Image image = Resources.Progress16;
_dimension = new FrameDimension(image.FrameDimensionsList[0]);
_frameCount = image.GetFrameCount(_dimension);
image.SelectActiveFrame(_dimension, _activeFrame);
Image = image;
}
private void TickImage()
{
if (_stop) return;
// get next frame index
if (++_activeFrame >= _frameCount)
{
_activeFrame = 0;
}
// switch image frame
Image.SelectActiveFrame(_dimension, _activeFrame);
// force refresh (NOTE: check if it's really needed)
Invalidate();
}
Another option is to use ImageList property with preloaded static frames and cycle ImageIndex propery just as you do it with SelectActiveFrame above.