Slideshow: one big image for all
Most of the websites I’ve set up weight is given by the images of the slideshow.
Here’s a simple PHP function that can be usefull to reduce both weight and number of connection for this element.
The concept behind this function is pretty simple:
- take an array of images (jpg/png/gif)
- merge them in a unique big jpeg image
- return the url to this one.
- using css sprite tecnique, set this big image as the background of every of the slideshow with a different background-position.
Here’s the code:
<?php
function merge_images($images, $config=null){
if(empty($images)) return 'No images';
$config = array_merge(
array(
'w' => '700',
'h' => '370',
'q' => '50',
'r' => false
),
$config
);
$combined_image = imagecreatetruecolor($config['w']*count($images), $config['h']);
$cache_name = '';
foreach($images as $image){
$cache_name .= $image['path'].';';
}
$cache_name .= serialize($config);
$cache_name = md5($cache_name);
$cache_dir = get_template_directory().'/cache/';
if (!@is_dir($cache_dir)){
if (!@mkdir($cache_dir)){
die('Couldn\'t create cache dir: '.$cache_dir);
}
}
$cache_url = get_bloginfo('template_url').'/cache/'.$cache_name.'.jpg';
$cache_path = $cache_dir.$cache_name.'.jpg';
if(!file_exists($cache_path) || IMAGE_MERGE_FORCE_REFRESH===true){
foreach($images as $array_index => $image){
$src = $image['url'].'?'.http_build_query($config, '', '&');
$info = getimagesize($src);
switch($info['mime']){
case 'image/jpeg':
$image = imagecreatefromjpeg($src);
break;
case 'image/png':
$image = imagecreatefrompng($src);
break;
case 'image/gif':
$image = imagecreatefromgif($src);
break;
default:
die('unknow mime type');
}
imagecopymerge(
$combined_image,
$image,
$array_index*$config['w'],
0, 0, 0,
$config['w'],
$config['h'],
100
);
imagejpeg(
$combined_image,
$cache_path,
$config['q']
);
}
}
return $cache_url;
}
The second parameter $config is optional array of width, height, quality, and resample; if not passed the default values are 800x600, 50% and ‘do not resample’ built to support all the parameter used by timthumb.
Using it is not a big deal:
- retrieve the image list from your CMS
- pass it to this function as first parameter
- print some div with in-line style setting the image url as background and position (wich is always number_of_the_image * width)
Here’s an example:
<?php
$width = 1900;
$height = 500;
$config = array(
'w'=>$width,
'h'=>$height,
'q'=>'50'
);
define('IMAGE_MERGE_FORCE_REFRESH', false);
$images = wp_get_imagelist_for_slideshow(
'current',
array(
'default'=>'',
'field'=>'caption'
),
$config
);
$merged_image_uri = merge_images($images, $config);
//vd($images);
$tpl = '
<div
class="slideshow_image"
title="%title%"
style="background:url(\''.
$merged_image_uri.
'\') no-repeat scroll -%opos%px -%vpos%px transparent;width:'.
$width.
'px;height:'.
$height.
'px;%style%"
>
<div class="black_grad z_6"></div>
<div class="caption_container z_10">
<div class="container_16 z_10">
<div class="grid_16 text_right color_fff font_30 font_palatino">%caption%</div>
</div>
</div>
</div>
';
foreach ($images as $array_index => $image){
//printf($tpl, $array_index * $width, 0);
echo str_replace(
array(
'%caption%',
'%opos%',
'%vpos%',
'%title%',
'%style%'
),
array(
$image['caption'],
$array_index * $width,
'0',
$image['title'],
($array_index == 0) ? '' : 'display:none'
),
$tpl
);
}
Using this method will give us some benefits:
- if someone uploads an image with wrong dimension, this will be re-sized and it will not brake the layout
- you will never serve a too heavy image, because this function can force it to have fixed jpeg quality; for example 60%
- for an averange of 5 images per slideshow we have only one concurrent http connection
- the total weight of the page is significantly decreased: on ‘aipini.it’ I was able to reduce from ~900K (~200k per image per 4 images) to an unique big image of ~400k
Limitation: it cannot be applied to a dynamically sized slideshow: for example a full screen images or an adaptive design: image size have to be know.