AnimStack: animation tools for GIMP 2.8
- May 2, 2016 - AnimStack 0.62 is a bugfix release, fixing Unicode handling
- May 19, 2013 - AnimStack 0.61 is a bugfix release, fixing very stupid bug with [render]
- April 17, 2013 - AnimStack 0.6 is released! See release notes in the comment section.
Watch video tutorials here: YouTube
Also check out the official AnimStack tumblr: animstack.tumblr.com
AnimStack is a collection of tools to simplify creating animations in GIMP. It makes heavy use of Layer Groups, introduced in GIMP 2.8.
A simple example of a problem this script might solve: you have an animation, but you want to put some text on top of it. Normally you would have to add text to every frame manually, but with AnimStack this task is completely automated. AnimStack is perfect for post-processing your GIF animations and adding various simple effects to them.
To get an overview of available features please watch the video: http://youtu.be/lHKx0g8xEl4
The main command of this script, "Process AnimStack Tags" is located in Filters > Animation. Read more about how to use the tags below the cut.
Because layer groups is a recently introduced feature of GIMP, working with them might be clunky. For that reason, I'm also bundling a few tools that might help dealing with them. The following tools are under Image menu:
- Flatten Layer Groups (also packaged separately at http://registry.gimp.org/node/26479)
- Reverse/Mirror layers - this tool allows to reverse the order of layers in an image or a layer group. The Mirror option keeps the original layers, but also adds those layers in reverse order above them except for the first and the last one (this effect is also known as Ping-pong). There is also an option to ignore layers that have AnimStack tags on them.
The next three tools are under Layer > Group menu:
- Pack linked layers - puts all linked layers in a layer group
- Copy linked layers - puts duplicates of all linked layers in a layer group
- Unpack layer group - puts all layers in a layer group outside of it
The main concept of AnimStack is a tag. There exist different types of tags: action tags, effect tags, generator tags, multiply tags and label tags. Each top-level layer or layer group might have one or several tags attached to it. To add a tag to a layer, put it in that layer's name. The order of the tags is significant, but their placement relative to the layer's original name isn't. All AnimStack tags are removed once they are processed, usually together with the layer they were on.
Tags are enclosed in square brackets. Each tag generally starts with an identifier and is followed by optional parameters, separated by ":" ([identifier:param1:param2:…]). The exact nature of identifier and parameters differs for different types of tags.
Multiply tags are the simplest type of tag. The syntax is "[*n]" where n is a positive integer. For example "[*6]" is a valid multiply tag. Multiply tags accept no parameters.
(new in 0.6) Label tags are tags with empty identifier. They accept one parameter, which is the name of the label. By default a label has an empty string as a name. For example tag "" is a label with name "", whereas "[:abcd]" is a label with name "abcd". You should generally stick to alphanumeric characters when naming your labels.
Action tag is the default type of tag, and the most important one. The syntax is "[action:param1:param2:…]". All parameters must be integers. For example "[roll:1:10]" is a valid action tag. There are several modifiers that can be attached to action name.
- A "." character before the action name (e.g. "[.roll:1:10]"). This makes an action "non-cumulative". Actions are "cumulative" by default.
- (new in 0.6) A "~" character before the action name (e.g. "[~fg]"). This makes an action work in reverse direction.
- (new in 0.6) An action tag can be assigned a terminating label, by adding ">label" at the end of action name (e.g. "[bg>end]").
Generator tags allow to introduce variables to be used by effect tags. The syntax is "[variable=generator:param1:param2:…]". Each parameter must be a number. For example "[foo=cycle:0:10:20]" is a valid generator tag.
Since version 0.5, it is possible to add arithmetic adjustments to any generator. The syntax is "[variable=offset+multiplier*generator:…]". Either of "offset+" and "multiplier*" can be omitted.
Effect tags have the most complicated syntax. First off, the tag's identifier must start with one of three symbols: "!", "-", "+". If the tag starts with "!", it's considered an "initial" effect, otherwise it's a "runtime" effect. Syntax for an initial effect is as follows: "[!effect:param1:…]". Syntax for a runtime effect is as follows: "[<-/+>range;effect:param1:…]". Range can be omitted (and usually is). Parameters must be numbers; in case of runtime effects, variables introduced by generator tags on the same layer are also allowed, and (new in 0.6) you can also add arithmetic adjustments to them (see generator tags).
The following are examples of valid effect tags: "[!scale:0.5]", "[-scale:x]", "[+move:10:5+-2*y]" (use generator assigned to variable y, multiply it by -2 and add 5).
Since version 0.5, [;effect:…] is a shortcut to [-;effect:…].
It is possible to specify a range of layers that a runtime effect tag affects. A range is a comma-separated list of "atomic" ranges that ends with a semicolon. Each range represents a set of non-negative integers. The atomic ranges can be one of:
- n - a non-negative integer (e.g. 0, 4, 100).
- n- - every integer larger than or equal to n.
- n-m - every integer from n to m, inclusive.
- /n - every n-th integer, starting from 0.
- m/n - every n-th integer, starting from m.
- rn - executed randomly 1 out of n times.
- mrn - executed randomly m out of n times.
A range that consists of several atomic ranges represents their union. In addition, an empty range represents every non-negative integer, including 0. This is important, since by default (i.e. when the range is omitted altogether) the range is considered to be every positive integer, 0 not included.
Examples of valid ranges:
- ";" - 0, 1, 2, 3, 4, 5, …
- "1,5-;" - 1, 5, 6, 7, 8, …
- "/3;" - 0, 3, 6, …
- "1/3;" - 1, 4, 7, …
- "1-5,2/4;" - 1, 2, 3, 4, 5, 6, 10, 14, …
Order of processing
The layers are processed top to bottom. At the first stage all multiply and label tags are processed. If a layer is encountered that has a multiply tag, it is duplicated the required amount of times. The original layer is deleted. If a layer has several multiply tags, only the first one is processed.
(new in 0.6) A layer can have several label tags attached to it. They are processed and removed at this stage, but AnimStack remembers which layers had which labels until the end of the entire process. If a layer is later converted into a layer group, the label is transferred to the layer group, but aside from that, label assignments do not change.
Once all the multiply and label tags have been processed, we start from top to bottom again. Once a layer with an action tag is encountered, things start to get interesting. First off, only the first action tag actually does anything, all subsequent ones are ignored. The layer might also have several generator and effect tags attached to it. As of version 0.3, if there's a runtime effect tag present, but no action tag, "[noop]" action tag is assumed.
AnimStack tries to determine the action that the action tag corresponds to. If it doesn't recognize the action, the layer is skipped altogether, and subsequent actions will also ignore it.
Once the action is started, all initial effects are executed, in order. Every action consists of several steps, which are numbered starting from 0. The step's number affects the values returned by generators, and whether a runtime effect is executed based on its range.
Each step of the action usually involves making a copy of the "source" layer and placing it into the "target" frame. An effect might affect either the source (most commonly) or the target. The difference between cumulative and non-cumulative actions comes into play here: if the action is cumulative, the effect is performed on the original source layer before it is copied and put into the target frame. If the action is non-cumulative, the effect is performed on the copy, after it has been added to the frame. At every step all the runtime effects are executed, in order. If there are variable parameters, they are substituted with the values generated by generators at the beginning of each step. (new in 0.6) One generator named "i" is always present, it simply generates the number of the current step.
There are two types of runtime effects, "+" and "-". They produce different results only with "roll" or "splice" actions. A "+" effect affects every layer in the roll at each step. A "-" effect affects only the current layer of the roll.
(new in 0.6) If the action had a terminating label attached to it, the action will stop after it reaches the frame tagged with this label (the action will be performed on this frame, but not on any frame after that).
All parameters are optional. You can omit any parameters from the end. As of AnimStack 0.5, you can also pass an empty string as a parameter. For example both "[copy:0]" (omitting the limit parameter) and "[copy::5]" (skipping the position parameter) are legal tags.
- bg:limit - walks up from the tagged layer, placing copies of it at the bottom of every untagged frame it encounters. If limit is supplied, at most limit frames are affected. This is useful for static backgrounds.
- fg:limit - walks down from the tagged layer, placing copies of it at the top of every untagged frame it encounters. If limit is supplied, at most limit frames are affected. This is the only tag that walks down. It is useful for static foregrounds, such as text.
- copy:position:limit - a more general version of bg tag, it allows to specify position within frame (see below). The position is -1 by default, which makes "[copy]" equivalent to "[bg]". If limit is supplied, at most limit frames are affected. It is useful when you want to insert a static element at specific position.
- roll:position:limit:roll-offset - works like copy if a single layer is tagged with it. However when it tags a layer group, the sublayers are cyclically picked starting from the bottom and inserted into untagged frames at a given position (-1 by default). If limit is supplied, at most limit frames are affected. If limit is 0 or less, it is considered to be infinite. If roll-offset is supplied, the starting layer is not the bottom layer, but the roll-offset'th starting from the bottom. This tag allows to insert one animation into another. Use repeat effect tag to repeat each layer from the roll several times.
- splice:position:roll-offset - a less general version of roll, it sets roll's limit to the number of sublayers in a tagged layer group. This means every sublayer is inserted at most once. It is useful for inserting a non-looped animation.
- noop:limit or no:limit - this action works like bg, except it doesn't actually place the source layer anywhere. It is only useful for effects that affect the target layer, such as the "delay" effect.
- matte:threshold:limit - applies matte effect to preserve partial transparency in GIF files. Works similar to bg, except when the target frame has a pixel with transparency value less than threshold (1 by default), this pixel is removed from the copy of the source layer. See http://youtu.be/49FGgONSduM for example.
- delete:period:width:limit - for every period frames, delete the first width frames. By default, period is 2 and width is period-1, so every second frame is deleted.
- render:limit:replace:only:interval - renders each frame into a single layer and puts that layer on top of the frame. If replace is greater than 0, delete every other layer in the frame. If only is provided, it is treated as a "position" argument. The layer at that position is rendered (usually just duplicated unless it's a layer group) and put at that position (if replace is on, the original layer is removed). This tag is useful for modifying the already existing frames instead of adding new layers into them like bg and friends do. replace argument is useful to get rid of the layers you don't need anymore. only allows to apply some effects to a single layer at specific position. Since AnimStack 0.5, if replace is less than 0, the rendered layer is inserted under whatever it was rendering (a single position or the whole frame). interval parameter was added in 0.6 and allows to render several layers in a frame if only is set. It denotes how many extra frames to render and in which direction they are counted starting from only. For example, interval=1 will render layer at position only and the one below it. If interval is negative, it will render layers above only.
sampler:position:count:limit:roll-offset:width:height - this is arguably the most complex tag yet. Basically there's a source image, or a series of images. Then there is also a bunch of rectangular areas, which I call nodes. A temporary layer is created with a specified width and height. At step 0, sampler uses the first node to cut a rectangular area from the source image and scale it into the temporary layer. This layer is then added at position to a target frame. Then it moves towards the second node with rectangular area gradually changing in a linear fashion. There are count steps to reach the last node, however by setting limit it is possible to end the path before it finishes.
- The thing tagged with sampler should preferably be a layer group. The bottom of this layer group is treated as the source and everything above it as nodes. Nodes should be layers with boundaries contained within the boundaries of the source layer(s); their contents do not matter. Nodes are ordered from bottom to top.
- position is -1 by default.
- If count is 0 (which is default), it is set equal to the number of untagged frames after the sampler. If count is negative, it is set to the number of frames in a roll. The number of nodes cannot be greater than count.
- limit is by default equal to count and cannot be greater than count. Both limit and count can be set to 0 to be calculated automatically.
- roll-offset - if has a non-negative value, treat source as a roll with given offset. Basically you can pan around another animation.
- width and height are equal to image size by default. You might want to change image canvas size to avoid setting them manually.
- sb and delay effect tags behave differently when used with sampler action tag. See their documentation for details.
dt:direction - this tag creates a duplicate tree. Depending on direction, it duplicates the target frame several times, placing copies below (0) or above (1) it. The default direction is 1. I'm going to assume this to be the case for now. Similarly to sampler, dt tag should be placed on a layer group. At the bottom of this layer group should be a layer or a layer group tagged with one of the "normal" action tags (that is, not another dt tag). This tag is processed as usual, except the target frame is duplicated according to the other contents of the duplicate tree.
- The duplicate is created for every layer inside dt, except for the bottommost one with the action tag.
- A layer group creates a new branch within the tree.
- By default, the previous duplicate is used as a basis for the copy. If dt is in non-cumulative mode ([.dt]) the root of the branch is used as a copy.
- Every duplicate may have some effects attached to it (including both "before" and runtime effects). These are applied regardless of their range to this duplicate.
- Every branch may also have some effects attached to it. Including the top-level branch, which is tagged with dt. The runtime effects are applied to every duplicate inside this branch. The "before" effects are applied only to those duplicates that copy the root of the branch and not the subsequent ones. Ranges are also ignored for these effects.
- The order of execution is: individual "before" effects, branch "before" effects, branch runtime effects, individual runtime effects. Inner branch effects are executed after outer branch effects.
- If this is confusing, watch the video tutorial for AnimStack 0.5 to see this feature in action.
- If direction is 0, the top layer is the one with the action tag, the duplicates are processed top to bottom and placed below the target frame.
One of possible tag arguments is position within frame. It is an integer number which might be negative. It describes where exactly to put a new layer within each frame. If position is non-negative, it counts from the top, starting from 0 (0 means at the top of layer stack and so on). If position is negative, it counts from the bottom, with -1 being the bottom of the frame's layer stack. If position is out of range for the given layer stack, it just puts the source layer as far from the top/bottom as possible, i.e. at the bottom/top.
- const:value - always returns value (0 by default)
- cycle:value1:value2:… - cyclically returns the supplied values (value1 at step 0, value2 at step 1 and so on). When no parameters, returns 0.
- rng:n - returns a non-negative random number less than n. n=10 by default.
- irng:n - returns a non-negative random integer less than n. n=10 by default.
inc:increment:initial - returns the initial value at step 0, then at each step it increases by increment. By default, increment is 1 and initial is 0.
(new in 0.6) Note that for each layer there is always a generator named i defined like "[i=inc]", which, combined with arithmetic adjustments of parameters makes this generator kinda unnecessary. For example instead of using generator "[x=inc:3:4]" you can use "4+3*i" as a parameter in your effects.
- osc:amplitude:period:phase - a simple harmonic oscillator with amplitude, period and phase. By default, amplitude is 10, period is 10 and phase is a random number from 0 to 1. The phase is normalized for period, i.e the phase 0.25 is 1/4th of the period and so on. This generator allows for "wavy" movements and stuff like that.
- poly:k1:k2:…:kn - produces a polynomial of degree n. Specifically, at step x, the result is k1*x + k2*x^2 + … + kn*x^n. The default values for coefficients are 0, except for the last one. The n-th degree of the polynomial is enforced, so if kn is 0 or omitted, it is set to 1. Note that the polynomial produced by poly has no constant term. You can add a constant using arithmetic adjustment feature of generators.
- dosc:amplitude:period:phase and dpoly:k1:k2:…:kn are derivatives of the above generators. You can use those with drotate effect to correctly rotate your object wrt its trajectory.
- move:x:y - moves the source layer by (x, y). By default x and y are 0.
- offset:x:y:wrap - offsets the source layer by (x, y). By default it "wraps around", i.e. when you offset to the right, the part of the layer that would be no longer visible appears from the left. If you want to disable wrapping, pass wrap=0. If x or y are skipped, the layer is offset randomly by that axis.
- resize - resizes the source layer to image size.
- scatter:mode - moves the source layer randomly so it doesn't go outside the borders of the image (if mode<=0, this is default) or moves the source layer randomly so that part of it is still within image (if mode>0). If you make a rectangular selection, this tag will try to move the layer so that it is inside of the selection. With non-rectangular selection this is not necessarily true, so don't bother.
- shrink:right:bottom:left:top - resizes the source layer by specified amount of pixels from right, bottom, left and top. Negative values will work, but they are not very useful. All parameters are 0 by default.
- scale:hscale:vscale - scales the source layer horizontally and vertically by specified coefficients. By default, hscale is 1 and vscale is equal to hscale.
- stretch:dwidth:dheight - stretches the layer horizontally by dwidth pixels and vertically by dheight pixels (or contracts if the values are negative). By default both parameters are 0.
- rotate:angle:nocrop - rotates the source layer by the specified angle (in degrees) around the center of the layer. By default it autocrops the layer before rotating it. Pass anything as nocrop to disable this. It is not recommended to use this effect with cumulative actions because of quality degradation (and if you disable autocrop beware of exponential layer growth).
delay:delay:delay2 - sets frame delay for target frame (useful for animated GIFs) to delay. Can be used in conjunction with noop action to mass-set delays for large number of frames.
- If used with sampler action tag, delay2 is used for path corners. By default delay2 is equal to delay.
- erase:n:direction - works only on text layers with unformatted text (i.e. no individual formatting for different parts of text as introduced in GIMP 2.8; no bold or italic text either). Erases either the last (if direction<=0, default) or the first (if direction>0) n letters from the text. n=1 by default. Use with fg action to make text appear letter by letter.
- dup:direction - duplicates the target frame and places the duplicate either below (if direction<=0, default) or above (if direction>0) the target frame. The duplicate will not be affected by the current action, but will be by subsequent actions. dup has remarkably different effect depending on whether the action is cumulative or not: in cumulative actions the target frame is duplicated before the source layer is added to it; in non-cumulative actions it happens after.
- mask:from - by default adds layer mask based on the current selection to the source layer. If from is specified, it describes a position inside the target frame. Alpha channel of a layer at that position is used to mask the source layer.
- opacity:opacity - sets opacity of the source layer to opacity (100 by default).
- replace:mode - sets frame disposal mode of a target frame to "replace" if mode>0 (default) or "combine" if mode<0. If mode is 0, clear any frame disposal tags.
- gb:radius-x:radius-y - applies gaussian blur to the source layer. By default radius-x is 0 and radius-y is equal to radius-x.
- mb:dx:dy - applies motion blur to the source layer. By default dx and dy are 0.
- zb:radius:cx:cy - applies zoom blur to the source layer. If radius (0 by default) is negative, zoom is inward. cx and cy are used to position the center of zoom relative to width and height of the image. By default cx and cy are 0.5, which corresponds to the center of the image.
- rb:angle:cx:cy - applies radial blur to the source layer. angle is 0 by default. cx and cy work like in zb.
- sb:kd:kz - does not do anything unless used with sampler action tag. Otherwise, it uses information provided by sampler tag to apply motion and zoom blurs to the source layer. The amount of blur is calculated based on movement in the path and is multiplied by coefficients kd for motion blur and kz for zoom blur. Corners of the path are never blurred. The default values are 10 for both kd and kz.
- invert - inverts color of the source layer.
- threshold:lower:upper - performs a threshold operation on the source layer, making each pixel completely black or completely white (transparency is not affected). Similar to Colors - Threshold tool of GIMP. However, if both parameters are omitted, the layer becomes completely black (again, sans transparency). thr is a shorthand for this tag.
- desaturate:mode - desaturates the source layer. Similar to Colors - Desaturate. The mode is "Lightness" for negative values, "Average" for 0 (default), and "Luminosity" for positive values. des is a shorthand for this tag.
- gradmap:r:g:b - similar to Colors - Map - Gradient Map. If RGB values are provided, the gradient is this color to white. If none of them are provided, the currently selected gradient is used. The effect is similar to desaturate, but with a tint of any color instead of black.
- repeat:n - this effect tag affects only roll, splice and sampler action tags. Basically, when a layer in a roll is picked, this tag makes it being picked n times in a row (if n is a positive number). If n is 0, it will keep picking the same layer. If n is negative, it will start choosing previous layers. Everything is complicated by the fact that n can be changed by generator, or the repeat tag might not have its effect due to being out of specified range. The rule is that if this effect is executed with a positive n, then for the next n-1 steps the same layer is chosen regardless of the presence/absence of repeat tags and their parameters. Generally this shouldn't be an issue, but it's something to keep in mind when you're trying to arrange some complicated pattern to pick layers from a roll.
- crop:margin - autocrop the layer, leaving a margin of margin pixels around it (which is 0 by default).
- drotate:x:y:ix:iy:nocrop - like rotate, but the angle is calculated as arctan(iy/ix)-arctan(y/x). It's the angle by which the vector (ix, iy) must be rotated to point in the same direction as (x, y). By default ix is 0 and iy is -1, which corresponds to object pointing upwards. If x and y are derivatives of the object's position, then "[drotate:x:y]" will rotate the object towards the direction of its movement.
- seed:n - sets random number generator seed to n. This can be used to ensure random effects like scatter and offset behave identically for two different layers. The results of generators rng and irng are also affected.