Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Gif Laravel Package

intervention/gif

A native PHP encoder and decoder for the GIF image format with no image processing extension dependencies. Easily decode, build, and encode animated GIFs, with optional GD-based frame splitting. Requires PHP 8.3+.

View on GitHub
Deep Wiki
Context7

Getting Started

Requirements and install. This package needs PHP 8.3+ and nothing else unless you touch Splitter. Install it like any Laravel dependency:

composer require intervention/gif

There is no service provider, config file, or facade to publish — it is a plain library. That is a feature: you call static entry points (Decoder::decode(), Builder::canvas()) and get value objects back. Everything else is your own wiring.

Where to look first. The two classes that matter in day-to-day work are:

  • Intervention\Gif\Decoder — turns a file path or raw binary string into a GifDataStream value object.
  • Intervention\Gif\Builder — a fluent canvas you add frames to and encode() back to binary.

If you plan to extract individual frames as GDImage resources (e.g. to resize or watermark each frame), Intervention\Gif\Splitter is the third entry point — and the only one that requires the GD extension.

Your first use case. The most common Laravel job for this package is normalizing user-uploaded animated GIFs: enforcing a loop count, capping frame delays, and re-encoding before storing. That flow is two calls:

use Intervention\Gif\Decoder;

$gif = Decoder::decode($request->file('avatar')->getRealPath());
// inspect / mutate metadata
$binary = $gif->encode();
Storage::disk('s3')->put($path, $binary);

Start there before exploring the Builder. Reading and re-encoding existing files covers most production needs and is the safest way to learn the object graph.

Implementation Patterns

Decode → tweak → encode. Decoder::decode() accepts either a filesystem path or the raw bytes of a GIF, so it slots cleanly into upload handlers where you only have a UploadedFile. Once you hold a GifDataStream, you read frame metadata (delays, loop count, dimensions) and encode back to a binary string. Wrap this in an Action class or a dedicated GifService so controllers stay thin and the logic is testable.

Builder for synthesized animations. When you are creating a GIF that did not exist before — progress bars, milestone badges, countdown cards — use the Builder:

use Intervention\Gif\Builder;

$gif = Builder::canvas(width: 480, height: 270);

$gif->addFrame(storage_path('frames/01.gif'), 0.25, 0, 0);
$gif->addFrame(storage_path('frames/02.gif'), 0.25, 0, 0);
$gif->addFrame(storage_path('frames/03.gif'));

$gif->setLoops(0); // infinite
Storage::put('milestones/celebrate.gif', $gif->encode());

Each frame is a path to an existing single-frame GIF; the builder stitches them into an animation with per-frame delay (seconds) and offsets. This is the pattern to reach for when frames are generated by your own renderer (GD, Blade-to-image, or an AI image service) and you just need compliant GIF assembly.

Preprocessing frames with Intervention Image. If you need to resize, crop, or watermark each frame before assembly, decode the source with Splitter, transform the resulting GDImage objects using the intervention/image API, then hand them back to the Builder (as temporary single-frame GIFs on disk). This is the canonical "unified media pipeline" pattern: one service handles GIF, PNG, and JPEG frames through the same transformation chain.

Queued batch processing. Any GIF work you would not want in a web request — extracting frames from a large upload, generating a personalized animation, or converting a set of frames to a compliant output — belongs in a ShouldQueue job. Since the library only takes strings and returns strings, it is trivially serializable. Pass the storage path or a temporary URL in the job payload and write the result back to Storage. Do not pass the binary string itself across the queue; store it and pass a reference.

Validation layer. Because the decoder throws a DecoderException on corrupted or truncated files (added in 4.2.2), you can write a custom Laravel validation rule that attempts a decode and rejects malformed uploads before they enter your pipeline. This is cheaper than storing a broken file and failing later during frame extraction.

Rule::make('gif', function ($attribute, $file, $fail) {
    try {
        Decoder::decode($file->getRealPath());
    } catch (\Throwable) {
        $fail('The :attribute is not a valid GIF.');
    }
});

Metadata enforcement. Accessibility and branding requirements (loop caps, maximum frame delays) are naturally expressed as post-decode checks: decode, walk the frames, throw a validation exception if a rule is violated, then re-encode with setLoops() if needed. Keep this as a distinct step so it can be toggled per feature.

Gotchas and Tips

  • PHP 8.3 is mandatory. If your Laravel app is on 8.1 or 8.2, you cannot install the current major version. Verify your composer.json platform constraint before adopting; downgrading to an older 4.x branch is possible but check the specific 4.x API surface, which has diverged.

  • GD is only needed for Splitter. Decoding and encoding work in a bare PHP container. If you only ever re-encode uploaded GIFs you do not need GD at all — which is precisely the reason to prefer this package over ImageMagick-based solutions on serverless or minimal Docker images. If you do call Splitter::split(), ensure gd is enabled in your container; it is not pulled in by this package.

  • Delays are in seconds, not hundredths. The GIF spec stores frame delay in centiseconds, but addFrame() takes seconds (.25 for a quarter-second). Do not pass 25 expecting 250ms — you will get a 25-second frame. If you round-trip a delay you read from a decoded GIF, check whether the accessor returns seconds or centiseconds before feeding it back into the builder.

  • setLoops(0) means infinite, not "no looping." The release notes for 4.2.3/4.2.4 specifically fixed confusion between loop count and repetition count. Double-check your interpretation when you are enforcing a maximum loop count for accessibility — the value you set may not match the "number of times the animation plays" you have in your head.

  • Corrupted files throw, they do not return null. Since 4.2.2, decoding a truncated or malformed GIF raises an exception. Wrap every decode in a try/catch and map to a domain-specific exception or validation failure rather than letting it bubble up as a 500. This applies equally to uploads and to files already in your storage bucket (which may have been corrupted in transit).

  • Builder::canvas() dimensions are the animation canvas, not a frame size. Frames added to the builder are positioned by $left/$top offset and can be smaller than the canvas. If your frames are a different size than the canvas, you get transparent padding, not scaling. Pre-scale frames with Intervention Image before adding them.

  • Memory scales with frame count and canvas size. Encoded GIFs are held in memory as a GifDataStream, and each frame is a full data block. A 5MB GIF with 300 frames can easily push a queue worker past PHP's memory_limit. Set an explicit memory_limit on the worker and consider a per-job timeout that accounts for encode time.

  • Extension point: block-level encoders/decoders. Encoder/decoder resolution is convention-based via CanDecode / CanEncode traits, and every block model extends AbstractEntity (which is Stringable). This means you can add a custom block type by following the src/Blocks/<Name>.php, src/Decoders/<Name>Decoder.php, src/Encoders/<Name>Encoder.php triad without forking. In practice this is rarely needed, but it is the escape hatch if a GIF variant is not handled correctly.

  • This is not a compression or conversion tool. The library encodes and decodes GIF bytes; it does not resize, compress, or convert video. Do not point it at "reduce GIF file size" tickets — reach for intervention/image (for resizing/re-encoding frames) or FFmpeg (for video-to-GIF) and use this package for the final assembly and metadata pass.

  • Pin your version and read the 5.0.0 changelog carefully. The 5.0.0 release notes are sparse ("Full Changelog" only), and 5.0.1 mentions "stricter comparisons" — both suggest API tightening. If you are upgrading from 4.x, run your GIF fixtures through the full decode→encode cycle in CI before deploying; the round-trip is the test that catches breaking changes in this package.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings