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

Php Image Resize Laravel Package

gumlet/php-image-resize

Resize, scale, and crop images in PHP with a simple, typed API. Requires PHP 8.1+ with gd and fileinfo, supports files, data URLs, and binary strings, and handles enlargement limits and multiple crop modes.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and verify the runtime first. The library is a plain Composer package with no Laravel service provider, config file, or facade — so there is nothing to publish and nothing to register.

composer require gumlet/php-image-resize:^3.0
php -m | grep -E 'gd|fileinfo'
php -r 'var_dump(gd_info()["WebP Support"]);'

Version selection is tied to your PHP runtime, not Laravel: 3.x requires PHP 8.1+, 2.0.x covers PHP 7.2–8.0, 2.1.x covers 8.0. Pin accordingly if you maintain a matrix of apps.

Where to look first. Skip the source and read the method list in the README — the entire public surface is roughly resize, resizeToWidth, resizeToHeight, resizeToBestFit, scale, crop, freecrop, save, output, plus the getters and the ImageResize::createFromString() static constructor. If your need isn't in that list (smart crop, EXIF rotation, SVG, HEIC, animated GIF preservation), this package will not do it and you should reach for Intervention Image instead.

First use case — a thumbnail on upload. Everything is chainable and operates on a filename on the local filesystem:

use Gumlet\ImageResize;

$image = new ImageResize($request->file('photo')->getRealPath());
$image->crop(400, 400)
    ->save(storage_path('app/public/avatars/'.$name.'.jpg'), IMAGETYPE_JPEG, 82);

Before spreading that around, decide two things: which disk the source lives on (the constructor wants a local path, not an S3 key) and whether this runs inline or in a queue. For anything user-facing, assume a queue.

Implementation Patterns

Wrap it in a single action class. The library's API is procedural and mutates internal state, so having one StoreResizedImage action (or a small App\Images\Resizer service) keeps call sites honest and gives you one place to swap to Intervention later.

final class ResizeImage
{
    public function __invoke(string $sourcePath, string $targetPath, int $width, int $height, string $disk = 'public'): void
    {
        $filesystem = Storage::disk($disk);

        $image = new ImageResize($filesystem->path($sourcePath));
        $image->crop($width, $height);
        $image->save($filesystem->path($targetPath), IMAGETYPE_JPEG, 82);
    }
}

Storage::path() is only meaningful on local disks (local, public). For S3, see the temp-file pattern below.

Generate each derivative from a fresh instance. Chained calls mutate the working GD resource, so a second resize computes from the first result, not the original. Derive every size from the source:

foreach (['thumb' => [200, 200], 'card' => [600, 400], 'hero' => [1600, 900]] as $name => [$w, $h]) {
    (new ImageResize($source))->crop($w, $h)->save($filesystem->path("derivatives/{$name}.jpg"), IMAGETYPE_JPEG, 82);
}

Push it to a job. Uploads should return fast; resize work belongs behind ShouldQueue, usually dispatched ->afterCommit() so the job never reads a file from a rolled-back transaction.

ProcessImage::dispatch($media->id)->afterCommit();

S3 / remote disks: go through a temp file. The library writes to paths, and it has no in-memory "give me the bytes" method (only save() and an echoing output()). The reliable bridge is:

$tmp = tempnam(sys_get_temp_dir(), 'img');
file_put_contents($tmp, Storage::disk('s3')->get($key));

(new ImageResize($tmp))->resizeToWidth(1600)->save($tmp, IMAGETYPE_JPEG, 82);

Storage::disk('s3')->put($target, fopen($tmp, 'r'));
unlink($tmp);

Reading an upload without touching the disk is clean via createFromString() — useful in feature tests and for images arriving in a request body:

$image = ImageResize::createFromString($request->file('photo')->get());

Validate before you hand it over. The library trusts you; it will happily be fed a 9000×9000 decompression bomb. Guard at the edge:

