Friday, July 22, 2016

PHP script to automatically create Image + CSS Sprite (Simple & Automatic)

I needed to create CSS Sprite and Image quickly. I did not want to gather images into image editors like Photoshop. Align them properly and create CSS classes to be able to use them easily. All those steps can take at least 30 minutes just to put together a sprite of 10 images.

So I found some codes online and combine them together, and added my own logics to make this script below.

This PHP function will take several parameters and it will generate a .png image file (containing all the image sprites combined) and CSS file you can include into your webpage.

Original credits goes to http://innvo.com/1315192249-css-sprites-with-php  for writting the base function.

Here is my customized function:

<?PHP
//CLASS to CREATE SPRITE
class images_to_sprite {

function images_to_sprite($sprite_name, $source_img_path, $img_output_path, $css_output_path, $img_output_url) {
$this->sprite_name = $sprite_name;
$this->source_img_path = $source_img_path.$this->sprite_name; // path to import images into sprite
$this->filetypes = array('jpg'=>true,'png'=>true,'jpeg'=>true,'gif'=>true); // Acceptable file extensions to consider
$this->img_output_path = $img_output_path; // Output filename default: mysprite.png
$this->css_output_path = $css_output_path; // Output filename default: mysprite.css
$this->img_output_url = $img_output_url;
$this->files = array();
}

function create_sprite() {

$files = array();
$max_width = 0;
$max_height = 0;
$canvas_height = 0;

// Read through the directory for suitable images
$files_arr = array();
if($handle = opendir($this->source_img_path)) {
while (false !== ($file = readdir($handle))) {
$split = explode('.',$file);

// Ignore non-matching file extensions
if($file[0] == '.' || !isset($this->filetypes[$split[count($split)-1]]))
continue;

$files_arr[] = $file;
}
closedir($handle);
}
// echo __LINE__.':files_arr: '.print_r($files_arr, true)."\n"; exit;

if(!empty($files_arr)){
sort($files_arr);

foreach($files_arr as $file){
$split = explode('.',$file);

// Ignore non-matching file extensions
if($file[0] == '.' || !isset($this->filetypes[$split[count($split)-1]]))
continue;

// Get image size and ensure it has the correct dimensions
$img_size_arr = getimagesize($this->source_img_path.'/'.$file);
// echo __LINE__.':img_size_arr: '.print_r($img_size_arr, true)."\n";

if(!empty($img_size_arr[0]) && $max_width < $img_size_arr[0]) $max_width = $img_size_arr[0];
if(!empty($img_size_arr[1])){
$canvas_height += $img_size_arr[1];
if($max_height < $img_size_arr[1]) $max_height = $img_size_arr[1];
}

// Image will be added to sprite, add to array
$file_arr = array(
'name' => $file,
'width' => $img_size_arr[0],
'height' => $img_size_arr[1]
);
$this->files[$file] = $file_arr;

$tmp = explode(".", $file);
$tmp = end($tmp);
$tmp = basename($file,$tmp);
$tmp = substr($tmp, 0, -1);
$filenames[] = $tmp;
}
}

$im = imagecreatetruecolor($max_width, $canvas_height);

// Add alpha channel to image (transparency)
imagesavealpha($im, true);
$alpha = imagecolorallocatealpha($im, 0, 0, 0, 127);
imagefill($im, 0, 0, $alpha);

// Append images to sprite and generate CSS lines
$i = 0;
$current_top = 0;
$current_pos = 0;

$fp = fopen($this->css_output_path.$this->sprite_name.'.css', 'w');

// wrapper class
fwrite($fp,'.sprite_'.$this->sprite_name.' { width:'.$max_width.'px; height:'.$max_height.'px; background-image:url(\''.$this->img_output_url.$this->sprite_name.'.png\'); }'."\n");


//Individual sprite image
foreach($this->files as $key => $file) {
/* top, right, bottom, left  - Image position */
fwrite($fp, '.sprite_' . $filenames[$i]. ' { width:'.$file['width'].'px; height:'.($file['height']-1).'px; background-position: 0 '.$current_pos.'px; }'."\n");

$im2 = imagecreatefrompng($this->source_img_path.'/'.$file['name']);
imagecopy($im, $im2, 0, $current_top, 0, 0, $file['width'], $file['height']);
$current_top += $file['height'];
$current_pos -= $file['height'];
$i++;
}

fclose($fp);
imagepng($im, $this->img_output_path.$this->sprite_name.'.png'); // Save image to file
imagedestroy($im);

chmod($this->css_output_path.$this->sprite_name.'.css', 0777);
chmod($this->img_output_path.$this->sprite_name.'.png', 0777);
}
}


----------------------------------------------------------------

(please see instructions of how to use above)


<?php
require_once '/data_local/app/cron_php/sprite/Images_to_sprite.class.php';

$class = new images_to_sprite(
'ribbon',
'/app/www/static/shared/img/sprite/raw/', // Source Images
'/app/www/static/shared/img/sprite/',        // Image output directory and file
'/app/www/static/shared/css/sprite/',       // CSS output directory and file
'/static/shared/img/sprite/'                      // base URL for css
);
$class->create_sprite();


--------------------------------------------------------------

This script will produce a PNG image sprite like this  (ribbon.png) :



And the CSS file output will look like this   (ribbon.css) :


.sprite_ribbon { width:20px; height:58px; background-image:url('/static/shared/img/sprite/ribbon.png'); }

.sprite_ribbon_10 { width:20px; height:46px; background-position: 0 0px; }

.sprite_ribbon_20 { width:20px; height:46px; background-position: 0 -47px; }

.sprite_ribbon_21 { width:20px; height:57px; background-position: 0 -94px; }

.sprite_ribbon_70 { width:20px; height:46px; background-position: 0 -152px; }


To use the Sprite Image you do this in your HTML (to show BOGO ribbon):
(c.gif is a 1x1 clear pixel - required by img tag)

<img class="sprite_ribbon sprite_ribbon_20" src="c.gif" />