kaliop/image-bundle
Kaliop ImageBundle is a Symfony bundle for managing and serving images, integrating with LiipImagineBundle to generate filtered variations and thumbnails. It provides image storage, upload handling, Twig helpers, and a simple API for cached image URLs and variations.
This is a Symfony bundle (kaliop/image-bundle), not a native Laravel package, so treat it as "Symfony component glue inside Laravel" rather than a php artisan vendor:publish-style install. Budget for a thin integration layer.
composer require kaliop/image-bundle — it pulls in the usual Symfony pieces (http-foundation, dependency-injection, config) plus an image driver (GD/Imagick) or an HTTP client for the Fastly provider.README.md and its DependencyInjection/Configuration.php first — that file is the real documentation for what variations, providers, and cache resolvers are configurable.config/images.php into it. Keep this in one ImageServiceProvider so the rest of the app never touches Symfony internals.ImageVariation (e.g. thumb_small = thumbnail 200x200, fit), resolve it for a stored file, and emit the resulting URL in a Blade view. That single loop — config → variation → URL → response — is 90% of day-to-day usage.Where to look when something is off: the variation registry (which named variations exist), the provider (who actually transforms bytes), and the cache resolver (who decides the output path/key). Almost every bug is one of those three being misconfigured.
Config-driven variations, not code-driven. Define all variations in config (fit, thumbnail, scale, plus quality and format filters) and reference them by name in controllers. This keeps filter tuning out of application code and makes cache keys stable.
Dedicated image controller/route. A single route like GET /img/{variation}/{path} that resolves the variation, streams the image (or 302s to the CDN), and sets long-lived Cache-Control/ETag headers. Blade then only needs a URL helper:
<img src="{{ image_url('thumb_small', $post->cover) }}" alt="">
Fastly/CDN offload with real dimensions. When using the Fastly provider, you generally don't transform locally at all — you emit a signed/parametrised CDN URL. As of v2.0.3, ImageVariation objects from the Fastly provider now carry populated width/height, so you can render intrinsic dimensions directly in markup (avoiding layout shift) without an extra getimagesize() round-trip:
$variation = $this->variations->get('hero');
<img src="..." width="{{ $variation->getWidth() }}" height="{{ $variation->getHeight() }}">
Pre-warm / async generation. For non-CDN providers, dispatch a queued job that requests each needed variation after upload so the first visitor isn't the one paying the transform cost. The URL helper should be idempotent so warm-up and render agree.
Testing. Bind a fake/stub provider in tests that returns a deterministic URL or a 1x1 image; assert on the URL contract (variation name, path, cache-busting segment) rather than on bytes.
hero_v2).width/height are not always known. v2.0.3 populates them, but only where the dimensions are derivable (fixed-size variations, or source dimensions already known). For relative "fit"-style variations the values can be null until the source is inspected — always null-check before emitting attributes rather than assuming the getters are non-null.crop then thumbnail ≠ thumbnail then crop. Put the intent-revealing filter first and document it next to the variation.How can I help you explore Laravel packages today?