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

Intervention Image Bundle Laravel Package

mael/intervention-image-bundle

A Symfony bundle that integrates the Intervention Image library, offering service configuration and convenient helpers for resizing, cropping, and manipulating images within Symfony applications.

View on GitHub
Deep Wiki
Context7

Getting Started

What this actually is. mael/intervention-image-bundle is a ~1-file Symfony bundle whose job is to register Intervention\Image\ImageManager in the container with a configurable driver. That's it. It is not a Laravel package, it has 1 star and 0 dependents. The latest release, 1.0.1, is a deprecation-only patch ("Fix Symfony 5.1 deprecations") — no new features, no API change, no Laravel support. Read that as a signal: the package is being kept installable on Symfony 5.x, not modernised for Symfony 6/7, and it still targets Intervention Image v2. Treat it as a reference implementation of "how to wire Intervention into a DI container," not as a dependency you should composer require in a new Laravel or Symfony app.

The Laravel translation. Laravel doesn't load Symfony bundles. The direct equivalent for a Laravel developer is intervention/image-laravel (v3), which gives you the Image facade. If you're on v2, the old intervention/image package shipped its own service provider. Either way, the day-to-day API is identical to what this bundle exposes — so everything below transfers, just through a different container.

Minimal steps if you're actually in a Symfony app:

  1. composer require mael/intervention-image-bundle — then pin intervention/image explicitly (^2.7) in your composer.json, because the bundle's own constraint is old and will resolve unpredictably.
  2. Enable it in config/bundles.php (older Symfony skeletons don't auto-register):
    Mael\InterventionImageBundle\InterventionImageBundle::class => ['all' => true],
    
  3. Confirm ext-gd or ext-imagick is installed — the bundle does not install a driver for you.
  4. Open DependencyInjection/Configuration.php first. That file is the entire public API surface: it tells you the config key, the allowed driver values, and whether the ImageManager service is aliased for autowiring.
  5. First use case: thumbnail on upload. Inject the manager, resize to a bounded box, write to a thumbnails/ path alongside the original.

The Laravel-side equivalent of "step 4" is just the container binding — one line in a service provider, and you never need the bundle at all:

$this->app->singleton(ImageManager::class, fn () => new ImageManager(['driver' => 'gd']));

Look at the bundle's Resources/config/services.* for the exact service id and any aliases before you start autowiring — that's the five minutes that saves an hour of Cannot autowire service errors.

Implementation Patterns

1. Autowire the manager, never new ImageManager(). The whole value of the bundle (or your own binding) is a single shared, driver-configured manager. Constructor-inject it:

final class ThumbnailService
{
    public function __construct(private ImageManager $images) {}

    public function make(string $src, string $dest, int $width = 300): void
    {
        $this->images->make($src)
            ->orientate()                      // v2: EXIF rotation is NOT automatic
            ->resize($width, null, function ($c) {
                $c->aspectRatio();
                $c->upsize();                  // don't blow up small images
            })
            ->save($dest, 82);
    }
}

(v3 API if you upgrade: $manager->read($src)->orientate()->scale(width: 300)->toJpeg(82)->save($dest) — note make()→read(), resize()→scale(), save()→toJpeg()/save().)

2. Upload → derivatives, but as a queued unit of work. The pattern that survives production: move the original to permanent storage in the request, dispatch a job/command that generates every derivative, persist the derivative paths (or a predictable path convention) on the model. Never loop over 6 sizes synchronously inside a 30-second PHP-FPM request.

// Laravel
Storage::disk('local')->put($path, $file);
GenerateDerivatives::dispatch($path)->onQueue('images');

3. On-the-fly resize behind a validated cache key. This is the most common "day-to-day" use and the easiest to get wrong. Validate w/h against a whitelist and a max bound before touching the filesystem:

$w = (int) $request->query('w', 300);
abort_unless(in_array($w, [64, 128, 300, 768, 1200], true), 404);

$key  = sprintf('%s_%d_%s.webp', sha1($path), $w, filemtime($absolute));
$out  = storage_path("app/cache/{$key}");

Include the source file's mtime (or content hash) in the key, or you will serve stale thumbnails forever after a re-upload.

4. Centralize every filter/size in one class or config array. Scattered ->resize(300) calls across controllers is how you end up with five different avatar sizes. One ImagePresets config, one apply(string $preset, Image $img) method, and preset names in the DB ("avatar", "og", "hero").

5. Twig/Blade helper for presentation. In Symfony, a Twig extension with {{ asset_path|thumb(300) }}; in Laravel, a Blade component or Image::url($path, $preset). Keep URL generation separate from rendering so the endpoint contract is testable in isolation.

6. Backfill as an artisan/console command. Ship images:regenerate {--force} on day one. You will change the OG-image dimensions three months in and need to rebuild everything idempotently.

7. Test dimensions, not pixels. Don't snapshot images. After the call, assert with getimagesize():

Storage::fake('public');
(new ThumbnailService(new ImageManager(['driver' => 'gd'])))
    ->make($fixture, $out = Storage::path('public/t.jpg'), 300);

[$w, $h] = getimagesize($out);
$this->assertSame(300, $w);
$this->assertLessThanOrEqual(300, $h);   // aspect ratio preserved

Keep one or two small real fixtures (a portrait, a CMYK JPEG, a transparent PNG) in tests/fixtures/. Those three catch ~80% of image bugs.

Gotchas and Tips

  • Version drift is the real risk, not the code. The 1.0.1 release only silences Symfony 5.1 deprecations; the service definition and the Intervention Image target are unchanged, so it still assumes v2. Intervention Image v3 (2023) renamed almost every method (make→read, resize→scale/resize, save→toJpeg/toPng/save). If Composer pulls v3, the bundle's service definition may still instantiate fine but your calls will break. Pin intervention/image:^2.7 deliberately, or skip the bundle and bind v3 yourself — a one-line singleton is cheaper than a stale wrapper.
  • Don't read 1.0.1 as "actively maintained." A deprecation-fix patch against Symfony 5.1 means the package is being kept afloat on the 5.x line, not migrated to Symfony 6/7 DI (constructor-argument services, no Definition-only config). If your app is on Symfony 6+, expect autowiring/config errors the bundle will never patch; write the binding yourself.
  • Verify the config key before writing YAML. Guessing mael_intervention_image vs intervention_image is a five-minute bin/console debug:config away. bin/console debug:container ImageManager tells you instantly whether autowiring will work.
  • Driver choice matters more than you think. GD is everywhere but silently degrades: no color-profile handling, poor CMYK JPEG behavior, worse resampling on large downscales. Imagick is better quality but isn't always compiled in and has its own policy.xml limits (PDF/PS, memory, disk). Don't discover this in production — assert the driver at boot.
  • Memory. A 12MP JPEG expands to ~50–70MB as an uncompressed bitmap before you resize it. memory_limit=128M + two concurrent uploads = fatal error with no stack trace. Either raise the limit for the queue worker or pre-check dimensions and reject >N megapixels.
  • Call ->orientate() on every user-uploaded photo. v2 does not respect EXIF orientation. Without it, iPhone photos are sideways and nobody notices until the client does.
  • Path traversal. Never pass a user-supplied string to ->make(). Resolve against a base directory, realpath(), and confirm the result is still inside that base. On-the-fly-resize endpoints are a classic LFI vector.
  • ->save() re-encodes and strips EXIF/IPTC. Good for size and privacy, bad if you wanted to preserve GPS or copyright. Use ->save($path, $quality) and be explicit about format; letting the extension guess produces surprises.
  • WebP/AVIF availability is environment-dependent. imagewebp() needs GD compiled with WebP support; Imagick needs the delegate. Detect once at boot and fall back to JPEG rather than emitting broken responses.
  • Extension points, in order of preference: (1) your own filter/preset class around the manager — portable across v2→v3 and Laravel↔Symfony; (2) a decorating service that wraps ImageManager for logging/metrics; (3) a compiler pass/tagged-filter collection in Symfony, or a container binding in Laravel; (4) only then, forking the bundle. Given the star count and the fact that 1.0.1 is a two-line deprecation fix, forking is a realistic option and the fork is ~50 lines.
  • The honest recommendation for a Laravel shop: don't add a Symfony bundle to get one singleton. Use intervention/image-laravel (maintained, facade, config publish) or the raw intervention/image package with a three-line provider. Adopt the patterns above — queued derivatives, preset registry, validated cache keys, dimension assertions — from this bundle; skip the dependency.
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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource