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

File Image Laravel Package

rekalogika/file-image

Adds image support to rekalogika/file: image files are identified, validated, and can be resized or converted into derivatives such as thumbnails. Works with the file abstraction, so dimensions, MIME type, and metadata are available wherever files are used in your PHP app.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install dependencies. This package is a filter for rekalogika/file, so it is not usable on its own. Pull both:

    composer require rekalogika/file rekalogika/file-image
    
  2. Confirm a backend image driver is available. The filter needs either ext-gd or ext-imagick at runtime. Check with php -m | grep -E 'gd|imagick'. In production containers this is the most common reason the filter silently fails.

  3. Read the rekalogika/file docs first. file-image only adds one piece — an image-resize FilterInterface implementation. Everything about storing, retrieving, deriving, and caching files lives in the base package. If you don't already understand FileInterface, FileReference, and how derived files are persisted, start there.

  4. First use case — on-demand thumbnail generation. The canonical scenario: you have an uploaded image stored as a FileInterface, and you want a variant. Construct the filter with a maximum width or height, and use rekalogika/file's derive mechanism to materialize a separate file:

    use Rekalogika\File\File\File;
    use Rekalogika\FileImage\Filter\ImageResizeFilter;
    
    $thumbnail = $original->derive(
        new ImageResizeFilter(maxWidth: 200, maxHeight: 200, square: true)
    );
    
    $thumbnail->getContent();          // binary payload
    $thumbnail->getFileReference();    // to persist alongside the original
    

    Because derive() caches derived files under the parent, calling this repeatedly with the same filter parameters costs nothing after the first call.

  5. Where to look first when something is wrong: inspect the derived file's storage path (you should see a subdirectory generated from the filter's name/parameters) and check storage/logs for GD/Imagick warnings. If derive() returns the original file unchanged, the filter was not picked up (see Gotchas).

Implementation Patterns

Variant-as-filter, computed lazily

Treat resized images as derived artifacts, never as primary entities. The pattern is:

// Do not persist the filter itself; persist the derived FileReference.
$avatar = $user->getPhoto()->derive(
    new ImageResizeFilter(maxWidth: 128, maxHeight: 128, square: true)
);
$user->setAvatarFile($avatar->getFileReference());

This keeps your domain model free of image concerns, and means the expensive decode/resize happens once per source image.

Aspect-ratio variants vs. square crops

The square flag is the whole API surface for cropping. Use it deliberately:

  • square: false — preserve aspect ratio, bound by maxWidth and maxHeight. Good for detail views, hero images, any layout that lets width drift.
  • square: true — center-crop to exactly min(maxWidth, maxHeight) square. Good for avatars, grid thumbnails, and any fixed container. Be aware the crop is center, so faces near an edge can be clipped; if that matters, store the original and use a client-side or manual crop before deriving.

A common pattern is a small ImageVariants service that returns an array of filters keyed by name (thumb, card, hero), each wrapped in ImageResizeFilter, so controllers and templates reference 'thumb' rather than repeating constructor arguments.

Chaining with storage / delivery

Derive at upload time in the upload handler (or a queued job for large originals), then serve the derived file through your normal rekalogika/file delivery mechanism:

// Controller
$image = $fileRepository->find($id);
return $this->fileResponse($image->derive($this->variants->get('card')));

Queued derivation is worth it once originals exceed a few megapixels; GD is synchronous and memory-hungry.

Integration with a File entity / attribute

When using rekalogika/file's entity integration, call derive() on the hydrated File object rather than the raw stream. Derived files then inherit the parent's metadata and reference storage location (the FileReferenceInterface), which is what makes cache invalidation work.

Testing

Because the filter is deterministic against a fixture, snapshot the dimensions of the output rather than the byte stream (GD/Imagick builds differ). A small helper that runs the filter through getimagesize() on the returned content is usually enough:

[$w, $h] = getimagesize($filtered->getContent());
$this->assertLessThanOrEqual(200, max($w, $h));

Gotchas and Tips

  • Read-only package. The repo is marked [READ-ONLY] and has minimal stars/attention. Pin the version in composer.json and be prepared to vendor or fork it. For anything beyond straightforward resize, keep your filter wiring in one class so swapping to a different resizer (Intervention, symfony/messenger + Imagick) is a one-file change.

  • square: true ignores one bound. Users routinely pass maxWidth: 300, maxHeight: 200, square: true and expect 300×200. They get a square. Decide the square size as min() yourself and document it.

  • GD/Imagick memory limits. GD decodes the entire image into memory. A 6000×4000 JPEG can blow memory_limit on resize. Either downscale originals on upload or raise the limit for the queue worker. Imagick fares better but has its own MAX_MEMORY/MAX_MAP policies.

  • EXIF orientation is a real hazard. If the driver doesn't apply Orientation from EXIF, portrait photos from phones derive as sideways thumbnails while the original displays correctly (browser + <img> applies orientation). Verify with a fixture, and if it fails, pre-rotate on upload.

  • Format is inherited from the source. Resizing a PNG yields a PNG, including alpha. If your target is WebP/AVIF, this filter won't do it for you — chain a converter filter or handle it at delivery.

  • Derived-file caching is keyed on filter identity. If the filter's getName() or parameter hashing is not stable, you'll get duplicate derived files (or, worse, a stale one returned for a new parameter set). When extending, always include all constructor arguments in the identity; don't add a "quality" setting without also hashing it.

  • No-op results are ambiguous. If you receive a file identical to the input, first check the filter was actually invoked (was a no-op because the image already fit within the bounds?) versus never being applied. getimagesize() on both sides distinguishes these quickly.

  • Extension points are in rekalogika/file, not here. For watermarking, format conversion, or quality tuning, write your own FilterInterface in your app and compose it with ImageResizeFilter by deriving twice, e.g. derive($resize)->derive($watermark). Don't try to subclass this filter for extra behavior.

  • Debugging tips: dump get_class($filter) and the constructor args before derive(); enable rekalogika/file's logging to see which storage paths are written; and clear derived files if you change filter semantics or upgrade either package, since existing cached variants are not invalidated automatically.

  • Synchronize package versions. file-image tracks rekalogika/file's filter interfaces. A minor bump on one can break the other. composer update these two together, never independently.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource