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 class NameParser {
Parsing a full name into components in PHP
string-parsing
arrays
normalization
Intermediate
8 steps
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
php
<?php namespace App\Services;
Building a cached daily leaderboard in Laravel
caching
aggregation
eager-loading
Intermediate
9 steps
php
<?php final class RotatingFileLogger {
How a rotating file logger works in PHP
logging
file-rotation
io
Intermediate
9 steps
php
class TwoFactorController extends Controller { public function show(Request $request): View|RedirectResponse {
Two-factor auth challenge flow in Laravel
authentication
two-factor
middleware
Intermediate
10 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.