Image Processing
By the end of this lesson you'll resize photos without squashing them, build square thumbnails, stamp watermarks, convert to WebP, and fix sideways phone uploads — the exact pipeline behind every avatar and gallery on the web.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
Part of the free Php course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
1️⃣ GD vs Imagick — Know Your Tools
PHP can't process images on its own — it leans on a library (a bundle of ready-made functions). There are two. GD is bundled with almost every PHP install and covers JPEG, PNG, GIF and WebP — it's what you'll use 90% of the time. Imagick is a separate extension that wraps the powerful ImageMagick program: it supports 200+ formats and gives sharper results, but it has to be installed on the server first. Before you write a single resize, check what you actually have.
If WebP Support says no or GD is missing, you'll get a fatal error later — so this is the first thing to confirm on any new server.
2️⃣ Loading & Creating Images
Every GD operation works on an image resource — the picture decompressed into memory. You get one two ways: load an existing file with imagecreatefromjpeg() (or ...png , ...webp ), or create a blank canvas with imagecreatetruecolor() . Call getimagesize() first — it reads just the file header, so you learn the real type and dimensions cheaply, before loading megabytes into RAM.
Notice the imagedestroy() calls at the end. GD resources are not cleaned up promptly by PHP, so on a busy server you must free each one the moment you're done or memory piles up.
3️⃣ Resizing & Thumbnails (the main event)
Serving a 4000×3000 original to a phone wastes bandwidth and slows your page. The fix is to resize . The one rule that matters: preserve the aspect ratio . Work out a single scale ratio and apply it to both width and height — apply two different ratios and the image squashes. To fit inside a box use min() ; capping at 1.0 stops you upscaling a small image (which only blurs it).
Always reach for imagecopyresampled() , not imagecopyresized() — the first smooths pixels for a clean result; the second just throws pixels away and looks jagged.
A thumbnail is usually a fixed square, which means you can't just fit — you'd get empty bars. Instead cover the box (use max() so it fills) and crop the overflow from the centre. That's "crop-to-fill", the look every avatar uses.
4️⃣ Watermarks
A watermark stamps text or a logo onto an image — useful for branding gallery photos. The key is the alpha (transparency) channel: imagecolorallocatealpha() takes a 4th value from 0 (solid) to 127 (invisible), so a value like 75 gives a soft, see-through mark that doesn't hide the photo.
5️⃣ Format Conversion & Compression
Converting to WebP is the single biggest page-speed win you can make: it's typically 25-35% smaller than JPEG and 80%+ smaller than PNG at the same visual quality. The pattern is "load in any format, save in another". The save functions also take a quality value (0-100) — your compression dial. 80 is the sweet spot : near-perfect to the eye, a fraction of the bytes.
6️⃣ EXIF Orientation & Metadata
EXIF is hidden data phones bake into a photo. Two parts matter. The Orientation flag records how the phone was held instead of rotating the pixels — so an untouched upload often appears sideways until you imagerotate() to compensate. The rest can include GPS coordinates and the camera model — a privacy leak if you publish the file as-is. The good news: re-saving through GD writes a clean file with no EXIF, so a load-process-save cycle fixes the rotation and strips the metadata in one go.
Now you try. The script below has the aspect-ratio maths blanked out. Fill in each ___ using the 👉 hint, then run it and check it against the Output panel.
One more. This one converts a JPEG to WebP — fill in the two missing GD function names.
7️⃣ The Intervention Image Library
Writing raw GD by hand is verbose and easy to get wrong. Intervention Image is the most popular PHP image library: install it with composer require intervention/image and you get one fluent, chainable API that sits on top of either GD or Imagick. It reads EXIF orientation automatically, and methods like cover() , scaleDown() and toWebp() replace a dozen lines of GD each.
For real projects, reach for Intervention first — you only drop down to raw GD when you need something the library doesn't expose.
📋 Quick Reference — Image Processing
No code is filled in this time — just a brief and an outline. Write the function yourself, run it on a real photo with php avatar.php , then check the result against the expected output in the comments. This is the crop-to-fill plus WebP combo you'll use for every profile picture.
Practice quiz
Which image library is bundled with almost every PHP install and used for most common work?
- Imagick
- Intervention
- GD
- ImageMagick CLI
Answer: GD. GD ships with nearly every PHP install and covers JPEG, PNG, GIF and WebP; Imagick is a separate extension.
Why call getimagesize() before loading an image into memory?
- It reads only the file header, so you learn the real type and dimensions cheaply before loading megabytes into RAM
- It resizes the image automatically
- It converts the image to WebP
- It strips EXIF data
Answer: It reads only the file header, so you learn the real type and dimensions cheaply before loading megabytes into RAM. getimagesize() reads just the header, returning width, height, and a type code without decompressing the whole file.
To resize an image without squashing it, how do you compute the new dimensions?
- Set the new width and height independently to your targets
- Use two different ratios for width and height
- Always crop to a square first
- Compute one scale ratio and multiply BOTH width and height by it
Answer: Compute one scale ratio and multiply BOTH width and height by it. Preserve the aspect ratio by applying a single ratio to both sides; two different ratios distort the image.
For a 1600x900 source fitting inside a 400x400 box (no upscaling), what is the resulting size?
- 400x400
- 400x225
- 711x400
- 400x300
Answer: 400x225. ratio = min(400/1600, 400/900, 1.0) = 0.25, so 1600x900 becomes 400x225.
When building a square thumbnail (crop-to-fill), which function picks the scale ratio?
- max(), so the image COVERS the box, then crop the overflow from the centre
- min(), to fit inside the box
- round(), to the nearest pixel
- abs(), to avoid negatives
Answer: max(), so the image COVERS the box, then crop the overflow from the centre. Crop-to-fill uses max() so the box is fully covered, then the centred overflow is cropped off.
Why use imagecopyresampled() instead of imagecopyresized()?
- It is the only one that works with WebP
- It is faster but lower quality
- It does smooth bilinear resampling for a clean result, while imagecopyresized just drops pixels and looks jagged
- It automatically strips EXIF
Answer: It does smooth bilinear resampling for a clean result, while imagecopyresized just drops pixels and looks jagged. imagecopyresampled smooths pixels; imagecopyresized throws pixels away and produces a jagged result.
In imagecolorallocatealpha(), what does an alpha value of 127 mean?
- Fully solid
- Fully transparent (invisible)
- Pure white
- 50% grey
Answer: Fully transparent (invisible). Alpha runs 0 (solid) to 127 (fully transparent); around 75 gives a soft, see-through watermark.
Which GD function saves an image as WebP, and what is the third argument?
- imagejpeg($img, $dest, 80) — the third argument is the width
- imagepng($img, $dest, 80) — the third argument is compression level
- imagecreatefromwebp($dest) — there is no quality argument
- imagewebp($img, $dest, 80) — the third argument is the quality (0–100)
Answer: imagewebp($img, $dest, 80) — the third argument is the quality (0–100). imagewebp() saves WebP; the third argument is the 0–100 quality dial, with 80 a great default.
Re-saving a phone photo through GD has what useful side effect on EXIF data?
- It doubles the GPS precision
- It writes a clean file with NO EXIF, automatically stripping GPS/metadata
- It rotates the image 180 degrees every time
- It embeds the camera model into the filename
Answer: It writes a clean file with NO EXIF, automatically stripping GPS/metadata. A load-process-save cycle through GD writes a clean file with no EXIF, removing the privacy-leaking metadata.
Why must you call imagedestroy() on GD resources when you're done?
- To save the file to disk
- It is required before every imagejpeg() call
- GD resources are not garbage-collected promptly, so freeing each one prevents memory piling up on a busy server
- It converts the image to grayscale
Answer: GD resources are not garbage-collected promptly, so freeing each one prevents memory piling up on a busy server. GD images aren't cleaned up promptly by PHP; free each resource the moment you're done to avoid memory exhaustion.