buttery

package module
v0.0.11 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 14, 2024 License: BSD-2-Clause-Views Imports: 13 Imported by: 0

README

buttery: a video editor with manual motion smoothing

examples/homer.buttery.gif

ABOUT

buttery generates continuous GIF loops.

EXAMPLE

$ buttery homer.gif

See buttery -help for more options.

DOWNLOAD

https://github.com/mcandre/buttery/releases

INSTALL FROM SOURCE

$ go install github.com/mcandre/buttery/cmd/buttery@latest

API DOCUMENTATION

https://pkg.go.dev/github.com/mcandre/buttery

LICENSE

BSD-2-Clause

RUNTIME REQUIREMENTS

(None)

CONTRIBUTING

For more information on developing buttery itself, see DEVELOPMENT.md.

LINT

buttery -check <GIF> can act as a linter for basic GIF file format integrity. In the event of a corrupt GIF file, the program emits a brief message and exits non-zero.

INSPECT

buttery -getFrames <GIF> reports the frame count. This is useful for planning edits, particularly towards the far end of the original animation sequence.

TRANSITIONS

Mirror

The -stitch Mirror option is the primary loop smoothing transition, and the default transition setting.

Mirror twists the GIF timeline around like a Mobius strip, so that it arrives naturally back at the start. This is useful for smoothing GIF's that present misaligned images at the extreme ends of the loop.

We can diagram logically how Mirror works, by examining its effect on the frame sequence. With the notation:

real frame sequence (successive sequence repeated during infinite loop playback...)
Before
1 2 3 (1 2 3 ...)

Each restart of the loop has a jarring visual jump from frame 3 to its successor frame 1.

After
1 2 3 2 (1 2 3 2 ...)

Of course, running the buttery editor yourself is the best way to appreciate how it works.

By mirroring the sequence backward in time, we remove the biggest visual jump. The overall visual effect is that of a sailor rowing back and forth in place. The Mirror transition often dramatically improves the smoothness of a GIF loop.

However, some motion may still appear awkward with mirroring, such as sharp, quick motions towards the extreme ends of the loop, or motions that appear to defy physical entropy. For this reason, we provide alternative transitions and other editing tools, described below.

FlipH / FlipV

The transision settings -stitch FlipH or -stitch FlipV disguise jarring misalignment, by reflecting the frames horizontally or vertically.

With the notation:

  • R: An original "right" frame
  • L: A frame reflected horizontally "leftward"
  • U: A original "upright" frame
  • D: A frame reflected vertically "downward"
Before

FlipH:

R R R (R R R ...)

FlipV:

U U U (U U U ...)
After

FlipH:

R R R L L L (R R R L L L ...)

FlipV:

U U U D D D (U U U D D D ...)

The FlipH/FlipV transitions are snappy, with an effect like rebounding a tennis ball across a net.

Shuffle

The -stitch Shuffle transition setting randomizes the frame sequence.

Before
1 2 3 4 5 6
After

Example ordering:

6 3 1 4 2 5

Naturally, the more unique frames available, the more opportunity for unique random orderings.

This transition tends to artificially accelerate the perceived animation speed.

This transition hides a single jarring misalignment, in the noise of a completely random, spastic animation.

None

The -stitch None transition setting applies no particular transition at all between animation cycles. In art, sometimes less is more.

SUPERCUTS

Animation smoothing takes a long time. We recommend pre-cutting your source assets to the desired subsequence. Every frame removed from the input GIF makes the buttery editing process faster.

Often, animations appear to accelerate when frame are removed. This is not always a bad thing; sometimes a fast animation helps to smooth over more subtle details.

Trim Start / End

The -trimStart <n> / -trimEnd <n> options drop n frames from the start and/or end of the original sequence. Zero indicates no trimming.

For brevity, we will now assume the None transition and elide the successive sequence repetitions.

Before
1 2 3 4 5
After

With -trimStart 1:

2 3 4 5

With -trimEnd 1:

1 2 3 4

With -trimStart 1 and -trimEnd 1:

2 3 4

Trim Edges

For convenience, we provide a similar option -trimEdges <n>. This drops n frames from both sides of the original sequence. Zero indicates no trimming.

Before
1 2 3 4 5
After

With -trimEdges 1:

2 3 4

Window

The -window <n> option truncates the original sequence to a fixed frame count. This is helpful for cutting down long animations. Zero indicates no truncation.

Before
1 2 3 4 5
After

With -window 3:

1 2 3

With -window 3 and -trimStart 1:

2 3 4

Cut Interval

The -cutInterval <n> option removes every nth frame from the original sequence.

This can mitigate some oscillation, such as lighting fluctuations from fans.

Before
1 2 3 4 5 6 7 8
After

With -cutInterval 2:

1 3 5 7

This can also artificially accelerate the perceived speed of the animation. Useful when want to accelerate an animation already scaled down to 2cs per frame.

SHIFT

