php-image-resize does the GD resize, scale and crop work in one class
PHP library to resize, scale and crop images. Cloud solution available at: www.gumlet.com
At a glance
- What is it?
- php-image-resize is a small PHP library that wraps GD to resize, scale and crop images, and its 3.0 release made the public API fully typed while raising the floor to PHP 8.1. The sharp edges are the animated GIF limitation that comes from GD itself, and the strictness of the new constructor.
- Who is it for?
- php-image-resize suits a PHP application that needs predictable resizing and cropping on upload with a small dependency and no service call, and it suits a team already on PHP 8.1 or newer who wants the typed API.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 16 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One class over GD, and the audience that wants that
php-image-resize is described as a PHP library to resize, scale and crop images, and it does exactly that much: it wraps the GD extension so that the common image manipulations a web application needs on upload are a couple of method calls rather than a block of GD boilerplate.
The audience is a PHP developer with an upload form. That is the use case the API is shaped around, and it shows in the method names: scale for a percentage, resizeToWidth, resizeToHeight, resizeToLongSide, resizeToShortSide and resizeToBestFit for the aspect ratio preserving variants, and crop with a choice of crop modes for the case where you want a fixed rectangle. Every one of them ends with a call to save.
The package is on Packagist under the same vendor and package name as the repository, and the licence is MIT. The homepage points at a hosted offering, Gumlet.com, described as a free service that can process images in real time and serve them worldwide through a CDN, and the README suggests it for anyone who would rather not crop, resize and store images on their own server. That is worth weighing as an alternative rather than dismissing: for a site with real image traffic, doing the resizing in the request cycle is a cost, and moving it to a service or to a build step is a different architecture.
What the library itself does is small, local and dependency free apart from PHP's own extensions, which is a good fit for a CMS plugin, a framework bundle or a small application that just needs images to come out the right shape.
Version 3.0 typed the API and tightened the inputs
The 3.0 release is described as a major release focused on modern PHP, static analysis and PHP 8.5 compatibility, with behaviour largely the same and most upgrades being about types and environment. That framing is accurate but incomplete, because several input contracts changed in ways that will break code at runtime.
The typed public API is the headline. Methods and public properties use scalar types and static return types, for example resize(int $width, int $height, bool $allow_enlarge = false): static, and the documentation notes the consequence for anyone who extends the class: custom subclasses that override methods must match those signatures.
The constructor is the change most likely to bite you. ImageResize::__construct(string $filename) requires a non-empty string path. Passing null is a TypeError in PHP 8, where previously you could pass null and receive an ImageResizeException instead. A real path, a data: URL, or ImageResize::createFromString() for binary data are the supported inputs.
createFromString(string $image_data) likewise only accepts a string, and an empty string still throws an ImageResizeException, with the message image_data must not be empty.
The save() signature is now documented with types, and one of them is a trap: exact_size is array|false, and it is the canvas size as a width and height array, not a boolean. Code that passed true to mean the old exact size behaviour now has to pass the dimensions.
Two smaller items round out the changes. The crop and flip constants are public const on ImageResize, with the same names and values as before, and BMP output calls imagebmp() without an invalid third argument, which fixes a deprecation when the quality was null.
The compatible fixes are worth knowing too, because they are behaviour you may have been quietly relying on. MIME detection through finfo now runs only when getimagesize() fails, so there is no finfo_open on every load, and chmod after a save runs only when the destination is a file path string, not for a stream or the null used by output().
The resize methods, and why allow_enlarge defaults to false
The API is easiest to learn by reading the four shapes of resize it offers. Scaling is percentage based:
$image = new ImageResize('image.jpg');
$image->scale(50);
$image->save('image2.jpg');Then there are the single dimension variants that keep the aspect ratio, resizeToHeight, resizeToWidth, resizeToLongSide and resizeToShortSide:
$image = new ImageResize('image.jpg');
$image->resizeToBestFit(500, 300);
$image->save('image2.jpg');And there is the direct resize, which does exactly what it says:
$image = new ImageResize('image.jpg');
$image->resize(800, 600);
$image->save('image2.jpg');The documentation is blunt about that last one: it will cause your image to skew if you do not use the same width and height ratio as the source image. The aspect ratio preserving variants exist precisely so you do not have to compute that yourself, and resizeToBestFit is the one to reach for when you have a bounding box rather than a single dimension.
The detail that catches people is the enlargement guard. All resize functions have an $allow_enlarge option which is set to false by default, and you enable it by passing true to any resize function:
$image = new ImageResize('image.jpg');
$image->resize(500, 300, $allow_enlarge = True);
$image->save('image2.jpg');That default is a sensible safety property. An upload pipeline that resizes to fixed dimensions without a guard will happily upscale a 40 pixel thumbnail to 500 pixels, producing a large, blurry file and doing the work of resizing it. Turning it on per call is the right granularity, because the same application may want one thumbnail enlarged and another not.
Crop scales first, then cuts, and the mode decides where
Cropping in this library is a two step operation, and knowing the order explains most of the surprising results.
$image = new ImageResize('image.jpg');
$image->crop(200, 200);
$image->save('image2.jpg');This will scale the image to be as close as it can to the passed dimensions, and then crop and centre the rest. The worked example in the documentation makes it concrete: an image of 400 by 600 pixels is resized down to 200 by 300, and then 50 pixels are taken off the top and the bottom, leaving 200 by 200.
So the crop is not a cut from the original. The image is scaled first, which means a source that is much larger than the target loses resolution, and a source that is smaller than the target is enlarged before being cut, which is the case where the enlargement guard interacts with cropping.
The second point is the crop mode. A few options are available to choose how you handle the width or height that exceed the target after the resize, and the default is CROPCENTER. The documentation shows that the plain crop call and the explicit form are equivalent:
$image = new ImageResize('image.jpg');
$image->crop(200, 200, true, ImageResize::CROPCENTER);
$image->save('image2.jpg');In the 400 by 600 example resized down to 200 by 300, 100 pixels of height exceed the target, and the crop mode is what decides whether those pixels come off the top and the bottom, off the top only, or from somewhere else. Choosing a mode that suits the content, a top aligned crop for a banner with a headline, for example, is the difference between a usable thumbnail and a cut-off subject.
The crop and flip constants are public const on the ImageResize class in version 3.0, with the same names and values as before, so existing code that references them still works.
What GD cannot do, and what 3.0.1 added
The limitation the documentation names is short and specific: this library uses the GD class, which does not support resizing animated gif files. There is no workaround inside the library, because the constraint is in the extension rather than in the wrapper. If your upload endpoint accepts animated GIFs, this library will not give you what you want, and you need either a different image stack or a design that treats the first frame as a still.
The newest release addresses a different class of problem. Version 3.0.1, published on 2026-10-06, added a check for decompression bombs, which is the attack where a small compressed file expands into an enormous image in memory. Given that the library is designed to sit in an upload path, that check is arguably the most important line in the recent changelog, because an image library that decompresses untrusted input without a limit is a denial of service waiting to happen.
The extension requirements are unchanged across the major version, with ext-gd and ext-fileinfo required. That the library still needs fileinfo after the 3.0 change is worth a note: MIME detection through finfo now runs only when getimagesize() fails, so the extension is still needed for the cases where the size call cannot identify the file, but it is no longer opened on every load.
Version 2.1.3, published on 2026-01-09, removed the PHP 8.5 deprecations, and the 3.0 release included the same class of cleanup by removing the deprecated finfo_close() usage, so the library is being kept current against the PHP release cycle rather than merely against the language features.
Which line to use, and the tooling around the code
The version matrix is explicit, and it is a table rather than a footnote:
| PHP version | Library version | |-------------|-----------------| | 8.1 to 8.5+ | 3.x (`^3.0`) | | 7.2 to 8.0 | `2.0.x` | | 8.0 (legacy)| `2.1.x` (if you were already on it) |
So the 3.x line requires PHP 8.1 or newer, and anyone on an older PHP stays on 2.x, with 2.0.x for 7.2 through 8.0 and 2.1.x only for projects that were already on it. The requirement is PHP 8.1 or newer with the gd and fileinfo extensions.
Installation is a normal Composer dependency:
{
"require": {
"gumlet/php-image-resize": "^3.0"
}
}There is also a non-Composer path, including the ImageResize.php file directly, which matters for legacy code that cannot use a package manager. Because the class is namespaced, you either use the fully qualified name or alias it:
use \Gumlet\ImageResize;
$image = new ImageResize();The internal quality tooling is worth a look, because it tells you what a maintainer of this project has to do before contributing. Formatting is PSR-12 through PHP-CS-Fixer with the composer cs-fix and cs-check commands, static analysis is PHPStan at level 3 on the lib/ directory, and the PHPUnit 10 configuration was migrated. Continuous integration runs the tests on PHP 8.2 to 8.5 with a separate static analysis job, and the test suite was expanded to cover a missing file, exact_size, enlargement, WebP and AVIF saving, gamma and filters.
The licence is MIT, recorded in the Licence.md file at the repository root. The last push was on 2026-10-06 and the repository is not archived, so the 3.x line is actively maintained.
Editorial conclusion
php-image-resize suits a PHP application that needs predictable resizing and cropping on upload with a small dependency and no service call, and it suits a team already on PHP 8.1 or newer who wants the typed API. It is the wrong choice if you need to process animated GIFs, because the library uses GD, which cannot resize them, and a poor match if you are still on PHP 8.0 or older, because the 3.x line requires PHP 8.1 and the 2.x line is the one that carries the old untyped signatures. Before upgrading, read the breaking changes list rather than assuming a patch, and check whether your code passes a null filename or a boolean where the new exact_size parameter now expects a width and height array.
Frequently asked questions
How do I install php-image-resize?
Through Composer, by requiring gumlet/php-image-resize with the constraint ^3.0. The 3.x line needs PHP 8.1 or newer with the gd and fileinfo extensions; older PHP versions stay on the 2.0.x or 2.1.x lines. You can also include the ImageResize.php file directly and use the namespaced Gumlet\ImageResize class.
What changed in version 3.0 of php-image-resize?
The public API is fully typed with scalar types and static return types, the constructor now requires a non-empty string path where null previously produced an ImageResizeException, createFromString only accepts a string, and the exact_size parameter of save() is now an array with the canvas width and height rather than a boolean.
Can php-image-resize handle animated GIFs?
No. The library uses the GD extension, and the documentation states that GD does not support resizing animated gif files. The workaround is a different image stack or treating only the first frame as a still image.
How does crop behave in php-image-resize?
The image is scaled to be as close as possible to the requested dimensions first, and then the excess is cropped and centred, so a 400 by 600 image cropped to 200 by 200 is first resized to 200 by 300. The crop mode constant, CROPCENTER by default, decides which side loses the excess pixels.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gumlet-php-image-resize)