Skip to content

Instantly share code, notes, and snippets.

@samilkorkmaz
Last active March 2, 2024 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samilkorkmaz/ae3044d346893f89d594c1d25b45f3f6 to your computer and use it in GitHub Desktop.
Save samilkorkmaz/ae3044d346893f89d594c1d25b45f3f6 to your computer and use it in GitHub Desktop.
Convert images to webp files under 250kB
<?php
//Convert PNG and JPEG images to WebP
function convertToWebp($source, $destination, $quality = 80) {
$startTime = microtime(true);
$info = getimagesize($source);
if ($info['mime'] == 'image/jpeg' || $info['mime'] == 'image/jpg' || $info['mime'] == 'image/jfif') {
echo "Original image is jpeg<br>";
// Load the JPEG file
$image = imagecreatefromjpeg($source);
// Read the EXIF data to get the orientation
$exif = exif_read_data($source);
if (!empty($exif['Orientation'])) {
switch ($exif['Orientation']) {
case 3:
echo "Rotate 180 degrees<br>";
$image = imagerotate($image, 180, 0);
break;
case 6:
echo "Rotate -90 degrees<br>";
$image = imagerotate($image, -90, 0);
break;
case 8:
echo "Rotate 90 degrees<br>";
$image = imagerotate($image, 90, 0);
break;
}
}
} elseif ($info['mime'] == 'image/png') {
echo "Original image is png<br>";
$image = imagecreatefrompng($source);
if ($image) {
// Preserve transparency
imagepalettetotruecolor($image);
imagealphablending($image, true);
imagesavealpha($image, true);
} else {
echo "Corrupt file, not converting to webp.<br>";
return false;
}
} else if ($info['mime'] == 'image/webp') {
echo "Original image is webp<br>";
$image = imagecreatefromwebp($source);
} else {
echo "Unsupported file type " . $info['mime'] . "<br>";
return false;
}
// Convert to WebP
$result = imagewebp($image, $destination, $quality);
// Free up memory
imagedestroy($image);
$endTime = microtime(true);
$duration = $endTime - $startTime;
echo __FUNCTION__ . " took " . round($duration, 3) . " seconds to execute.<br>";
return $result;
}
function resizeWebP($sourceFile, $destinationFile, $targetWidth, $targetHeight) {
$startTime = microtime(true);
// Create an image resource from the source WebP file
$sourceImage = imagecreatefromwebp($sourceFile);
if (!$sourceImage) {
die('Failed to load source image');
}
// Get the dimensions of the source image
list($sourceWidth, $sourceHeight) = getimagesize($sourceFile);
// Create a new image resource with the target dimensions
$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
// Preserve transparency in case the source image has it
imagecolortransparent($targetImage, imagecolorallocatealpha($targetImage, 0, 0, 0, 127));
imagealphablending($targetImage, false);
imagesavealpha($targetImage, true);
// Copy and resize the source image to the target image
imagecopyresampled(
$targetImage, // Destination image
$sourceImage, // Source image
0, 0, // Destination x, y
0, 0, // Source x, y
$targetWidth, // Destination width
$targetHeight, // Destination height
$sourceWidth, // Source width
$sourceHeight // Source height
);
// Save the resized image to the destination file
imagewebp($targetImage, $destinationFile);
// Free up memory
imagedestroy($sourceImage);
imagedestroy($targetImage);
$endTime = microtime(true);
$duration = $endTime - $startTime;
echo __FUNCTION__ . " took " . round($duration, 3) . " seconds to execute.<br>";
return filesize($destinationFile);
}
$scriptStartTime = microtime(true);
//$directoryPath = 'c:/xampp/htdocs/image/product/';
$directoryPath = 'c:/xampp_8_2_12/htdocs/image/product/';
$filesAndFolders = glob($directoryPath . '*'); // some files don't have extension
// Check if any images were found.
$nFiles = 0;
if ($filesAndFolders !== false) {
echo "Found " . count($filesAndFolders) . " files and folders<br>";
$maxSizeReduction = 1;
$maxReducedFile = "";
foreach ($filesAndFolders as $i => $source) {
if (is_file($source)) { // exclude directories
$nFiles++;
echo "<br>" . $nFiles . ". " . $source . "<br>";
$filePath = pathinfo($source, PATHINFO_DIRNAME);
$filenameWithoutExt = pathinfo($source, PATHINFO_FILENAME);
$destinationWebP = $filePath . '/webp/' . $filenameWithoutExt . '.webp';
if (convertToWebp($source, $destinationWebP, 80)) {
$fileSizeOriginal = filesize($source);
$fileSizeWebP = filesize($destinationWebP);
$sizeReductionFromWebPConversion = $fileSizeOriginal / $fileSizeWebP;
echo "fileSizeOriginal: " . $fileSizeOriginal . " bytes, fileSizeWebP: " . $fileSizeWebP . " bytes (" . round($sizeReductionFromWebPConversion, 1) . "x reduction)<br>";
$maxSizeBytes = 250 * 1024; //250kB
$sizeReductionFromWidthHeightChange = 1;
if ($fileSizeWebP > $maxSizeBytes) {
$imageInfo = getimagesize($destinationWebP);
if ($imageInfo !== false) {
$width = $imageInfo[0];
$height = $imageInfo[1];
$reductionFactor = sqrt($maxSizeBytes / $fileSizeWebP); // Width and height reduction to get desired file size is an approximation because the actual size after reduction also depends on the image content, compression efficiency, and specific format characteristics
$reducedWidth = (int)round($reductionFactor * $width);
$reducedHeight = (int)round($reductionFactor * $height);
echo "width: " . $width . ", height: " . $height . ", reductionFactor: " . round($reductionFactor, 3) . ", reducedWidth: " . $reducedWidth .
", reducedHeight: " . $reducedHeight . "<br>";
clearstatcache(true, $destinationWebP); // To get up-to-date file size of $destinationWebP after resizeWebP
$reducedSize = resizeWebP($destinationWebP, $destinationWebP, $reducedWidth, $reducedHeight);
if ($reducedSize) {
$sizeReductionFromWidthHeightChange = $fileSizeWebP / $reducedSize;
echo 'Image resized successfully to ' . $reducedSize . ' bytes (' . round($sizeReductionFromWidthHeightChange, 1) . 'x resize reduction, ' .
round($fileSizeOriginal / $reducedSize, 1) . 'x total reduction)<br>';
} else {
echo 'Failed to resize image.<br>';
}
} else {
echo "Failed to get image dimensions.<br>";
}
}
$totalSizeReduction = $sizeReductionFromWebPConversion * $sizeReductionFromWidthHeightChange;
if ($totalSizeReduction > $maxSizeReduction) {
$maxSizeReduction = $totalSizeReduction;
$maxReducedFile = $source;
}
}
}
}
echo "<br><b>maxSizeReduction: " . round($maxSizeReduction, 1) . ", maxReducedFile: " . $maxReducedFile . "</b><br>";
} else {
echo "No files found in " . $directoryPath . "<br>";
}
$scriptEndTime = microtime(true);
$scriptDuration = $scriptEndTime - $scriptStartTime;
echo "For " . $nFiles . " files, it took " . round($scriptDuration / 60, 3) . " minutes.<br>";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment