php
62 lines · 10 steps
Batch image resizing with PHP GD
A service that scales every image in a directory to fit within bounds while preserving type and transparency.
Explained by
highlit
1<?php
2
3namespace App\Services;
4
5use RuntimeException;
6
7final class ImageResizer
8{
9 public function __construct(
10 private readonly int $maxWidth = 1920,
11 private readonly int $maxHeight = 1080,
12 private readonly int $jpegQuality = 82,
13 ) {}
14
15 public function resizeDirectory(string $sourceDir, string $targetDir): array
16 {
17 if (!is_dir($targetDir) && !mkdir($targetDir, 0755, true) && !is_dir($targetDir)) {
18 throw new RuntimeException("Cannot create target directory: {$targetDir}");
19 }
20
21 $processed = [];
22 foreach (glob(rtrim($sourceDir, '/') . '/*.{jpg,jpeg,png}', GLOB_BRACE) as $path) {
23 $target = $targetDir . '/' . basename($path);
24 $this->resize($path, $target);
25 $processed[] = $target;
26 }
27
28 return $processed;
29 }
30
31 public function resize(string $source, string $target): void
32 {
33 [$width, $height, $type] = getimagesize($source) ?: throw new RuntimeException("Not an image: {$source}");
34
35 $src = match ($type) {
36 IMAGETYPE_JPEG => imagecreatefromjpeg($source),
37 IMAGETYPE_PNG => imagecreatefrompng($source),
38 default => throw new RuntimeException("Unsupported type: {$source}"),
39 };
40
41 $scale = min($this->maxWidth / $width, $this->maxHeight / $height, 1.0);
42 $newWidth = max(1, (int) round($width * $scale));
43 $newHeight = max(1, (int) round($height * $scale));
44
45 $dst = imagecreatetruecolor($newWidth, $newHeight);
46
47 if ($type === IMAGETYPE_PNG) {
48 imagealphablending($dst, false);
49 imagesavealpha($dst, true);
50 }
51
52 imagecopyresampled($dst, $src, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
53
54 match ($type) {
55 IMAGETYPE_JPEG => imagejpeg($dst, $target, $this->jpegQuality),
56 IMAGETYPE_PNG => imagepng($dst, $target, 6),
57 };
58
59 imagedestroy($src);
60 imagedestroy($dst);
61 }
62}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Constructor property promotion with readonly gives you immutable, self-documenting configuration in one signature.
- 2Scaling by the minimum ratio capped at 1.0 fits an image inside a box without ever enlarging it.
- 3GD handles are raw resources, so freeing them with imagedestroy is essential to avoid leaking memory.
Related explainers
php
<?php namespace App\Http\Controllers;
Streaming a filtered CSV export in Laravel
streaming
csv-export
query-builder
Intermediate
9 steps
php
<?php namespace App\Http\Middleware;
Idempotent requests with Laravel middleware
idempotency
middleware
caching
Advanced
8 steps
php
<?php namespace App\Cache;
A content-hashed fragment cache in PHP
caching
content-hashing
atomic-writes
Intermediate
10 steps
python
from pathlib import Path from PIL import Image, ImageOps
Batch image resizing with Pillow
image-processing
batch-jobs
error-handling
Intermediate
8 steps
php
<?php namespace App\View\Composers;
How a Laravel view composer feeds the navigation
view-composer
caching
dependency-injection
Intermediate
5 steps
php
public function transaction(callable $callback, int $maxAttempts = 3): mixed { $attempt = 0;
Retrying database deadlocks in PHP
retry
transactions
deadlock
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/batch-image-resizing-with-php-gd-explained-php-6aef/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.