Skip to content

Animation class + APNG support - #48

Merged
matmen merged 3 commits into
masterfrom
animation
Oct 15, 2026
Merged

matmen merged 3 commits into
masterfrom
animation

Conversation

@matmen

@matmen matmen commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator

Adds Animation, a format-independent base class for animated images, and APNG decoding/encoding. GIF becomes a subclass of Animation and is deprecated in its favor.

New

  • Animation: an array of Frames with loopCount, width/height/duration, resize() and slice(). This is the same API GIF had, but not tied to one format.
    • Animation.decode(data) decodes GIFs and APNGs into fully composited frames. Still images become a single frame.
    • encodeGIF(quality) and encodeAPNG(compression) encode it.
  • APNG decoding: all frames with their delays, offsets, dispose and blend operations, plus the loop count.
    • Broken animations (wrong sequence numbers, missing frame data, wrong frame count) fall back to the default image, as browsers do.
    • Image.decode() keeps returning an APNG's default image.
  • APNG encoding: lossless, with full alpha.
    • All frames share the smallest color type that fits them: a palette for up to 256 colors, otherwise greyscale or RGB, with or without alpha.
    • The first frame doubles as the default image for viewers without APNG support.

Deprecated

  • GIF: use Animation instead. new GIF(frames).encode() becomes new Animation(frames).encodeGIF(), and GIF.decode() becomes Animation.decode().
    • GIF keeps working unchanged in 3.x, and decode() still returns GIF instances for GIF files.
    • Removal is planned for 4.0.

Testing

  • Pillow's APNG test suite (54 files):
    • 38 are pixel-identical to Pillow.
    • 4 differ only where Pillow blends semi-transparent pixels differently from the APNG spec's integer "over" formula, which we follow.
    • 11 are broken files Pillow rejects; we fall back to the default image, like browsers.
  • Round trips: animations with offsets and all disposal modes (keep, background, previous), encoded as APNG and decoded again by us and by Pillow, match the expected composited frames exactly.
  • Loop counts: -1/0/n round-trip through APNG and GIF.
  • New tests: tests/animation.js.

Closes #6

matmen and others added 2 commits October 15, 2026 07:50
APNG: decoding (broken animations fall back to the default image, like
browsers do) and encoding with full alpha; the frame compositing follows
the APNG spec's integer "over" operation. Matches Pillow on its APNG test
files, except where Pillow blends semi-transparent pixels differently from
the spec.

Animation is the new base class of GIF: Animation.decode() reads GIF and
APNG (still images become one frame), encodeGIF() and encodeAPNG() write
them. GIF keeps its API, Image.decode() still returns an APNG's default
image.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ljnxm1Qjrocq1izGajLx8J
GIF only adds encode() (encodeGIF), a decode() that accepts nothing but
GIFs (Animation.decode) and its toString. It stays fully working in 3.x,
editors show it as deprecated with the replacement; removal is planned
for 4.0. Frame's documentation now talks about animations instead of GIFs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ljnxm1Qjrocq1izGajLx8J
@matmen matmen added this to the v3.1.0 milestone Oct 15, 2026
@matmen matmen self-assigned this Oct 15, 2026
@matmen matmen added the enhancement New feature or request label Oct 15, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ljnxm1Qjrocq1izGajLx8J
@matmen
matmen merged commit 428a1bb into master Oct 15, 2026
13 checks passed
@matmen
matmen deleted the animation branch October 15, 2026 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WIP: Full PNG support

1 participant