$request->validate([
    'photo' => ['required', 'file', 'mimes:jpg,jpeg,png,webp', 'max:10240',
                'dimensions:max_width=6000,max_height=6000'],
]);

Testing dimensions is trivial with Storage::fake() and PHP's own getimagesize():

Storage::fake('public');
// ... exercise the controller or job ...
$this->assertSame([200, 200], array_slice(
    getimagesize(Storage::disk('public')->path('avatars/a.jpg')), 0, 2
));

Serving the result. Don't call output() inside a controller — it echoes directly and sets its own headers, which fights Laravel's response lifecycle. Either return a normal file response, or stream:

return response()->file(Storage::disk('public')->path($key));

Gotchas and Tips

  • The quality argument means different things per format. For JPEG and WebP it's 0–100 (higher = better). For PNG it's the zlib compression level 0–9, passed straight to imagepng(). Passing 90 for a PNG produces a needlessly huge file. Branch on type in your wrapper.
  • Never rely on type inference from the target filename. If you omit $image_type, save() falls back to the source type, not the extension you gave it — so a JPEG saved as thumb.png is a PNG extension with JPEG bytes inside. Always pass IMAGETYPE_JPEG / IMAGETYPE_PNG / IMAGETYPE_WEBP explicitly.
  • Instances are stateful. As above: resizeToWidth(100)->resizeToWidth(200) gives you 200px, not a re-derive from the original. This is the single most common bug with this package.
  • No EXIF autorotation. Phone photos with orientation tags come out sideways. Either normalize client-side, or read exif_read_data() and rotate the GD resource yourself before saving. This alone often justifies Intervention.
  • Animated GIFs are flattened to the first frame. If animated content matters, this is the wrong tool.
  • Transparency dies on a JPEG target. Alpha becomes black unless you composite onto a background colour first. Keep PNG/WebP for logos and UI assets.
  • allow_enlarge defaults to false on most resize methods. A 60×60 upload silently stays 60×60 when you asked for 400×400 — which reads like a bug in testing. Pass true when you genuinely want upscaling; do it deliberately, since it just blurs.
  • scale() takes a percentage, not a ratio: scale(50) halves. scale(0.5) gives you a one-pixel image.
  • GD loads the full bitmap into memory. A 4000×3000 JPEG is ~48 MB of uncompressed pixels on top of the compressed source; three concurrent jobs will exhaust a default 128 MB memory_limit. Cap input dimensions (see validation above) and consider ini_set('memory_limit', ...) inside the job.
  • save() will not create directories. Missing parent directories produce a confusing failure — Storage::makeDirectory() first.
  • Catch Gumlet\ImageResizeException. Corrupt files, unsupported types, and unreadable sources all throw it. Letting it bubble turns a bad upload into a 500 with a stack trace.
  • WebP support is a build-time property of GD, not of this package. Feature-detect with gd_info()['WebP Support'] and fall back to JPEG.
  • No SVG, no HEIC, no AVIF. Verify MIME with fileinfo and reject those types explicitly rather than relying on extension checks.
  • output() sets Content-Type and echoes. It's designed for standalone scripts. In Laravel, use response()->file() or a temp file.
  • Extension points are limited to subclassing. If you need behaviour the package doesn't expose, subclass ImageResize and add methods that write through imagejpeg()/imagewebp() on the internal resource — but at that point, evaluate whether Intervention Image's driver abstraction is the better long-term bet.
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.
hotmeteor/eco-env
mvaliolahi/hydrate
wearede/tbcpay-php
parsnick/steak
thibaud-dauce/mattermost-php
multilinguals/apollo-client
antaresbr/collection
kr0lik/phpstan-rules
loco/loco
starfederation/datastar-php
yupmin/modern-phystrix
stephenjude/extended-artisan-commands
lumphp/laravel-macroable
lumphp/laravel-collections
lumphp/laravel-contracts
sermepa/sermepa
arkecosystem/fortify
arkecosystem/ui
owowagency/laravel-resources
gtjamesa/php-standards