Image
- Resize an image
- Compress or convert an image
- Display the image
- Generated files
- Errors
- Image customization
- Metadata
The Image library resizes, compresses and converts images with the PHP GD extension. Supported formats are jpg, png, gif, webp and avif (bmp as source only), depending on the GD build.
Resize an image
The constructor takes the output directory, created if not exists:
<?php
$image = new Image(App::getBaseDir('pub/media/cache'));
$result = $image->resize(App::getAssetPath('media/photo.jpg'), 800, 600);
The image fits in the maximum width and height, keeping the ratio. An image is never enlarged. Use 0 for no limit:
<?php
$image->resize($source, 800); // max width 800px, any height
$image->resize($source, 0, 600); // max height 600px, any width
All arguments:
<?php
$image->resize(
'/var/www/magework/pub/assets/Acme/media/photo.jpg', // absolute source path
800, // maximum width (0 for no limit)
600, // maximum height (0 for no limit)
85, // quality between 0 and 100 (null for the default quality)
'My Photo', // new file name (null to keep the source file name)
'webp' // output format (null to keep the source format)
);
The method returns the image data, or null on failure:
array(5) {
["path"]=> string(58) "/var/www/magework/pub/media/cache/my-photo-800x533-85.webp"
["file"]=> string(24) "my-photo-800x533-85.webp"
["width"]=> int(800)
["height"]=> int(533)
["format"]=> string(4) "webp"
}
Use the Image::KEY_PATH, Image::KEY_FILE, Image::KEY_WIDTH, Image::KEY_HEIGHT and Image::KEY_FORMAT constants to read the result.
To compute the final dimensions without generating any file:
<?php
[$width, $height] = $image->getDimensions(1600, 1200, 800, 800); // [800, 600]
Compress or convert an image
compress re-encodes the image without changing its dimensions:
<?php
$image->compress($source, 70); // same format, quality 70
$image->compress($source, 80, null, 'webp'); // convert to webp
$image->compress($source, null, 'banner', 'avif'); // default quality, new name
The quality applies to jpg, webp and avif. png is lossless: the compression level is set with setPngCompression (see Image customization). JPEG images are saved as progressive JPEG.
Display the image
Generate the image in a public directory, then build the URL with the file name. On the page or block class:
<?php
declare(strict_types=1);
class Acme_Block_Gallery extends Core_Block
{
public function getThumbnail(string $file): ?array
{
try {
$image = new Image(App::getBaseDir('pub/media/cache'));
} catch (Exception $exception) {
App::log($exception, Logger::ERR);
return null;
}
$result = $image->resize(App::getAssetPath('media/' . $file), 400, 400, 80, null, 'webp');
if ($result === null) {
App::log($image->getError(), Logger::WARN);
return null;
}
$result['url'] = App::getUrl('media/cache/' . $result[Image::KEY_FILE]);
return $result;
}
}
In the template:
<?php if ($thumbnail = $this->getThumbnail('photo.jpg')): ?>
<img src="<?= App::escapeUrl($thumbnail['url']) ?>"
width="<?= $thumbnail['width'] ?>"
height="<?= $thumbnail['height'] ?>"
alt="Photo" />
<?php endif; ?>
Generated files
The generated file name contains the formatted name, the dimensions and the quality:
{name}-{width}x{height}-{quality}.{extension}
The name is formatted for URLs: lowercase, accents and non-latin chars transliterated, other chars replaced by -.
<?php
$image->formatName('Café Crème Été 2025'); // cafe-creme-ete-2025
$image->formatName('Привет мир'); // privet-mir
When the file already exists and is more recent than the source, it is returned without any processing. The file is generated again when the source image is updated.
Images are written in a temporary file first, then renamed: a partially written image is never served.
Two source images with the same file name in different directories generate the same file. Use the name argument to avoid conflicts.
Errors
The constructor throws an Exception when the GD extension is missing or when the output directory cannot be created or is not writable.
resize and compress return null on failure (missing source, invalid image, unsupported format, write error). The reason is available with getError:
<?php
$result = $image->resize($source, 800, 600);
if ($result === null) {
App::log($image->getError(), Logger::WARN);
}
Check the output formats supported by the current GD build:
<?php
$image->getSupportedFormats(); // ['jpg', 'png', 'gif', 'webp', 'avif']
$image->isSupported('avif'); // true
Image customization
| Method | Description | Default |
|---|---|---|
| setOutputDir | Absolute output directory (created if not exists) | Constructor argument |
| setQuality | Default quality between 0 and 100 (jpg, webp, avif) | 90 |
| setPngCompression | PNG compression level between 0 (none) and 9 (max), lossless | 9 |
| setBackground | Background color in hexadecimal, replaces transparency for jpg | #FFFFFF |
<?php
$image = new Image(App::getBaseDir('pub/media/cache'));
$image->setQuality(80)->setBackground('#000000');
Transparency is kept for png, webp, avif and gif. Only the first frame of an animated GIF is kept.
Metadata
The image is re-encoded, all metadata are removed: EXIF (GPS location, date, camera), IPTC, XMP and comments. Personal data of uploaded photos are not published.
The EXIF orientation is applied before saving (requires the PHP exif extension): portrait photos taken with a smartphone are displayed in the right direction.
The ICC color profile is also removed. Images in a wide color space (Display P3, Adobe RGB) may look slightly different.
- Installation
- Configuration
- Add a new package
- Add a new HTML page
- Templating best practices
- Add a new block
- Assets
- Serve any type of file
- Rewrite a route
- Data assignment
- Objects and class fallback
- Models
- Database
- Forms
- Session messages
- Send emails
- Captcha
- Resize and compress images
- Framework tools
- Console Commands
- Hooks
- Custom shared libraries
- External libraries with composer
- Write content in Markdown
- Static Site Generator