08/23/2025
Convert PNG and JPEG to WebP with a PHP script
For a handful of files, use the image converter on this site — it runs in your browser, nothing is uploaded, and there is no script to deploy. The rest of this page is for a folder full of them on a server.
<?php
if (!extension_loaded('gd')) {
exit("The GD extension is not enabled. Enable it in php.ini.\n");
}
$directory = '.';
$quality = 82; // see the note below -- 100 is not what you want
$converted = $skipped = 0;
foreach (scandir($directory) as $file) {
$extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
if (!in_array($extension, ['jpg', 'jpeg', 'png'], true)) {
continue;
}
$output = pathinfo($file, PATHINFO_FILENAME) . '.webp';
if (file_exists($output)) {
continue;
}
if ($extension === 'png') {
$image = imagecreatefrompng($file);
imagepalettetotruecolor($image);
imagealphablending($image, true);
imagesavealpha($image, true);
} else {
$image = imagecreatefromjpeg($file);
}
if ($image === false) {
continue;
}
imagewebp($image, $output, $quality);
imagedestroy($image);
// KEEP THE SMALLER FILE. WebP does not win on every image.
if (filesize($output) >= filesize($file)) {
unlink($output);
$skipped++;
echo "kept original: {$file}\n";
} else {
$converted++;
$saved = round((1 - filesize($output) / filesize($file)) * 100);
echo "converted {$file} -> {$output} ({$saved}% smaller)\n";
}
}
echo "\n{$converted} converted, {$skipped} left alone.\n";
Run it from the folder you want converted. It writes alongside the originals and deletes nothing you had before.
Quality 100 is the wrong setting, and it is the common mistake
PHP's manual describes the parameter as ranging from "0 (worst quality,
smaller file) to 100 (best quality, biggest file)", and says that passing
-1 uses a default of 80.
That default is the useful hint. At 100 the encoder is told to preserve everything it can, and the result is frequently larger than the JPEG you started with — which defeats the entire purpose. Somewhere in the high 70s to mid 80s is where WebP earns its reputation: visually indistinguishable on photographs, and meaningfully smaller.
82 is a reasonable starting point. Look at the output on a few of your own images before running it over a thousand.
Why the size check matters
WebP is not smaller than everything. It reliably beats JPEG on photographs and PNG on flat graphics, and it loses on:
- an already-optimized PNG or JPEG, where the previous encoder has already done this work;
- very small images, where the container overhead is a large fraction of the file;
- screenshots of large flat areas, which PNG compresses extremely well.
A conversion loop with no size check will happily make those pages
heavier while reporting success. Comparing filesize() and deleting the
loser costs one line and removes the whole question.
Converting is only half of it
A .webp file next to a .jpg changes nothing until something serves it.
You need either markup that offers both:
<picture>
<source srcset="photo.webp" type="image/webp">
<img src="photo.jpg" alt="..." width="1200" height="800">
</picture>
...or a build step that emits WebP and rewrites the references for you, which is what most static site generators do. Converting the folder and leaving the HTML pointing at the old files is a common way to end up with twice the images and none of the benefit.
Questions this keeps raising
What quality should I use for WebP?
Somewhere around 80. PHP's imagewebp uses 80 as its own default when you pass -1, and the manual describes 100 as "best quality, biggest file" rather than as lossless. At 100 the output is often larger than the JPEG it replaced, which is the opposite of the point.
Does this preserve PNG transparency?
Yes, provided you call imagepalettetotruecolor, imagealphablending and imagesavealpha before writing, which the script above does. Skip them and a transparent background comes out black.
Why did WebP make my file bigger?
Because it does not win on everything. Already-optimized images, very small images and screenshots of large flat areas can all come out larger. That is why the script compares the two sizes and keeps the original when WebP loses.
Do I still need the original JPEG or PNG?
Keep it. Browser support for WebP is effectively universal now, but the original is your source: re-encoding from a WebP later compounds the loss. Serve the WebP, archive the original.