alto / image
Lazy image resizing, cropping and encoding with predictable geometry and efficient multi-output rendering.
Fund package maintenance!
Requires
- php: >=8.3
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.94
- league/flysystem: ^3.0
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.5 || ^12.5
Suggests
- ext-gd: Bundled with PHP. Enables the GD driver.
- ext-imagick: TIFF, HEIC, CMYK, ICC conversion, SVG rasterization, and shrink-on-load.
- league/flysystem: Enables FlysystemStore, so derivatives can live on S3 or any other adapter.
- phpunit/phpunit: Required to extend Alto\Image\Test\DriverTestCase when writing a driver.
Provides
None
Conflicts
- ext-imagick: <3.7
Replaces
None
README
Resize, crop and encode images from PHP with lazy execution, predictable output geometry and one decode for multiple derivatives.
Quick start
use Alto\Image\Image; Image::open('photo.jpg') ->cover(800, 450) ->webp(80) ->save('hero.webp');
Drivers are detected automatically and safe input limits are applied before decoding.
Image represents one source and one requested output. ImageSet represents
several outputs from that source and renders them together. Both are immutable
and hold no decoded pixels.
Header inspection, projected dimensions, signatures and derivative paths need no image extension. Rendering uses GD or Imagick.
Features
- Crop by coordinates, anchor, focal point, attention or entropy.
- Preserve ICC profiles or convert pixels to another colour space with Imagick.
- Transform animated images frame by frame with Imagick.
- Produce several sizes and formats from one source decode.
- Read files, encoded bytes and streams. Write files or storage backends.
- Encode common raster formats supported by the selected driver. Controls include quality, effort, byte limits, progressive output and lossless output.
- Extract dominant colours and compare images with perceptual hashes.
See crop, colour profile conversion, encoding, drivers and analysis.
Installation
Install ALTO Image with Composer:
composer require alto/image
ALTO Image requires PHP 8.3 or later. Rendering requires ext-gd or ext-imagick.
Inspect the available formats and local extension configuration with:
vendor/bin/image doctor
Command line
Composer installs vendor/bin/image with three subcommands:
| Command | Purpose |
|---|---|
image doctor |
Inspect installed drivers and formats |
image info |
Read image headers without decoding |
image convert |
Transform and write one image |
Run them through vendor/bin/image. See the
command-line reference for arguments, examples and exit
codes.
Multiple outputs
Create a responsive image set and write it to a local derivative store:
use Alto\Image\Format; use Alto\Image\Image; $paths = Image::open('photo.jpg') ->cover(ratio: 16 / 9) ->widths(640, 960, 1280) ->formats(Format::Webp, Format::Avif) ->store('public/media');
The resulting ImageSet contains six images in the requested order. Missing
outputs are rendered together with one source decode. store() returns their ordered paths.
Combine outputs with different shapes or qualities using and():
use Alto\Image\Image; $source = Image::open('upload.jpg'); $paths = $source->cover(1600, 900)->webp(82) ->and($source->cover(600, 400)->webp(80)) ->and($source->cover(160, 160)->webp(75)) ->store('public/media');
Transformations
Named methods cover common geometry and encoding operations:
use Alto\Image\Image; $image = Image::open('photo.jpg') ->fit(1600, 1600) ->sharpen() ->webp(80); $size = $image->size(); $key = $image->signature(); $bytes = $image->bytes();
Transforms can also be parsed from their stable string representation:
use Alto\Image\Image; use Alto\Image\Transform; $transform = Transform::parse('cover=1280x720,g:top-right|sharpen'); $bytes = Image::open('photo.jpg') ->transformedBy($transform) ->webp() ->bytes();
Storage
Pass a directory directly for local storage, or use a store object when the application needs paths, pruning or another backend:
use Alto\Image\Image; use Alto\Image\Store\LocalStore; $store = new LocalStore('public/media'); $image = Image::open('photo.jpg')->cover(800, 450)->webp(); $path = $store->path($image); $path = $image->store($store); $removed = $store->prune(new DateTimeImmutable('-30 days'));
FlysystemStore supports Flysystem adapters. Custom stores implement
Store\StoreInterface.
Metadata and safety
EXIF, IPTC and XMP are stripped by default, so GPS coordinates in an uploaded
photograph do not reach a browser by accident. The ICC colour profile is kept so
the pixels retain their meaning. Use withMetadata() to remove the profile too,
or keepMetadata() to retain all supported metadata.
use Alto\Image\Image; use Alto\Image\Limits; Image::open($upload) ->within(new Limits(maxPixels: 20_000_000)) ->fit(1600, 1600) ->webp() ->save($destination);
Read the image safety guide before processing untrusted paths or transform strings. Limit user-supplied transformations to the operations the endpoint needs:
use Alto\Image\Transform; $transform = Transform::parse( $value, only: ['cover', 'crop', 'sharpen'], );
Documentation
- Documentation index
- Installation
- Getting started
- Image formats
- Transform images
- Image sets
- Storage
- Image safety
- Image analysis
- Drivers
- Command line
- Image errors
Contributing
Contributions of all kinds are welcome. Visit the project on GitHub to report a bug, suggest a feature, or open a pull request.
Before submitting code, run:
# Runs PHP CS Fixer, PHPStan, and PHPUnit
composer qa
Changes to public behavior should include tests and documentation.
Run composer coverage separately to enforce the 100% line-coverage floor.
Portable operations must remain independent of GD and Imagick: unit tests run
without either extension, driver behavior belongs in tests/Driver/, and
malformed input belongs in tests/Fuzz/.
Support
ALTO Image is open source and independently maintained by Simon André. If it is useful to your work, you can support its continued development through GitHub Sponsors.
Sharing the package or starring it on GitHub also helps.
License
ALTO Image is released by ALTO PHP under the MIT License.