Is it possible to create tiled GIF images with Magick.NET?

Feb 26, 2015 at 12:18 PM
Edited Feb 26, 2015 at 12:27 PM
So, is it possible to create tiled GIFs? This image might help to understand what i want:

http://upload.wikimedia.org/wikipedia/commons/a/aa/SmallFullColourGIF.gif

Essentialy you can make multiple frames/tiles that overlap eachother and are all shown at once, since every frame is transparent except on its own subimage it creates what is shown in the picture above. Every frame/tile has his own pallete ofcourse

I tryed using those samples
https://magick.codeplex.com/wikipage?title=Combining%20images

and comnbing them, essentialy i used the Mosaic option and tryed saving it as a gif but it didnt work, only the last frame was saved.

Using a animation delay of 0 also doesnt work.
Coordinator
Feb 26, 2015 at 8:23 PM
Edited Feb 26, 2015 at 8:25 PM
You should scroll down a bit more. The mosaic example is not the example for an animated gif. You should use the one that says 'Create animated gif.'. For your case this means that you have to add an image for each frame to a MagickImageCollection. The following will show you what the person that created the SmallFullColourGIF.gif had to add to the collection to create that image:
// Load Image
using (MagickImageCollection images = new MagickImageCollection(@"C:\SmallFullColourGIF.gif"))
{
  // collection.Optimize will create frames with only the difference this method makes sure each
  // frame is a complete image instead of just the changes between each frame
  images.Coalesce();

  int i = 0;

  // Save each frame to a file
  foreach (MagickImage image in images)
  {
    image.Write(@"D:\SmallFullColourGIF-" + (i++) + ".gif");
  }
}
Feb 27, 2015 at 5:29 AM
Edited Feb 27, 2015 at 5:32 AM
Yes i did use the 'Create animated gif.' example, but didnt come up with a solution, how exactly do i add multiple images to a single frame? What i have for now are 4 of these images and i want to add them to a single gif image in a single frame each with its own pallete (this is just a test case)
imgur
using (MagickImageCollection collection = new MagickImageCollection())
{
    for (int a = 0; a < subImages.Count; a++)
    {
        collection.Add(new MagickImage(subImages[a].fullBmp));
        //collection[a].AlphaColor = subImages[a].transparent;
        //collection[a].Alpha(AlphaOption.Copy);
        //collection[a].AnimationDelay = 400;
        QuantizeSettings settings = new QuantizeSettings();
        settings.ColorSpace = ColorSpace.RGB;
        settings.Colors = subImages[a].palette.Count+1;
        collection[a].Quantize(settings);
    }

    //collection.Optimize();
    collection.Coalesce();
    collection.Write("output.gif");
    /*using(MagickImage result = collection.merge())
    {
         result.Write("output.gif");
    }*/
}
I know that you can assing a color per palette to be transparent in a GIF image but i dont know if i am doing that right also. Anyways i tryed all of the combinations to get the result i want but it doesnt seem to be happening. I tryed using every AlphaOption with every MagickImage result = collection.() that could do what i wanted to do but nothing seems to get me the right thing.

Is there anything i am missing?
Coordinator
Feb 28, 2015 at 6:07 PM
Edited Feb 28, 2015 at 6:08 PM
What you should do with your input images is change the black color to transparent. You can do this with the Opaque method. Below is an example.
using (MagickImageCollection images = new MagickImageCollection())
{
  for (int i = 1; i <= 4; i++)
  {
    // This is where I put your images an numbered them 1 to 4
    MagickImage image = new MagickImage(@"C:\input\" + i + ".png");

    // I lowered this value to make the animation faster
    image.AnimationDelay = 35;

    // We don't need to change the first image because we want to keep
    // the black background
    if (i > 1)
    {
      // This will tell the gif to keep the previous image and put this image
      // on top of the previous frames.
      image.GifDisposeMethod = GifDisposeMethod.None;

      // This changes the 'black' color to 'transparent', we need to add the
      // color fuzz because the black background is not completely black.
      image.ColorFuzz = new Percentage(10);
      image.Opaque(new MagickColor("black"), MagickColor.Transparent);
    }

    // Add frame to the collcation
    images.Add(image);

    // Writing the frame so you can see how it looks like
    image.Write(@"C:\output\frame" + i + ".gif");
  }

  images.Write(@"C:\output\animation.gif");
}
Mar 2, 2015 at 11:55 AM
Ok, i am getting closer this code was a nice help. I come to this point currently
http://i.imgur.com/Gyjs3G4.gif
Now the only thing i want is to actualy get rid of the animation but i dont think this is possible without comprimising the quality (since right now its actualy true color), every 8x8 pixel frame has its own palette.

I dont know if it was understood what i wanted, essentialy now i want to combine all those frames into one frame as tiles where each tile has its own pallete like now.

Anyways thanks for the help so far!
Coordinator
Mar 2, 2015 at 3:35 PM
You want to create an animated gif that does not animate?
Mar 3, 2015 at 5:30 AM
I try to explain it again. This is the input picture http://i.imgur.com/UQdIpTM.png , if i convert this picture directly into a gif i get this http://i.imgur.com/eL7PvWD.gif , because a gif can only have 256 colors (or 255 with a transparent one) so you get a loss of colors. Now if i take smaller tiles from the original picture and create a custom palette from for each tile i can get the original colors back 1:1 without any loss the current result of this is http://i.imgur.com/Gyjs3G4.gif

This is a animated picture where each frame is a 8x8 square and the previous frames are left as background. Now i want to do one of the following 2 things:
  • Leave the current result gif as it is (http://i.imgur.com/Gyjs3G4.gif) and somehow make it stop repeating after the last frame is shown so that after it goes through all frames once it stops at the last frame and simply shows every frame(none of them actualy overlap and just have transparent parts where the other frames are). I dont know if this is possible.
  • The second solution (which i know its possible but dont know how to do it or if magick supports it) is to take each frame of the current result gif(http://i.imgur.com/Gyjs3G4.gif) and save it in one frame as tiles where each tile still has its own color palette and is again a 1:1 copy of the original image.
Coordinator
Mar 3, 2015 at 10:57 AM
Thanks for the explanation, I am now getting what you are trying to accomplish.

An answer to your first question is that you can set the number of animation iterations with the AnimationIterations property of MagickImage. Setting it to 1 will prevent the loop. I don't understand the second solution so I cannot help you with that. I think ImageMagick will use a color palette for each frame anyways.
Mar 3, 2015 at 11:19 AM
Hm, only MagickImage has the AnimationIterations property right? I am setting it like this but it doesnt seem to work
using (MagickImageCollection collection = new MagickImageCollection())
{
    for (int a = 0; a < subImages.Count; a++)
    {
        //fullBmp are sized 128x128 but only a 8x8 square within it is actualy colored everything else is a single color which gets coded as transparent
        MagickImage mi = new MagickImage(subImages[a].fullBmp);
        mi.GifDisposeMethod = GifDisposeMethod.None;
        mi.Opaque(new MagickColor(subImages[a].transparent), MagickColor.Transparent);
        mi.AnimationIterations = 1;
        mi.AnimationDelay = 1;
        collection.Add(mi);
    }

    collection.Coalesce();
    collection.Optimize();
    collection.Write("output.gif");        
}
Do i need to set it somewhere else?

Also if i try to explain the second solution again, the goal essentialy is to show every frame of the gif (http://i.imgur.com/Gyjs3G4.gif) at once without any animation between the frames. The gif format can accomplish this with multiple tiles inside a single frame, but as i said again i dont know if thats possible to do in magick.net
Coordinator
Mar 7, 2015 at 12:02 PM
I did some experimenting and I came up with the following code:
// Could be larger but this works if every pixel in the block has a different color
int blockSize = 16;

using (MagickImage image = new MagickImage("input.png"))
{
  using (MagickImageCollection gif = new MagickImageCollection())
  {
    MagickImage background = new MagickImage(MagickColor.Transparent, image.Width, image.Height);
    background.AnimationIterations = 1;
    background.GifDisposeMethod = GifDisposeMethod.None;
    background.AnimationDelay = 0;
    gif.Add(background);
    
    for (int x = 0; x < image.Width; x += blockSize)
    {
      for (int y = 0; y < image.Height; y += blockSize)
      {
        MagickImage subImage = image.Clone();
        int subImageWidth = Math.Min(image.Width - x, blockSize);
        int subImageHeight = Math.Min(image.Width - x, blockSize);

        subImage.Crop(new MagickGeometry(x, y, subImageWidth, subImageHeight));
        subImage.GifDisposeMethod = GifDisposeMethod.None;
        subImage.AnimationDelay = 0;

        gif.Add(subImage);
      }
    }
  
    gif.Write("output.gif");
  }
}
But this does not work in most browsers. Using the GIF wiki page (that explains it won't work in most browsers) I found the following example: http://phil.ipal.org/tc.html. If you open it in IE or Chrome it will show an animation. If you open it in FireFox it will start animating but suddenly it decides to stop that and show the whole image.