The -shift <offset> option performs a circular, leftward shift on the original sequence. This is useful for fine tuning how the GIF's very first cycle presents, before entering successive loops.

Zero is the neutral shift. A negative offset indicates rightward shift.

Before
1 2 3
After

With -shift 1:

2 3 1

With -shift -1:

3 1 2

SCALE DELAY

The -scaleDelay <factor> option adjusts animation speed, by multiplying each frame delay by the given factor.

1 = 1.0 is the neutral, and default factor.

Negative values reverse the original sequence.

We can diagram this in terms of the frame delays, expressed in centiseconds. That is, 4cs indicates 4 centisec = 4/100 sec between advancing to the next frame.

Before
4cs 6cs 8cs
After

With -scaleDelay 2:

8cs 12cs 16cs

With -scaleDelay 0.5:

2cs 3cs 4cs

With -scaleDelay -1:

8cs 6cs 4cs

For compatibility with a wide range of GIF viewers, the resulting delay is upheld to a lower bound of 2cs.

LOOP COUNT

The -loopCount <n> option configures the low-level GIF loop counter setting. According to the GIF standard:

  • -1 indicates loop exactly once.
  • 0 indicates infinite, endless looping (default).
  • n indicates n replays after the first play = 1 + n total iterations.
Before
1 2 3
After

With -loopCount 0:

1 2 3 (1 2 3 ...)

SEE ALSO

  • ffmpeg edits and converts videos
  • gifenc.sh converts numerous video formats to animated GIF's
  • ImageMagick converts between multimedia formats, including GIF and WEBP
  • mkvtools edits MKV videos
  • VLC plays numerous multimedia formats
  • webm supports audio in animation loops

🧈

Documentation

Index

Constants

View Source
const Version = "0.0.11"

Version is semver.

Variables

This section is empty.

Functions

func GetDimensions added in v0.0.2

func GetDimensions(paletteds []*image.Paletted) (int, int)

GetDimensions reports the horizontal and vertical bounds of a GIF.

func GetPaletteSize added in v0.0.2

func GetPaletteSize(paletteds []*image.Paletted) int

GetPaletteSize queries the size of a GIF's color space.

func ReverseSlice added in v0.0.2

func ReverseSlice(s interface{})

ReverseSlice performs an in-place swap in reverse order.

func ShuffleSlice added in v0.0.6

func ShuffleSlice(s interface{})

ShuffleSlice randomizes the order of a slice.

Types

type Config added in v0.0.4

type Config struct {
	// TrimEdges removes frames from the start and end of the incoming sequence (Default zero).
	TrimEdges int

	// TrimStart removes frames from the start of the incoming sequence (Default zero).
	TrimStart int

	// TrimEnd removes fromes frames from the end of the incoming sequence (Default zero).
	TrimEnd int

	// CutInterval removes every nth frame from the incoming sequence (Default zero).
	CutInterval int

	// Window truncates frames from the incoming sequence (Default zero).
	//
	// Zero indicates no window truncation.
	Window int

	// Shift moves the start of the sequence leftward (Default zero).
	Shift int

	// Stitch denotes a loop continuity transition (Default Mirror).
	Stitch Stitch

	// ScaleDelay multiplies each frame delay by a factor (Default 1.0).
	//
	// The resulting delay is upheld to a lower bound of 2 centisec.
	//
	// A negative scale delay reverses the incoming sequence.
	ScaleDelay float64

	// LoopCount denotes how many times to play the animation (Default 0).
	//
	// -1 indicates one play.
	// 0 indicates infinite, endless plays.
	// N indicates 1+N iterations.
	LoopCount int
}

Config models a set of animation editing manipulations.

func NewConfig added in v0.0.4

func NewConfig() Config

NewConfig generates a default Config.

func (Config) Edit added in v0.0.4

func (o Config) Edit(destPth string, sourceGif *gif.GIF) error

Edit applies the configured GIF manipulations.

func (Config) Validate added in v0.0.4

func (o Config) Validate() error

Validate checks for basic Config integrity.

type Stitch added in v0.0.2

type Stitch int

Stitch models a loop continuity strategy.

const (
	// None ends the incoming sequence as-is.
	None Stitch = iota

	// Mirror follows the end of the incoming sequence by replaying the sequence backwards.
	Mirror

	// FlipH follows the end of the incoming sequence by replaying the sequence reflected horizontally.
	FlipH

	// FlipV follows the end of the incoming sequence by replaying the sequence reflected vertically.
	FlipV

	// Shuffle randomizes the incoming sequence.
	Shuffle
)

func ParseStitch added in v0.0.2

func ParseStitch(s string) (*Stitch, bool)

ParseStitch generates a Stitch from a string value.

func (Stitch) String added in v0.0.2

func (i Stitch) String() string

func (Stitch) Validate added in v0.0.6

func (o Stitch) Validate() error

Validate rejects out of bound values.

Directories

Path Synopsis
src

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL