I am building a PHP function to manipulate and generate a series of images with Imagick. The aim is to make responsive images with the <picture>
element.
Basically this is what it does:
- Checks if the original image exist.
- Check if the thumbnails already exist and generates the
<picture>
element.
Otherwise:- Resize images; from the original image it creates 10 thumbnails
- Compress the thumbnails
- Saves the thumbnails
- Generate the
<picture>
element with the thumbnails
The function uses an array as parameters that looks like this:
$params = array(
'thumbWidth' => array( 500, 750, 1000, 1600, 2000),
'thumbHeight' => array( 333, 500, 667, 1067, 1500),
'breakPoints' => array( 500, 750, 1000, 1600),
'quality' => 65
);
The thumbHeight
array can be null so the function only resizes the tumbnails according to the widths. Keeping the aspect ratio.
This is the function:
<?php
public static function picturebuilder($imgUrl, $imageAlt, $params) {
// check if the image exists
if (!file_exists($imgUrl)) {
echo "<script>console.log( 'Cannot find : " . $imgUrl . "' );</script>";
return false;
}
// Get the original image info
$imgInfo = pathinfo($imgUrl);
$imgName = $imgInfo['filename'];
$imgExtension = '.' . $imgInfo['extension'];
$thumbDir = 'image_thumbs/' . $imgInfo['dirname'];
// set HD upscale ratio
$upscale_HD_images = 1.5;
$thumbQuality = $params['quality'];
$breakPoints = $params['breakPoints'];
// Build the Thumb width array
$paramWidths = $params['thumbWidth'];
$thumbWidths = array();
foreach ($paramWidths as $paramWidth) {
array_push($thumbWidths, $paramWidth);
array_push($thumbWidths, floor($paramWidth * $upscale_HD_images));
}
// Build the thumb height array
$paramHeights = $params['thumbHeight'];
$thumbHeights = array();
list($XLwidth, $XLheight) = getimagesize($imgUrl);
if ($paramHeights) {
$crop = true;
// If height is specified get the width and height of image from params
foreach ($paramHeights as $paramHeight) {
array_push($thumbHeights, $paramHeight);
array_push($thumbHeights, floor($paramHeight * $upscale_HD_images));
}
} else {
// If no height is specified get the width and height of image form original file
foreach ($thumbWidths as $thumbWidth) {
$thumbHeight = floor($thumbWidth*$XLheight/$XLwidth);
array_push($thumbHeights, $thumbHeight);
}
}
// Create the thumb paths array
$i = 0;
$thumbPaths = array();
foreach ($thumbWidths as $thumbWidth) {
$thumbHeight = $thumbHeights[$i];
$thumbPath = $thumbDir . '/' . $imgName . '-' . $thumbWidth . 'x' . $thumbHeight . 'q' . $thumbQuality . $imgExtension;
array_push($thumbPaths,$thumbPath);
$i++;
}
// Generate thumbnails if the number 8 doesn't exist
if(!file_exists($thumbPaths[8])){
// Create folders if they don't exixt
if (!file_exists($thumbDir)) {
mkdir($thumbDir, 0777, true);
}
$i = 0;
if($crop) {
foreach ($thumbWidths as $thumbWidth) {
$imagick = new imagick($imgUrl);
$thumbHeight = $thumbHeights[$i];
$imagick->cropThumbnailImage($thumbWidth,$thumbHeight);
$imagick->setImageCompressionQuality($thumbQuality);
$imagick->writeImage($thumbPaths[$i]);
$imagick->clear();
$imagick->destroy();
$i++;
}
} else {
foreach ($thumbWidths as $thumbWidth) {
$imagick = new imagick($imgUrl);
$thumbHeight = $thumbHeights[$i];
$imagick->resizeImage($thumbWidth,$thumbHeight,imagick::FILTER_LANCZOS, 1, true);
$imagick->setImageCompressionQuality($thumbQuality);
$imagick->writeImage($thumbPaths[$i]);
$imagick->clear();
$imagick->destroy();
$i++;
}
}
}
?>
<picture>
<source srcset="<?php echo $thumbPaths[9] . ' 2x,' . $thumbPaths[8]; ?>" media="(min-width: <?php echo $breakPoints[3]; ?>px)"/>
<source srcset="<?php echo $thumbPaths[7] . ' 2x,' . $thumbPaths[6]; ?>" media="(min-width: <?php echo $breakPoints[2]; ?>px) and (max-width: <?php echo $breakPoints[3] - 1; ?>px)"/>
<source srcset="<?php echo $thumbPaths[5] . ' 2x,' . $thumbPaths[4]; ?>" media="(min-width: <?php echo $breakPoints[1]; ?>px) and (max-width: <?php echo $breakPoints[2] - 1; ?>px)"/>
<source srcset="<?php echo $thumbPaths[3] . ' 2x,' . $thumbPaths[2]; ?>" media="(min-width: <?php echo $breakPoints[0]; ?>px) and (max-width: <?php echo $breakPoints[1] - 1; ?>px)"/>
<source srcset="<?php echo $thumbPaths[1] . ' 2x,' . $thumbPaths[0]; ?>" media="(max-width: <?php echo $breakPoints[0] - 1; ?>px)"/>
<img src="<?php echo $thumbPaths[8]; ?>"
srcset="<?php echo $thumbPaths[9] . ' 2x,' . $thumbPaths[8]; ?>"
alt="<?php echo $imageAlt; ?>"
width="<?php echo $thumbWidths[8]; ?>"
height="<?php echo $thumbHeights[8]; ?>"
/>
</picture>
<?php
}
?>
This is what the function call looks like (I am using this in a CMS):
$params = array(
'thumbWidth' => array( 500, 750, 1000, 1600, 2000),
'thumbHeight' => null,
'breakPoints' => array( 500, 750, 1000, 1600),
'quality' => 65
);
$imgUrl = 'images/my-big-image.jpg';
$alt= 'Alternative text for my big image';
echo plgContentPicturebuilder::picturebuilder($imgUrl,$alt,$params);
I have successfully tested this function but I am concerned about the performance.
Depending on the number of images per page, the function can be called over 20 times on first page load and be asked to generate over 200 thumbnails.
This is when it gets very slow and generates 504 Gateway Time Out errors on my server.
picturebuilder()
often get called per script/page load? Can you please edit your post to include sample calls with examples of the calls to illustrate the parameters? \$\endgroup\$$imgUrl
ever the same across calls? \$\endgroup\$