Page 1 of 2
Creating a Cleared Frame GIF Animation in the MagickWand API
Posted: 2012-03-07T14:49:56-07:00
by garyb
Hi, I'm trying to use the MagickWand API in Objective-C/iOS to make a "Cleared Frame GIF Animation" in "ImageMagick 6.6.9-7 2011-05-02 Q8" but I have no idea where to begin... as seen at:
http://www.imagemagick.org/Usage/anim_basics/#cleared (With no pause seen in the background.)
I think I would need to use addImage to compile a bunch of transparent image frames (eg: PNGs) into a GIF and then somehow convert this gif to use my background image?
My main goal is to avoid animating the dither in the background between each frame. It looks like this method will give me just that, but again, not sure how to accomplish this with the MagickWand API. It kind of sucks that all the docs/examples are all in command-line mode.
Code: Select all
convert bunny_grass.gif \( bunny_anim.gif -repage 0x0+5+15\! \) \
-coalesce -delete 0 -deconstruct -loop 0 bunny_bgnd.gif
So I guess to sum up, I would somehow need to re-create this using the MagickWand API. If anyone has any pointers or example code, that would be greatly appreciated!
Thanks,
Gary
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-07T16:22:05-07:00
by el_supremo
I've worked out how to do the first stage of Anthony's example.
Perhaps this will give you a head start on the rest of it.
I'll post again if/when I figure out the -coalesce and -deconstruct.
Pete
Code: Select all
// This implements the command:
// convert bunny_grass.gif bunny_anim.gif -loop 0 bunny_on_grass.gif
// from Anthony's examples at: http://www.imagemagick.org/Usage/anim_basics/#cleared
#include <windows.h>
#include <wand/magick_wand.h>
void test_wand(void)
{
MagickWand *mw = NULL;
MagickWandGenesis();
/* Create a wand */
mw = NewMagickWand();
/* Read the input image */
if(MagickReadImage(mw,"bunny_grass.gif"));
if(MagickReadImage(mw,"bunny_anim.gif"));
// do "-loop 0"
MagickSetOption(mw,"loop","0");
/* write the images into one file */
if(MagickWriteImages(mw,"bunny_on_grass.gif",MagickTrue));
/* Tidy up */
if(mw) mw = DestroyMagickWand(mw);
MagickWandTerminus();
}
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-07T17:10:34-07:00
by el_supremo
It wasn't quite as tricky as I thought. Here's the example with coalesce and deconstruct.
I had to use a MagickCore to get at the DeleteImages function.
@ Magick: Can a MagickWand version of DeleteImages be included in a new release - or have I missed (or forgotten) how to do this in MagickWand?
Pete
Code: Select all
// This implements the command:
// convert bunny_grass.gif ( bunny_anim.gif -repage 0x0+5+15! ) \
// -coalesce -delete 0 -deconstruct -loop 0 bunny_bgnd.gif
// from Anthony's examples at: http://www.imagemagick.org/Usage/anim_basics/#cleared
#include <windows.h>
#include <wand/magick_wand.h>
// Need MagickCore for DeleteImages
#include <magick/MagickCore.h>
// and this is needed for the address of the image list (&aw->images)
#include <wand/magick-wand-private.h>
void test_wand(void)
{
MagickWand *mw = NULL;
MagickWand *aw = NULL;
ExceptionInfo *exception;
MagickWandGenesis();
/* Create a wand */
mw = NewMagickWand();
/* Read the input image */
if(MagickReadImage(mw,"bunny_grass.gif"));
//( bunny_anim.gif -repage 0x0+5+15\! )
// We need a separate wand to do this bit in parentheses
aw = NewMagickWand();
if(MagickReadImage(aw,"bunny_anim.gif"));
MagickResetImagePage(aw,"0x0+5+15!");
// Now we have to add the images in the aw wand on to the end
// of the mw wand.
MagickAddImage(mw,aw);
// We can now destroy the aw wand so that it can be used
// for the next operation
if(aw) aw = DestroyMagickWand(aw);
// -coalesce
aw = MagickCoalesceImages(mw);
// delete 0
DeleteImages(&aw->images,"0",exception);
// Now free up the mw wand for the next step
if(mw) mw = DestroyMagickWand(mw);
// -deconstruct
mw = MagickDeconstructImages(aw);
// -loop 0
MagickSetOption(mw,"loop","0");
/* write the images into one file */
if(MagickWriteImages(mw,"bunny_on_grass.gif",MagickTrue));
/* Tidy up */
if(mw) mw = DestroyMagickWand(mw);
if(aw) aw = DestroyMagickWand(aw);
MagickWandTerminus();
}
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-07T19:49:58-07:00
by garyb
Thanks for the help!
I'll give that a shot. It couldn't actually find <wand/magick-wand-private.h> though.
So in turn, DeleteImages(&aw->images, ...) isn't working unfortunately.
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-07T19:51:22-07:00
by anthony
MagickDeconstructImage() is actually just a alias for the Layers method "CompareAny"
however for overlay animations, you can use "CompareOverlay" instead which makes more sense.
"Deconstruct" as an operation should be depreciated.
Is their some reason you want an actual 'overlay' animation? (no transparency in any GIF frame?)
Note that if you do not mind transparency being used in the overlay images, For example something like the bunny animation produces in Transparency Optimization
http://www.imagemagick.org/Usage/anim_opt/#opt_trans
then the layers Optimize method can be used, as a general purpose optimizer. Their is just no guarantee that you will get a 'Overlay Animation'.
You may actually get a 'mixed disposal animation' as IM GIF optimization function thinks the result will be smaller (less pixels changed between each frame update). Note that that does not mean it is less pixels overall, or in fact a smaller file size, as that requires recursive optimization that could take a VERY long time!
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-07T20:06:25-07:00
by anthony
garyb wrote:Thanks for the help!
I'll give that a shot. It couldn't actually find <wand/magick-wand-private.h> though.
So in turn, DeleteImages(&aw->images, ...) isn't working unfortunately.
It is missing as it is 'private'. that is because DeleteImages is not MagickWand, but a lower level MagickCore library function.
Typical way of deleting images, is to destroy the old wand and create a new wand. Or use ClearmagickWand(), whcih is the same thing (I verified it in the code).
Of course any operational settings would also be lost.
NOTE do not extract images and use MagickDestroyImage() as it is also incorrect wand usage, and may infact produce a segmentation fault. It should not be a public function!
That wand function should really take a MagickWand argument and destroy the current image from the wand, allowing you to iterate over the images destroying them. Perhaps a MagickDestroyAllImages() function would also be useful addition.
This was something I only recently discovered as I develop Imv7 Shell API. That API is already much more closely liked to MagickWand API by using a expanded form of MagickWand - a "MagickCLI Wand" in fact
-- Interesting times ahead for MagickWand!
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-08T07:45:59-07:00
by el_supremo
I should have mentioned that I am using Version 6.7.3-3 Q16 which is a bit behind the times.
@Anthony: The "MagickCLI Wand" sounds very interesting. Looking forward to seeing it.
Pete
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-08T07:47:20-07:00
by garyb
anthony wrote:
Is their some reason you want an actual 'overlay' animation? (no transparency in any GIF frame?)
Note that if you do not mind transparency being used in the overlay images, For example something like the bunny animation produces in Transparency Optimization
http://www.imagemagick.org/Usage/anim_opt/#opt_trans
then the layers Optimize method can be used, as a general purpose optimizer. Their is just no guarantee that you will get a 'Overlay Animation'.
You may actually get a 'mixed disposal animation' as IM GIF optimization function thinks the result will be smaller (less pixels changed between each frame update). Note that that does not mean it is less pixels overall, or in fact a smaller file size, as that requires recursive optimization that could take a VERY long time!
I know it's kind of a lofty goal, but if there's another method that gives me the effect of a static background underneath frames, no jitter/animated in the background's dither between frames, is fast-ish to run and gives a fairly small file size, I'd love to hear it!!
I don't neccessarily need transparency in the final GIF since each frame will have the background under them. I just saw this:
This is good enough for most purposes. For example by using the 'Dst_Over' composition method you could also place an image 'under' the animation as a static background.
From:
http://www.imagemagick.org/Usage/anim_m ... mpose_draw which sounds good to me! So is it easy to run this command:
Code: Select all
convert script_k.gif -repage 100x100+20+20\! -coalesce \
-draw 'image DstOver 0,0 0,0 "granite:"' \
-layers Optimize script_k_granite.gif
in the MagickWand API?
Question: I noticed this operates on a previously created GIF - "script_k.gif" - is there any way to do it all in one MagickWand session? (eg: create the GIF
and at the same time overlay the frames on a background)
Question: Will it also have the weird 0-delay extra frame that I have to remove?
I *also* experimented with using:
Code: Select all
MagickOrderedPosterizeImage(wand, "o8x8,13")
but I found that a) there was still some animated dither between frames in some areas, and b) I like the look of the "regular" dithered image instead of the posterized dither.
Thank you so much for the help.
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-08T08:47:15-07:00
by el_supremo
Typical way of deleting images, is to destroy the old wand
In this case we don't want to destroy all the images in the wand - only remove the first one. I'll have a look at doing it by iterating over the images and copying all but the first into a new wand.
To fix up the use of Deconstruct
change this:
Code: Select all
mw = MagickDeconstructImages(aw);
to this:
Code: Select all
mw = MagickCompareImageLayers(aw,CompareAnyLayer);
Pete
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-08T10:19:42-07:00
by el_supremo
I've reworked my previous code so that it does not use MagickCore and it uses CompareImageLayers instead of Deconstruct.
The latest iteration of the code is in my MagickWand examples at:
http://members.shaw.ca/el.supremo/MagickWand/bunny.htm
Pete
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-08T12:24:07-07:00
by garyb
Thanks for posting that Pete! Is there any other official MagickWand way to delete a frame at a specific index, rather than loop through the entire image sequence and copy out every frame except 0? Seems kind of silly/overhead.
Edit: Also, apparently
MagickCompareImageLayers only works with "Image *images" instead of a MagickWand?
Thanks,
Gary
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-08T13:58:05-07:00
by el_supremo
Is there any other official MagickWand way to delete a frame at a specific index
Not that I know of.
rather than loop through the entire image sequence and copy out every frame except 0? Seems kind of silly/overhead
The underlying images are in a doubly-linked list so it would seem to be much easier for IM to delete the images.
apparently MagickCompareImageLayers only works with "Image *images" instead of a MagickWand?
No, the first argument to that function is a MagickWand and it returns a MagickWand.
Pete
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-08T14:15:33-07:00
by garyb
el_supremo wrote:Is there any other official MagickWand way to delete a frame at a specific index
Not that I know of.
I found
RemoveZeroDelayLayers but it looks like that's a MagickCore function. Oh well, just curious.
el_supremo wrote:rather than loop through the entire image sequence and copy out every frame except 0? Seems kind of silly/overhead
The underlying images are in a doubly-linked list so it would seem to be much easier for IM to delete the images.
That went over my head, but if you say so, then sounds good to me!
el_supremo wrote:apparently MagickCompareImageLayers only works with "Image *images" instead of a MagickWand?
No, the first argument to that function is a MagickWand and it returns a MagickWand.
No idea why I thought that! I must have been trying a different similarly-named function. Oops.
Anyway, thanks a ton!!
PS:
If I could pick your brain once more, any idea why this isn't working?
http://www.wizards-toolkit.org/discours ... =6&t=20482
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-09T00:02:02-07:00
by anthony
garyb wrote:I know it's kind of a lofty goal, but if there's another method that gives me the effect of a static background underneath frames, no jitter/animated in the background's dither between frames, is fast-ish to run and gives a fairly small file size, I'd love to hear it!!
I don't neccessarily need transparency in the final GIF since each frame will have the background under them.
Either pre-dither the background before overlaying the image, especially with a fixed palette. OR use ordered-dither for the dithering.
Note dithering for small numbers of colors (or fixed palette) really needs a overhaul in IM. For example ordered dither with a user supplied palette would be a great addition! Unfortunately I have no time for it, though I do have links for it.
Question: I noticed this operates on a previously created GIF - "script_k.gif" - is there any way to do it all in one MagickWand session? (eg: create the GIF and at the same time overlay the frames on a background)
Question: Will it also have the weird 0-delay extra frame that I have to remove?
If you overlay their should be no 0-delay frame. And their is no reason the background animation (or static image) has to be external. What is needed however is that rather than a "null:" seperator image (required for CLI whcih only has one active Image List (or wand), the MagickWand API should be merging two separate wands! I designed the Core API to allow this, but I don't think who ever added it to the API is taking advantage of that!
I *also* experimented with using:
Code: Select all
MagickOrderedPosterizeImage(wand, "o8x8,13")
but I found that a) there was still some animated dither between frames in some areas, and b) I like the look of the "regular" dithered image instead of the posterized dither.
The problem is that it is a fixed mathematical palette and not one designed for the images! As for the existing dither, that could only mean their is color differences between the frames that the ordered dither is enhancing! Remove that difference (from due to saving to intermediate image) and it should go away.
Re: Creating a Cleared Frame GIF Animation in the MagickWand
Posted: 2012-03-09T00:09:43-07:00
by anthony
el_supremo wrote:Is there any other official MagickWand way to delete a frame at a specific index
Not that I know of.
Definatally need to get MagickDeleteImage() function to delete current image from MagickWand! As well as a MagickDeleteAllImages() function. Depreciate the useless to the API function MagickDeleteImages()
I will added these changes to at least IMv7 Wand API, but will look at back-porting them the current IMv6 too.